mirror of
https://github.com/servo/servo.git
synced 2025-08-05 21:50:18 +01:00
Upgrade WebRender to e491e1ae637b2eed1e7195855d88357e5eb3ddf9 (#30323)
* Upgrade vendored version of WebRender * Patch WebRender: upgrade version of gleam * Restore hit testing implementation * Fix WebRender warnings * Adapt Servo to new WebRender * Update results * Add a workaround for #30313 This slightly expands text boundaries in order to take into account the fact that layout isn't measuring glyph boundaries.
This commit is contained in:
parent
c079acb3c3
commit
a9d37cb85a
563 changed files with 48524 additions and 51657 deletions
11
third_party/webrender/example-compositor/compositor-wayland/Cargo.toml
vendored
Normal file
11
third_party/webrender/example-compositor/compositor-wayland/Cargo.toml
vendored
Normal file
|
@ -0,0 +1,11 @@
|
|||
[package]
|
||||
name = "compositor-wayland"
|
||||
version = "0.1.0"
|
||||
authors = ["Glenn Watson <gw@intuitionlibrary.com>",
|
||||
"Robert Mader <robert.mader@posteo.de>"]
|
||||
edition = "2018"
|
||||
license = "MPL-2.0"
|
||||
|
||||
[build-dependencies]
|
||||
cc = "1.0"
|
||||
pkg-config = "^0.3.17"
|
63
third_party/webrender/example-compositor/compositor-wayland/build.rs
vendored
Normal file
63
third_party/webrender/example-compositor/compositor-wayland/build.rs
vendored
Normal file
|
@ -0,0 +1,63 @@
|
|||
/* 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/. */
|
||||
|
||||
use std::process::Command;
|
||||
use std::env;
|
||||
use std::fs;
|
||||
|
||||
extern crate pkg_config;
|
||||
|
||||
fn main() {
|
||||
let out_dir = env::var("OUT_DIR").unwrap();
|
||||
|
||||
fs::create_dir_all(&format!("{}/include", out_dir)).unwrap();
|
||||
Command::new("wayland-scanner")
|
||||
.args(&["client-header", "/usr/share/wayland-protocols/stable/viewporter/viewporter.xml"])
|
||||
.arg(&format!("{}/include/viewporter-client-protocol.h", out_dir))
|
||||
.status().unwrap();
|
||||
|
||||
Command::new("wayland-scanner")
|
||||
.args(&["public-code", "/usr/share/wayland-protocols/stable/viewporter/viewporter.xml"])
|
||||
.arg(&format!("{}/viewporter-protocol.c", out_dir))
|
||||
.status().unwrap();
|
||||
|
||||
Command::new("wayland-scanner")
|
||||
.args(&["client-header", "/usr/share/wayland-protocols/stable/xdg-shell/xdg-shell.xml"])
|
||||
.arg(&format!("{}/include/xdg-shell-client-protocol.h", out_dir))
|
||||
.status().unwrap();
|
||||
|
||||
Command::new("wayland-scanner")
|
||||
.args(&["public-code", "/usr/share/wayland-protocols/stable/xdg-shell/xdg-shell.xml"])
|
||||
.arg(&format!("{}/xdg-shell-protocol.c", out_dir))
|
||||
.status().unwrap();
|
||||
|
||||
cc::Build::new()
|
||||
.include(&format!("{}/include", out_dir))
|
||||
.file("src/lib.cpp")
|
||||
.file(&format!("{}/viewporter-protocol.c", out_dir))
|
||||
.file(&format!("{}/xdg-shell-protocol.c", out_dir))
|
||||
.compile("wayland");
|
||||
|
||||
println!("cargo:rustc-link-lib=dylib=stdc++");
|
||||
|
||||
pkg_config::Config::new()
|
||||
.atleast_version("1")
|
||||
.probe("egl")
|
||||
.unwrap();
|
||||
pkg_config::Config::new()
|
||||
.atleast_version("1")
|
||||
.probe("gl")
|
||||
.unwrap();
|
||||
pkg_config::Config::new()
|
||||
.atleast_version("1")
|
||||
.probe("wayland-client")
|
||||
.unwrap();
|
||||
pkg_config::Config::new()
|
||||
.atleast_version("1")
|
||||
.probe("wayland-egl")
|
||||
.unwrap();
|
||||
|
||||
println!("cargo:rerun-if-changed=src/lib.rs");
|
||||
println!("cargo:rerun-if-changed=src/lib.cpp");
|
||||
}
|
772
third_party/webrender/example-compositor/compositor-wayland/src/lib.cpp
vendored
Normal file
772
third_party/webrender/example-compositor/compositor-wayland/src/lib.cpp
vendored
Normal file
|
@ -0,0 +1,772 @@
|
|||
/* 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/. */
|
||||
|
||||
#define UNICODE
|
||||
|
||||
#include <algorithm>
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <map>
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <sys/mman.h>
|
||||
#include <unistd.h>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
#include <wayland-client.h>
|
||||
#include <wayland-egl.h>
|
||||
|
||||
#include <EGL/egl.h>
|
||||
#include <EGL/eglext.h>
|
||||
#include <GL/gl.h>
|
||||
#include <GLES2/gl2.h>
|
||||
|
||||
#include "viewporter-client-protocol.h"
|
||||
#include "xdg-shell-client-protocol.h"
|
||||
|
||||
#define UNUSED(x) (void)(x)
|
||||
|
||||
#define MIN(x, y) (((x) < (y)) ? (x) : (y))
|
||||
#define MAX(x, y) (((x) > (y)) ? (x) : (y))
|
||||
|
||||
#define NUM_QUERIES 2
|
||||
|
||||
#define VIRTUAL_OFFSET 512 * 1024
|
||||
|
||||
enum SyncMode {
|
||||
None_ = 0,
|
||||
Swap = 1,
|
||||
Commit = 2,
|
||||
Flush = 3,
|
||||
Query = 4,
|
||||
};
|
||||
|
||||
// The OS compositor representation of a picture cache tile.
|
||||
struct Tile {
|
||||
uint64_t surface_id;
|
||||
int x;
|
||||
int y;
|
||||
|
||||
struct wl_surface* surface;
|
||||
struct wl_subsurface* subsurface;
|
||||
struct wp_viewport* viewport;
|
||||
struct wl_egl_window* egl_window;
|
||||
EGLSurface egl_surface;
|
||||
bool is_visible;
|
||||
|
||||
std::vector<EGLint> damage_rects;
|
||||
};
|
||||
|
||||
struct TileKey {
|
||||
int x;
|
||||
int y;
|
||||
|
||||
TileKey(int ax, int ay) : x(ax), y(ay) {}
|
||||
};
|
||||
|
||||
bool operator==(const TileKey& k0, const TileKey& k1) {
|
||||
return k0.x == k1.x && k0.y == k1.y;
|
||||
}
|
||||
|
||||
struct TileKeyHasher {
|
||||
size_t operator()(const TileKey& key) const { return key.x ^ key.y; }
|
||||
};
|
||||
|
||||
struct Surface {
|
||||
uint64_t id;
|
||||
int tile_width;
|
||||
int tile_height;
|
||||
bool is_opaque;
|
||||
std::unordered_map<TileKey, Tile*, TileKeyHasher> tiles;
|
||||
};
|
||||
|
||||
struct WLDisplay {
|
||||
struct wl_display* display;
|
||||
struct wl_registry* registry;
|
||||
struct wl_compositor* compositor;
|
||||
struct wl_subcompositor* subcompositor;
|
||||
struct xdg_wm_base* wm_base;
|
||||
struct wl_seat* seat;
|
||||
struct wl_pointer* pointer;
|
||||
struct wl_touch* touch;
|
||||
struct wl_keyboard* keyboard;
|
||||
struct wl_shm* shm;
|
||||
struct wl_cursor_theme* cursor_theme;
|
||||
struct wl_cursor* default_cursor;
|
||||
struct wl_surface* cursor_surface;
|
||||
struct wp_viewporter* viewporter;
|
||||
|
||||
PFNEGLSWAPBUFFERSWITHDAMAGEEXTPROC swap_buffers_with_damage;
|
||||
};
|
||||
|
||||
struct WLGeometry {
|
||||
int width, height;
|
||||
};
|
||||
|
||||
struct WLWindow {
|
||||
WLGeometry geometry;
|
||||
bool enable_compositor;
|
||||
SyncMode sync_mode;
|
||||
bool closed;
|
||||
|
||||
WLDisplay* display;
|
||||
struct wl_surface* surface;
|
||||
struct xdg_surface* xdg_surface;
|
||||
struct xdg_toplevel* xdg_toplevel;
|
||||
struct wl_callback* callback;
|
||||
struct wp_viewport* viewport;
|
||||
bool wait_for_configure;
|
||||
|
||||
struct wl_egl_window* egl_window;
|
||||
EGLSurface egl_surface;
|
||||
|
||||
EGLDeviceEXT eglDevice;
|
||||
EGLDisplay eglDisplay;
|
||||
EGLContext eglContext;
|
||||
EGLConfig config;
|
||||
|
||||
// Maintain list of layer state between frames to avoid visual tree rebuild.
|
||||
std::vector<uint64_t> currentLayers;
|
||||
std::vector<uint64_t> prevLayers;
|
||||
|
||||
// Maps WR surface IDs to each OS surface
|
||||
std::unordered_map<uint64_t, Surface> surfaces;
|
||||
std::vector<Tile*> destroyedTiles;
|
||||
std::vector<Tile*> hiddenTiles;
|
||||
};
|
||||
|
||||
extern "C" {
|
||||
|
||||
static void init_wl_registry(WLWindow* window);
|
||||
static void init_xdg_window(WLWindow* window);
|
||||
|
||||
WLWindow* com_wl_create_window(int width, int height, bool enable_compositor,
|
||||
SyncMode sync_mode) {
|
||||
WLDisplay* display = new WLDisplay;
|
||||
WLWindow* window = new WLWindow;
|
||||
|
||||
window->display = display;
|
||||
window->geometry.width = width;
|
||||
window->geometry.height = height;
|
||||
window->enable_compositor = enable_compositor;
|
||||
window->sync_mode = sync_mode;
|
||||
window->closed = false;
|
||||
|
||||
display->display = wl_display_connect(NULL);
|
||||
assert(display->display);
|
||||
|
||||
init_wl_registry(window);
|
||||
if (enable_compositor && !display->viewporter) {
|
||||
fprintf(stderr, "Native compositor mode requires wp_viewporter support\n");
|
||||
window->closed = true;
|
||||
}
|
||||
|
||||
window->eglDisplay =
|
||||
eglGetPlatformDisplay(EGL_PLATFORM_WAYLAND_KHR, display->display, NULL);
|
||||
|
||||
eglInitialize(window->eglDisplay, nullptr, nullptr);
|
||||
eglBindAPI(EGL_OPENGL_API);
|
||||
|
||||
EGLint num_configs = 0;
|
||||
EGLint cfg_attribs[] = {EGL_SURFACE_TYPE,
|
||||
EGL_WINDOW_BIT,
|
||||
EGL_RENDERABLE_TYPE,
|
||||
EGL_OPENGL_BIT,
|
||||
EGL_RED_SIZE,
|
||||
8,
|
||||
EGL_GREEN_SIZE,
|
||||
8,
|
||||
EGL_BLUE_SIZE,
|
||||
8,
|
||||
EGL_ALPHA_SIZE,
|
||||
8,
|
||||
EGL_DEPTH_SIZE,
|
||||
24,
|
||||
EGL_NONE};
|
||||
EGLConfig configs[32];
|
||||
|
||||
eglChooseConfig(window->eglDisplay, cfg_attribs, configs,
|
||||
sizeof(configs) / sizeof(EGLConfig), &num_configs);
|
||||
assert(num_configs > 0);
|
||||
window->config = configs[0];
|
||||
|
||||
EGLint ctx_attribs[] = {EGL_CONTEXT_OPENGL_PROFILE_MASK,
|
||||
EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT,
|
||||
EGL_CONTEXT_MAJOR_VERSION,
|
||||
3,
|
||||
EGL_CONTEXT_MINOR_VERSION,
|
||||
2,
|
||||
EGL_NONE};
|
||||
|
||||
// Create an EGL context that can be used for drawing
|
||||
window->eglContext = eglCreateContext(window->eglDisplay, window->config,
|
||||
EGL_NO_CONTEXT, ctx_attribs);
|
||||
|
||||
window->surface = wl_compositor_create_surface(display->compositor);
|
||||
init_xdg_window(window);
|
||||
|
||||
struct wl_region* region =
|
||||
wl_compositor_create_region(window->display->compositor);
|
||||
wl_region_add(region, 0, 0, INT32_MAX, INT32_MAX);
|
||||
wl_surface_set_opaque_region(window->surface, region);
|
||||
wl_region_destroy(region);
|
||||
|
||||
if (enable_compositor) {
|
||||
xdg_toplevel_set_title(window->xdg_toplevel,
|
||||
"example-compositor (Wayland)");
|
||||
} else {
|
||||
xdg_toplevel_set_title(window->xdg_toplevel, "example-compositor (Simple)");
|
||||
}
|
||||
|
||||
window->wait_for_configure = true;
|
||||
wl_surface_commit(window->surface);
|
||||
|
||||
EGLBoolean ok = eglMakeCurrent(window->eglDisplay, EGL_NO_SURFACE,
|
||||
EGL_NO_SURFACE, window->eglContext);
|
||||
assert(ok);
|
||||
|
||||
display->swap_buffers_with_damage =
|
||||
(PFNEGLSWAPBUFFERSWITHDAMAGEEXTPROC)eglGetProcAddress(
|
||||
"eglSwapBuffersWithDamageKHR");
|
||||
|
||||
return window;
|
||||
}
|
||||
|
||||
bool com_wl_tick(WLWindow* window) {
|
||||
if (window->wait_for_configure) {
|
||||
int ret = 0;
|
||||
while (window->wait_for_configure && !window->closed && ret != -1) {
|
||||
wl_display_dispatch(window->display->display);
|
||||
}
|
||||
} else {
|
||||
wl_display_dispatch_pending(window->display->display);
|
||||
}
|
||||
|
||||
return !window->closed;
|
||||
}
|
||||
|
||||
static void unmap_hidden_tiles(WLWindow* window) {
|
||||
for (Tile* tile : window->hiddenTiles) {
|
||||
if (tile->subsurface) {
|
||||
wl_subsurface_destroy(tile->subsurface);
|
||||
tile->subsurface = nullptr;
|
||||
}
|
||||
}
|
||||
window->hiddenTiles.clear();
|
||||
}
|
||||
|
||||
static void clean_up_tiles(WLWindow* window) {
|
||||
for (Tile* tile : window->destroyedTiles) {
|
||||
eglDestroySurface(window->eglDisplay, tile->egl_surface);
|
||||
wl_egl_window_destroy(tile->egl_window);
|
||||
wp_viewport_destroy(tile->viewport);
|
||||
wl_surface_destroy(tile->surface);
|
||||
delete tile;
|
||||
}
|
||||
window->destroyedTiles.clear();
|
||||
}
|
||||
|
||||
static void handle_callback(void* data, struct wl_callback* callback,
|
||||
uint32_t time) {
|
||||
WLWindow* window = (WLWindow*)data;
|
||||
UNUSED(time);
|
||||
|
||||
assert(window->callback == callback);
|
||||
|
||||
wl_callback_destroy(callback);
|
||||
window->callback = nullptr;
|
||||
}
|
||||
|
||||
static const struct wl_callback_listener frame_listener = {handle_callback};
|
||||
|
||||
void com_wl_swap_buffers(WLWindow* window) {
|
||||
if (window->enable_compositor) {
|
||||
for (auto surface_it = window->surfaces.begin();
|
||||
surface_it != window->surfaces.end(); ++surface_it) {
|
||||
Surface* surface = &surface_it->second;
|
||||
|
||||
for (auto tile_it = surface->tiles.begin();
|
||||
tile_it != surface->tiles.end(); ++tile_it) {
|
||||
Tile* tile = tile_it->second;
|
||||
|
||||
if (!tile->damage_rects.empty() && tile->is_visible) {
|
||||
eglMakeCurrent(window->eglDisplay, tile->egl_surface,
|
||||
tile->egl_surface, window->eglContext);
|
||||
eglSwapInterval(window->eglDisplay, 0);
|
||||
|
||||
/* if (window->display->swap_buffers_with_damage) {
|
||||
window->display->swap_buffers_with_damage(
|
||||
window->eglDisplay, tile->egl_surface,
|
||||
tile->damage_rects.data(), tile->damage_rects.size() / 4);
|
||||
} else */
|
||||
eglSwapBuffers(window->eglDisplay, tile->egl_surface);
|
||||
tile->damage_rects.clear();
|
||||
|
||||
eglMakeCurrent(window->eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE,
|
||||
window->eglContext);
|
||||
} else {
|
||||
wl_surface_commit(tile->surface);
|
||||
}
|
||||
}
|
||||
}
|
||||
wl_surface_commit(window->surface);
|
||||
unmap_hidden_tiles(window);
|
||||
clean_up_tiles(window);
|
||||
|
||||
int ret = 0;
|
||||
switch (window->sync_mode) {
|
||||
case SyncMode::None_:
|
||||
wl_display_roundtrip(window->display->display);
|
||||
break;
|
||||
case SyncMode::Swap:
|
||||
window->callback = wl_surface_frame(window->surface);
|
||||
wl_callback_add_listener(window->callback, &frame_listener, window);
|
||||
wl_surface_commit(window->surface);
|
||||
|
||||
while (window->callback && !window->closed && ret != -1) {
|
||||
ret = wl_display_dispatch(window->display->display);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
assert(false);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
// If not using native mode, then do a normal EGL swap buffers.
|
||||
switch (window->sync_mode) {
|
||||
case SyncMode::None_:
|
||||
eglSwapInterval(window->eglDisplay, 0);
|
||||
break;
|
||||
case SyncMode::Swap:
|
||||
eglSwapInterval(window->eglDisplay, 1);
|
||||
break;
|
||||
default:
|
||||
assert(false);
|
||||
break;
|
||||
}
|
||||
eglSwapBuffers(window->eglDisplay, window->egl_surface);
|
||||
}
|
||||
}
|
||||
|
||||
// Create a new native surface
|
||||
void com_wl_create_surface(WLWindow* window, uint64_t surface_id,
|
||||
int tile_width, int tile_height, bool is_opaque) {
|
||||
assert(window->surfaces.count(surface_id) == 0);
|
||||
|
||||
Surface surface;
|
||||
surface.id = surface_id;
|
||||
surface.tile_width = tile_width;
|
||||
surface.tile_height = tile_height;
|
||||
surface.is_opaque = is_opaque;
|
||||
|
||||
window->surfaces.emplace(surface_id, surface);
|
||||
}
|
||||
|
||||
void com_wl_create_tile(WLWindow* window, uint64_t surface_id, int x, int y) {
|
||||
WLDisplay* display = window->display;
|
||||
|
||||
assert(window->surfaces.count(surface_id) == 1);
|
||||
Surface* surface = &window->surfaces.at(surface_id);
|
||||
|
||||
TileKey key(x, y);
|
||||
assert(surface->tiles.count(key) == 0);
|
||||
|
||||
Tile* tile = new Tile;
|
||||
tile->surface_id = surface_id;
|
||||
tile->x = x;
|
||||
tile->y = y;
|
||||
tile->is_visible = false;
|
||||
|
||||
tile->surface = wl_compositor_create_surface(display->compositor);
|
||||
tile->viewport =
|
||||
wp_viewporter_get_viewport(display->viewporter, tile->surface);
|
||||
|
||||
if (surface->is_opaque) {
|
||||
struct wl_region* region =
|
||||
wl_compositor_create_region(window->display->compositor);
|
||||
wl_region_add(region, 0, 0, INT32_MAX, INT32_MAX);
|
||||
wl_surface_set_opaque_region(tile->surface, region);
|
||||
wl_region_destroy(region);
|
||||
}
|
||||
|
||||
tile->egl_window = wl_egl_window_create(tile->surface, surface->tile_width,
|
||||
surface->tile_height);
|
||||
tile->egl_surface = eglCreateWindowSurface(window->eglDisplay, window->config,
|
||||
tile->egl_window, NULL);
|
||||
assert(tile->egl_surface != EGL_NO_SURFACE);
|
||||
|
||||
surface->tiles.emplace(key, tile);
|
||||
}
|
||||
|
||||
static void show_tile(WLWindow* window, Tile* tile) {
|
||||
if (tile->is_visible) {
|
||||
assert(tile->subsurface);
|
||||
return;
|
||||
}
|
||||
|
||||
tile->subsurface = wl_subcompositor_get_subsurface(
|
||||
window->display->subcompositor, tile->surface, window->surface);
|
||||
|
||||
/* This is not comprehensive yet, see hide_tile() */
|
||||
Surface* surface = &window->surfaces.at(tile->surface_id);
|
||||
for (auto tile_it = surface->tiles.begin(); tile_it != surface->tiles.end();
|
||||
++tile_it) {
|
||||
Tile* other_tile = tile_it->second;
|
||||
|
||||
if (other_tile->is_visible) {
|
||||
wl_subsurface_place_above(tile->subsurface, other_tile->surface);
|
||||
}
|
||||
}
|
||||
|
||||
tile->is_visible = true;
|
||||
}
|
||||
|
||||
static void hide_tile(WLWindow* window, Tile* tile) {
|
||||
if (!tile->is_visible) {
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* This is a workaround for missing API on the egl-wayland platform. We
|
||||
* likely want to replace it a solution that detaches the buffer from
|
||||
* the surface, which would require us to manage buffers manually.
|
||||
*/
|
||||
wl_subsurface_set_position(tile->subsurface, window->geometry.width / 2,
|
||||
window->geometry.height / 2);
|
||||
wp_viewport_set_source(tile->viewport, wl_fixed_from_int(0),
|
||||
wl_fixed_from_int(0), wl_fixed_from_int(1),
|
||||
wl_fixed_from_int(1));
|
||||
wl_subsurface_place_below(tile->subsurface, window->surface);
|
||||
tile->is_visible = false;
|
||||
window->hiddenTiles.push_back(tile);
|
||||
}
|
||||
|
||||
void com_wl_destroy_tile(WLWindow* window, uint64_t surface_id, int x, int y) {
|
||||
assert(window->surfaces.count(surface_id) == 1);
|
||||
|
||||
Surface* surface = &window->surfaces.at(surface_id);
|
||||
TileKey key(x, y);
|
||||
assert(surface->tiles.count(key) == 1);
|
||||
Tile* tile = surface->tiles[key];
|
||||
|
||||
hide_tile(window, tile);
|
||||
wl_surface_commit(tile->surface);
|
||||
|
||||
window->destroyedTiles.push_back(tile);
|
||||
surface->tiles.erase(key);
|
||||
}
|
||||
|
||||
void com_wl_destroy_surface(WLWindow* window, uint64_t surface_id) {
|
||||
assert(window->surfaces.count(surface_id) == 1);
|
||||
|
||||
Surface* surface = &window->surfaces.at(surface_id);
|
||||
for (auto tile_it = surface->tiles.begin(); tile_it != surface->tiles.end();
|
||||
tile_it = surface->tiles.begin()) {
|
||||
Tile* tile = tile_it->second;
|
||||
|
||||
com_wl_destroy_tile(window, surface_id, tile->x, tile->y);
|
||||
}
|
||||
|
||||
window->surfaces.erase(surface_id);
|
||||
}
|
||||
|
||||
void com_wl_destroy_window(WLWindow* window) {
|
||||
for (auto surface_it = window->surfaces.begin();
|
||||
surface_it != window->surfaces.end(); ++surface_it) {
|
||||
Surface& surface = surface_it->second;
|
||||
|
||||
com_wl_destroy_surface(window, surface.id);
|
||||
}
|
||||
|
||||
if (window->egl_surface != EGL_NO_SURFACE) {
|
||||
eglDestroySurface(window->eglDisplay, window->egl_surface);
|
||||
}
|
||||
eglDestroyContext(window->eglDisplay, window->eglContext);
|
||||
eglTerminate(window->eglDisplay);
|
||||
|
||||
delete window;
|
||||
}
|
||||
|
||||
// Bind a native surface to allow issuing GL commands to it
|
||||
GLuint com_wl_bind_surface(WLWindow* window, uint64_t surface_id, int tile_x,
|
||||
int tile_y, int* x_offset, int* y_offset,
|
||||
int dirty_x0, int dirty_y0, int dirty_width,
|
||||
int dirty_height) {
|
||||
*x_offset = 0;
|
||||
*y_offset = 0;
|
||||
|
||||
assert(window->surfaces.count(surface_id) == 1);
|
||||
Surface* surface = &window->surfaces[surface_id];
|
||||
|
||||
TileKey key(tile_x, tile_y);
|
||||
assert(surface->tiles.count(key) == 1);
|
||||
Tile* tile = surface->tiles[key];
|
||||
|
||||
tile->damage_rects.push_back(dirty_x0);
|
||||
tile->damage_rects.push_back(dirty_y0);
|
||||
tile->damage_rects.push_back(dirty_width);
|
||||
tile->damage_rects.push_back(dirty_height);
|
||||
|
||||
EGLBoolean ok = eglMakeCurrent(window->eglDisplay, tile->egl_surface,
|
||||
tile->egl_surface, window->eglContext);
|
||||
assert(ok);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Unbind a currently bound native surface
|
||||
void com_wl_unbind_surface(WLWindow* window) {
|
||||
eglMakeCurrent(window->eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE,
|
||||
window->eglContext);
|
||||
}
|
||||
|
||||
void com_wl_begin_transaction(WLWindow*) {}
|
||||
|
||||
// Add a native surface to the visual tree. Called per-frame to build the
|
||||
// composition.
|
||||
void com_wl_add_surface(WLWindow* window, uint64_t surface_id, int offset_x,
|
||||
int offset_y, int clip_x, int clip_y, int clip_w,
|
||||
int clip_h) {
|
||||
Surface* surface = &window->surfaces[surface_id];
|
||||
window->currentLayers.push_back(surface_id);
|
||||
|
||||
for (auto tile_it = surface->tiles.begin(); tile_it != surface->tiles.end();
|
||||
++tile_it) {
|
||||
Tile* tile = tile_it->second;
|
||||
|
||||
int pos_x = MAX((tile->x * surface->tile_width) + offset_x, clip_x);
|
||||
int pos_y = MAX((tile->y * surface->tile_height) + offset_y, clip_y);
|
||||
|
||||
float view_x = MAX((clip_x - offset_x) - tile->x * surface->tile_width, 0);
|
||||
float view_y = MAX((clip_y - offset_y) - tile->y * surface->tile_height, 0);
|
||||
|
||||
float view_w = MIN(surface->tile_width - view_x, (clip_x + clip_w) - pos_x);
|
||||
float view_h =
|
||||
MIN(surface->tile_height - view_y, (clip_y + clip_h) - pos_y);
|
||||
view_w = MIN(window->geometry.width - pos_x, view_w);
|
||||
view_h = MIN(window->geometry.height - pos_y, view_h);
|
||||
|
||||
if (view_w > 0 && view_h > 0) {
|
||||
show_tile(window, tile);
|
||||
|
||||
wl_surface_set_buffer_transform(tile->surface,
|
||||
WL_OUTPUT_TRANSFORM_FLIPPED_180);
|
||||
wl_subsurface_set_position(tile->subsurface, pos_x, pos_y);
|
||||
wp_viewport_set_source(tile->viewport, wl_fixed_from_double(view_x),
|
||||
wl_fixed_from_double(view_y),
|
||||
wl_fixed_from_double(view_w),
|
||||
wl_fixed_from_double(view_h));
|
||||
} else {
|
||||
hide_tile(window, tile);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void com_wl_end_transaction(WLWindow* window) {
|
||||
bool same = window->prevLayers == window->currentLayers;
|
||||
if (!same) {
|
||||
struct wl_surface* prev_surface = window->surface;
|
||||
|
||||
for (auto it = window->currentLayers.begin();
|
||||
it != window->currentLayers.end(); ++it) {
|
||||
Surface* surface = &window->surfaces[*it];
|
||||
|
||||
struct wl_surface* next_surface = nullptr;
|
||||
for (auto tile_it = surface->tiles.begin();
|
||||
tile_it != surface->tiles.end(); ++tile_it) {
|
||||
Tile* tile = tile_it->second;
|
||||
|
||||
if (tile->is_visible) {
|
||||
wl_subsurface_place_above(tile->subsurface, prev_surface);
|
||||
|
||||
if (!next_surface) {
|
||||
next_surface = tile->surface;
|
||||
}
|
||||
}
|
||||
}
|
||||
prev_surface = next_surface;
|
||||
}
|
||||
}
|
||||
|
||||
window->prevLayers.swap(window->currentLayers);
|
||||
window->currentLayers.clear();
|
||||
}
|
||||
|
||||
void glInvalidateFramebuffer(GLenum target, GLsizei numAttachments,
|
||||
const GLenum* attachments) {
|
||||
UNUSED(target);
|
||||
UNUSED(numAttachments);
|
||||
UNUSED(attachments);
|
||||
}
|
||||
|
||||
// Get a pointer to an EGL symbol
|
||||
void* com_wl_get_proc_address(const char* name) {
|
||||
/* Disable glInvalidateFramebuffer for now as it triggers errors.
|
||||
* This is likely due to the egl-wayland platform, which we may want to
|
||||
* replace with a custom implementation in order to have more control
|
||||
* over the low-lever bits.
|
||||
*/
|
||||
if (strcmp(name, "glInvalidateFramebuffer") == 0) {
|
||||
return (void*)glInvalidateFramebuffer;
|
||||
}
|
||||
|
||||
return (void*)eglGetProcAddress(name);
|
||||
}
|
||||
|
||||
void com_wl_deinit(WLWindow* window) { UNUSED(window); }
|
||||
|
||||
static void handle_xdg_surface_configure(void* data,
|
||||
struct xdg_surface* surface,
|
||||
uint32_t serial) {
|
||||
WLWindow* window = (WLWindow*)data;
|
||||
|
||||
xdg_surface_ack_configure(surface, serial);
|
||||
|
||||
if (window->wait_for_configure) {
|
||||
if (window->enable_compositor) {
|
||||
int width = window->geometry.width;
|
||||
int height = window->geometry.height;
|
||||
|
||||
window->egl_window = wl_egl_window_create(window->surface, 1, 1);
|
||||
window->egl_surface = eglCreateWindowSurface(
|
||||
window->eglDisplay, window->config, window->egl_window, NULL);
|
||||
assert(window->egl_surface != EGL_NO_SURFACE);
|
||||
|
||||
EGLBoolean ok = eglMakeCurrent(window->eglDisplay, window->egl_surface,
|
||||
window->egl_surface, window->eglContext);
|
||||
assert(ok);
|
||||
|
||||
glClearColor(1.0, 1.0, 1.0, 1.0);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
|
||||
window->viewport = wp_viewporter_get_viewport(window->display->viewporter,
|
||||
window->surface);
|
||||
wp_viewport_set_destination(window->viewport, width, height);
|
||||
|
||||
eglSwapBuffers(window->eglDisplay, window->egl_surface);
|
||||
} else {
|
||||
window->egl_window = wl_egl_window_create(
|
||||
window->surface, window->geometry.width, window->geometry.height);
|
||||
window->egl_surface = eglCreateWindowSurface(
|
||||
window->eglDisplay, window->config, window->egl_window, NULL);
|
||||
assert(window->egl_surface != EGL_NO_SURFACE);
|
||||
|
||||
EGLBoolean ok = eglMakeCurrent(window->eglDisplay, window->egl_surface,
|
||||
window->egl_surface, window->eglContext);
|
||||
assert(ok);
|
||||
}
|
||||
}
|
||||
|
||||
window->wait_for_configure = false;
|
||||
}
|
||||
|
||||
static const struct xdg_surface_listener xdg_surface_listener = {
|
||||
handle_xdg_surface_configure};
|
||||
|
||||
static void handle_xdg_toplevel_configure(void* data,
|
||||
struct xdg_toplevel* toplevel,
|
||||
int32_t width, int32_t height,
|
||||
struct wl_array* states) {
|
||||
WLWindow* window = (WLWindow*)data;
|
||||
UNUSED(toplevel);
|
||||
UNUSED(states);
|
||||
|
||||
if (width > 0 && height > 0) {
|
||||
window->geometry.width = width;
|
||||
window->geometry.height = height;
|
||||
|
||||
if (!window->wait_for_configure) {
|
||||
if (window->enable_compositor) {
|
||||
wp_viewport_set_destination(window->viewport, window->geometry.width,
|
||||
window->geometry.height);
|
||||
} else {
|
||||
wl_egl_window_resize(window->egl_window, window->geometry.width,
|
||||
window->geometry.height, 0, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void handle_xdg_toplevel_close(void* data,
|
||||
struct xdg_toplevel* toplevel) {
|
||||
UNUSED(toplevel);
|
||||
WLWindow* window = (WLWindow*)data;
|
||||
window->closed = true;
|
||||
}
|
||||
|
||||
static const struct xdg_toplevel_listener xdg_toplevel_listener = {
|
||||
handle_xdg_toplevel_configure,
|
||||
handle_xdg_toplevel_close,
|
||||
};
|
||||
|
||||
static void xdg_wm_base_ping(void* data, struct xdg_wm_base* shell,
|
||||
uint32_t serial) {
|
||||
UNUSED(data);
|
||||
xdg_wm_base_pong(shell, serial);
|
||||
}
|
||||
|
||||
static const struct xdg_wm_base_listener wm_base_listener = {
|
||||
xdg_wm_base_ping,
|
||||
};
|
||||
|
||||
static void registry_handle_global(void* data, struct wl_registry* registry,
|
||||
uint32_t name, const char* interface,
|
||||
uint32_t version) {
|
||||
WLDisplay* d = (WLDisplay*)data;
|
||||
|
||||
if (strcmp(interface, "wl_compositor") == 0) {
|
||||
d->compositor = (struct wl_compositor*)wl_registry_bind(
|
||||
registry, name, &wl_compositor_interface, MIN(version, 4));
|
||||
} else if (strcmp(interface, "wp_viewporter") == 0) {
|
||||
d->viewporter = (struct wp_viewporter*)wl_registry_bind(
|
||||
registry, name, &wp_viewporter_interface, 1);
|
||||
} else if (strcmp(interface, "xdg_wm_base") == 0) {
|
||||
d->wm_base = (struct xdg_wm_base*)wl_registry_bind(
|
||||
registry, name, &xdg_wm_base_interface, 1);
|
||||
xdg_wm_base_add_listener(d->wm_base, &wm_base_listener, NULL);
|
||||
} else if (strcmp(interface, "wl_subcompositor") == 0) {
|
||||
d->subcompositor = (struct wl_subcompositor*)wl_registry_bind(
|
||||
registry, name, &wl_subcompositor_interface, 1);
|
||||
}
|
||||
}
|
||||
|
||||
static void registry_handle_global_remove(void* data,
|
||||
struct wl_registry* registry,
|
||||
uint32_t name) {
|
||||
UNUSED(data);
|
||||
UNUSED(registry);
|
||||
UNUSED(name);
|
||||
}
|
||||
|
||||
static const struct wl_registry_listener registry_listener = {
|
||||
registry_handle_global, registry_handle_global_remove};
|
||||
|
||||
static void init_wl_registry(WLWindow* window) {
|
||||
WLDisplay* display = window->display;
|
||||
|
||||
display->registry = wl_display_get_registry(display->display);
|
||||
wl_registry_add_listener(display->registry, ®istry_listener, display);
|
||||
|
||||
wl_display_roundtrip(display->display);
|
||||
|
||||
assert(display->compositor);
|
||||
assert(display->wm_base);
|
||||
assert(display->subcompositor);
|
||||
}
|
||||
|
||||
static void init_xdg_window(WLWindow* window) {
|
||||
window->xdg_surface =
|
||||
xdg_wm_base_get_xdg_surface(window->display->wm_base, window->surface);
|
||||
assert(window->xdg_surface);
|
||||
xdg_surface_add_listener(window->xdg_surface, &xdg_surface_listener, window);
|
||||
|
||||
window->xdg_toplevel = xdg_surface_get_toplevel(window->xdg_surface);
|
||||
xdg_toplevel_add_listener(window->xdg_toplevel, &xdg_toplevel_listener,
|
||||
window);
|
||||
assert(window->xdg_toplevel);
|
||||
}
|
||||
}
|
269
third_party/webrender/example-compositor/compositor-wayland/src/lib.rs
vendored
Normal file
269
third_party/webrender/example-compositor/compositor-wayland/src/lib.rs
vendored
Normal file
|
@ -0,0 +1,269 @@
|
|||
/* 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/. */
|
||||
|
||||
use std::os::raw::{c_void, c_char};
|
||||
|
||||
/*
|
||||
|
||||
This is a very simple (and unsafe!) rust wrapper for the Wayland / EGL
|
||||
implementation in lib.cpp.
|
||||
|
||||
It just proxies the calls from the Compositor impl to the C99 code. This is very
|
||||
hacky and not suitable for production!
|
||||
|
||||
*/
|
||||
|
||||
// Opaque wrapper for the Window type in lib.cpp
|
||||
#[repr(C)]
|
||||
pub struct Window {
|
||||
_unused: [u8; 0]
|
||||
}
|
||||
|
||||
// C99 functions that do the compositor work
|
||||
extern {
|
||||
fn com_wl_create_window(
|
||||
width: i32,
|
||||
height: i32,
|
||||
enable_compositor: bool,
|
||||
sync_mode: i32,
|
||||
) -> *mut Window;
|
||||
fn com_wl_destroy_window(window: *mut Window);
|
||||
fn com_wl_tick(window: *mut Window) -> bool;
|
||||
fn com_wl_get_proc_address(name: *const c_char) -> *const c_void;
|
||||
fn com_wl_swap_buffers(window: *mut Window);
|
||||
|
||||
fn com_wl_create_surface(
|
||||
window: *mut Window,
|
||||
id: u64,
|
||||
tile_width: i32,
|
||||
tile_height: i32,
|
||||
is_opaque: bool,
|
||||
);
|
||||
|
||||
fn com_wl_create_tile(
|
||||
window: *mut Window,
|
||||
id: u64,
|
||||
x: i32,
|
||||
y: i32,
|
||||
);
|
||||
|
||||
fn com_wl_destroy_tile(
|
||||
window: *mut Window,
|
||||
id: u64,
|
||||
x: i32,
|
||||
y: i32,
|
||||
);
|
||||
|
||||
fn com_wl_destroy_surface(
|
||||
window: *mut Window,
|
||||
id: u64,
|
||||
);
|
||||
|
||||
fn com_wl_bind_surface(
|
||||
window: *mut Window,
|
||||
surface_id: u64,
|
||||
tile_x: i32,
|
||||
tile_y: i32,
|
||||
x_offset: &mut i32,
|
||||
y_offset: &mut i32,
|
||||
dirty_x0: i32,
|
||||
dirty_y0: i32,
|
||||
dirty_width: i32,
|
||||
dirty_height: i32,
|
||||
) -> u32;
|
||||
fn com_wl_unbind_surface(window: *mut Window);
|
||||
|
||||
fn com_wl_begin_transaction(window: *mut Window);
|
||||
|
||||
fn com_wl_add_surface(
|
||||
window: *mut Window,
|
||||
id: u64,
|
||||
x: i32,
|
||||
y: i32,
|
||||
clip_x: i32,
|
||||
clip_y: i32,
|
||||
clip_w: i32,
|
||||
clip_h: i32,
|
||||
);
|
||||
|
||||
fn com_wl_end_transaction(window: *mut Window);
|
||||
|
||||
fn com_wl_deinit(window: *mut Window);
|
||||
}
|
||||
|
||||
pub fn create_window(
|
||||
width: i32,
|
||||
height: i32,
|
||||
enable_compositor: bool,
|
||||
sync_mode: i32,
|
||||
) -> *mut Window {
|
||||
unsafe {
|
||||
com_wl_create_window(width, height, enable_compositor, sync_mode)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn destroy_window(window: *mut Window) {
|
||||
unsafe {
|
||||
com_wl_destroy_window(window);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn tick(window: *mut Window) -> bool {
|
||||
unsafe {
|
||||
com_wl_tick(window)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_proc_address(name: *const c_char) -> *const c_void {
|
||||
unsafe {
|
||||
com_wl_get_proc_address(name)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn create_surface(
|
||||
window: *mut Window,
|
||||
id: u64,
|
||||
tile_width: i32,
|
||||
tile_height: i32,
|
||||
is_opaque: bool,
|
||||
) {
|
||||
unsafe {
|
||||
com_wl_create_surface(
|
||||
window,
|
||||
id,
|
||||
tile_width,
|
||||
tile_height,
|
||||
is_opaque,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn create_tile(
|
||||
window: *mut Window,
|
||||
id: u64,
|
||||
x: i32,
|
||||
y: i32,
|
||||
) {
|
||||
unsafe {
|
||||
com_wl_create_tile(
|
||||
window,
|
||||
id,
|
||||
x,
|
||||
y,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn destroy_tile(
|
||||
window: *mut Window,
|
||||
id: u64,
|
||||
x: i32,
|
||||
y: i32,
|
||||
) {
|
||||
unsafe {
|
||||
com_wl_destroy_tile(
|
||||
window,
|
||||
id,
|
||||
x,
|
||||
y,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn destroy_surface(
|
||||
window: *mut Window,
|
||||
id: u64,
|
||||
) {
|
||||
unsafe {
|
||||
com_wl_destroy_surface(
|
||||
window,
|
||||
id,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn bind_surface(
|
||||
window: *mut Window,
|
||||
surface_id: u64,
|
||||
tile_x: i32,
|
||||
tile_y: i32,
|
||||
dirty_x0: i32,
|
||||
dirty_y0: i32,
|
||||
dirty_width: i32,
|
||||
dirty_height: i32,
|
||||
) -> (u32, i32, i32) {
|
||||
unsafe {
|
||||
let mut x_offset = 0;
|
||||
let mut y_offset = 0;
|
||||
|
||||
let fbo_id = com_wl_bind_surface(
|
||||
window,
|
||||
surface_id,
|
||||
tile_x,
|
||||
tile_y,
|
||||
&mut x_offset,
|
||||
&mut y_offset,
|
||||
dirty_x0,
|
||||
dirty_y0,
|
||||
dirty_width,
|
||||
dirty_height,
|
||||
);
|
||||
|
||||
(fbo_id, x_offset, y_offset)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add_surface(
|
||||
window: *mut Window,
|
||||
id: u64,
|
||||
x: i32,
|
||||
y: i32,
|
||||
clip_x: i32,
|
||||
clip_y: i32,
|
||||
clip_w: i32,
|
||||
clip_h: i32,
|
||||
) {
|
||||
unsafe {
|
||||
com_wl_add_surface(
|
||||
window,
|
||||
id,
|
||||
x,
|
||||
y,
|
||||
clip_x,
|
||||
clip_y,
|
||||
clip_w,
|
||||
clip_h,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn begin_transaction(window: *mut Window) {
|
||||
unsafe {
|
||||
com_wl_begin_transaction(window)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn unbind_surface(window: *mut Window) {
|
||||
unsafe {
|
||||
com_wl_unbind_surface(window)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn end_transaction(window: *mut Window) {
|
||||
unsafe {
|
||||
com_wl_end_transaction(window)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn swap_buffers(window: *mut Window) {
|
||||
unsafe {
|
||||
com_wl_swap_buffers(window);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn deinit(window: *mut Window) {
|
||||
unsafe {
|
||||
com_wl_deinit(window);
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load diff
|
@ -88,6 +88,8 @@ extern {
|
|||
);
|
||||
|
||||
fn com_dc_end_transaction(window: *mut Window);
|
||||
|
||||
fn deinit(window: *mut Window);
|
||||
}
|
||||
|
||||
pub fn create_window(
|
||||
|
@ -259,3 +261,7 @@ pub fn swap_buffers(window: *mut Window) {
|
|||
com_dc_swap_buffers(window);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn deinit(window: *mut Window) {
|
||||
todo!()
|
||||
}
|
||||
|
|
|
@ -7,7 +7,10 @@ license = "MPL-2.0"
|
|||
|
||||
[dependencies]
|
||||
webrender = { path = "../../webrender" }
|
||||
gleam = "0.12.0"
|
||||
gleam = "0.15"
|
||||
|
||||
[target.'cfg(windows)'.dependencies]
|
||||
compositor-windows = { path = "../compositor-windows" }
|
||||
|
||||
[target.'cfg(target_os = "linux")'.dependencies]
|
||||
compositor-wayland = { path = "../compositor-wayland" }
|
||||
|
|
|
@ -16,10 +16,12 @@ use euclid::Angle;
|
|||
use gleam::gl;
|
||||
use std::ffi::CString;
|
||||
use std::sync::mpsc;
|
||||
use webrender::api::*;
|
||||
use webrender::{CompositorSurfaceTransform, Transaction, api::*, euclid::point2};
|
||||
use webrender::api::units::*;
|
||||
#[cfg(target_os = "windows")]
|
||||
use compositor_windows as compositor;
|
||||
#[cfg(target_os = "linux")]
|
||||
use compositor_wayland as compositor;
|
||||
use std::{env, f32, process};
|
||||
|
||||
// A very hacky integration with DirectComposite. It proxies calls from the compositor
|
||||
|
@ -42,6 +44,7 @@ impl webrender::Compositor for DirectCompositeInterface {
|
|||
fn create_surface(
|
||||
&mut self,
|
||||
id: webrender::NativeSurfaceId,
|
||||
_virtual_offset: DeviceIntPoint,
|
||||
tile_size: DeviceIntSize,
|
||||
is_opaque: bool,
|
||||
) {
|
||||
|
@ -89,6 +92,7 @@ impl webrender::Compositor for DirectCompositeInterface {
|
|||
&mut self,
|
||||
id: webrender::NativeTileId,
|
||||
dirty_rect: DeviceIntRect,
|
||||
_valid_rect: DeviceIntRect,
|
||||
) -> webrender::NativeSurfaceInfo {
|
||||
let (fbo_id, x, y) = compositor::bind_surface(
|
||||
self.window,
|
||||
|
@ -118,14 +122,15 @@ impl webrender::Compositor for DirectCompositeInterface {
|
|||
fn add_surface(
|
||||
&mut self,
|
||||
id: webrender::NativeSurfaceId,
|
||||
position: DeviceIntPoint,
|
||||
transform: CompositorSurfaceTransform,
|
||||
clip_rect: DeviceIntRect,
|
||||
_image_rendering: ImageRendering,
|
||||
) {
|
||||
compositor::add_surface(
|
||||
self.window,
|
||||
id.0,
|
||||
position.x,
|
||||
position.y,
|
||||
transform.transform_point2d(point2(0., 0.)).unwrap().x as i32,
|
||||
transform.transform_point2d(point2(0., 0.)).unwrap().y as i32,
|
||||
clip_rect.origin.x,
|
||||
clip_rect.origin.y,
|
||||
clip_rect.size.width,
|
||||
|
@ -136,6 +141,42 @@ impl webrender::Compositor for DirectCompositeInterface {
|
|||
fn end_frame(&mut self) {
|
||||
compositor::end_transaction(self.window);
|
||||
}
|
||||
fn create_external_surface(&mut self, _: webrender::NativeSurfaceId, _: bool) { todo!() }
|
||||
|
||||
fn attach_external_image(
|
||||
&mut self,
|
||||
_id: webrender::NativeSurfaceId,
|
||||
_external_image: ExternalImageId
|
||||
) {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn enable_native_compositor(&mut self, _enable: bool) {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn deinit(&mut self) {
|
||||
compositor::deinit(self.window);
|
||||
}
|
||||
|
||||
fn get_capabilities(&self) -> webrender::CompositorCapabilities {
|
||||
webrender::CompositorCapabilities {
|
||||
virtual_surface_size: 1024 * 1024,
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
|
||||
fn invalidate_tile(
|
||||
&mut self,
|
||||
_id: webrender::NativeTileId,
|
||||
_valid_rect: DeviceIntRect,
|
||||
) {}
|
||||
|
||||
fn start_compositing(
|
||||
&mut self,
|
||||
_dirty_rects: &[DeviceIntRect],
|
||||
_opaque_rects: &[DeviceIntRect],
|
||||
) {}
|
||||
}
|
||||
|
||||
// Simplisitic implementation of the WR notifier interface to know when a frame
|
||||
|
@ -159,7 +200,7 @@ impl RenderNotifier for Notifier {
|
|||
})
|
||||
}
|
||||
|
||||
fn wake_up(&self) {
|
||||
fn wake_up(&self, _composite_needed: bool) {
|
||||
}
|
||||
|
||||
fn new_frame_ready(&self,
|
||||
|
@ -181,7 +222,7 @@ fn push_rotated_rect(
|
|||
time: f32,
|
||||
) {
|
||||
let color = color.scale_rgb(time);
|
||||
let rotation = LayoutTransform::create_rotation(
|
||||
let rotation = LayoutTransform::rotation(
|
||||
0.0,
|
||||
0.0,
|
||||
1.0,
|
||||
|
@ -194,13 +235,16 @@ fn push_rotated_rect(
|
|||
);
|
||||
let transform = rotation
|
||||
.pre_translate(-transform_origin)
|
||||
.post_translate(transform_origin);
|
||||
.then_translate(transform_origin);
|
||||
let spatial_id = builder.push_reference_frame(
|
||||
LayoutPoint::zero(),
|
||||
spatial_id,
|
||||
TransformStyle::Flat,
|
||||
PropertyBinding::Value(transform),
|
||||
ReferenceFrameKind::Transform,
|
||||
ReferenceFrameKind::Transform {
|
||||
is_2d_scale_translation: false,
|
||||
should_snap: false,
|
||||
},
|
||||
);
|
||||
builder.push_rect(
|
||||
&CommonItemProperties::new(
|
||||
|
@ -235,7 +279,7 @@ fn build_display_list(
|
|||
|
||||
let scroll_space_info = builder.define_scroll_frame(
|
||||
&fixed_space_info,
|
||||
Some(scroll_id),
|
||||
scroll_id,
|
||||
LayoutRect::new(LayoutPoint::zero(), layout_size),
|
||||
LayoutRect::new(LayoutPoint::zero(), layout_size),
|
||||
ScrollSensitivity::Script,
|
||||
|
@ -289,6 +333,32 @@ fn build_display_list(
|
|||
0.1,
|
||||
time,
|
||||
);
|
||||
|
||||
push_rotated_rect(
|
||||
builder,
|
||||
LayoutRect::new(
|
||||
LayoutPoint::new(100.0, 600.0),
|
||||
LayoutSize::new(size_factor * 400.0, size_factor * 400.0),
|
||||
),
|
||||
ColorF::new(1.0, 1.0, 0.0, 1.0),
|
||||
scroll_space_info.spatial_id,
|
||||
root_pipeline_id,
|
||||
time,
|
||||
time,
|
||||
);
|
||||
|
||||
push_rotated_rect(
|
||||
builder,
|
||||
LayoutRect::new(
|
||||
LayoutPoint::new(700.0, 600.0),
|
||||
LayoutSize::new(size_factor * 400.0, size_factor * 400.0),
|
||||
),
|
||||
ColorF::new(0.0, 1.0, 1.0, 1.0),
|
||||
scroll_space_info.spatial_id,
|
||||
root_pipeline_id,
|
||||
time,
|
||||
time,
|
||||
);
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
|
@ -358,13 +428,15 @@ fn main() {
|
|||
} else {
|
||||
webrender::CompositorConfig::Draw {
|
||||
max_partial_present_rects: 0,
|
||||
draw_previous_partial_present_regions: false,
|
||||
partial_present: None,
|
||||
}
|
||||
};
|
||||
let opts = webrender::RendererOptions {
|
||||
clear_color: Some(ColorF::new(1.0, 1.0, 1.0, 1.0)),
|
||||
debug_flags,
|
||||
enable_picture_caching: true,
|
||||
compositor_config,
|
||||
surface_origin_is_top_left: false,
|
||||
..webrender::RendererOptions::default()
|
||||
};
|
||||
let (tx, rx) = mpsc::channel();
|
||||
|
@ -383,10 +455,9 @@ fn main() {
|
|||
notifier,
|
||||
opts,
|
||||
None,
|
||||
device_size,
|
||||
).unwrap();
|
||||
let api = sender.create_api();
|
||||
let document_id = api.add_document(device_size, 0);
|
||||
let mut api = sender.create_api();
|
||||
let document_id = api.add_document(device_size);
|
||||
let device_pixel_ratio = 1.0;
|
||||
let mut current_epoch = Epoch(0);
|
||||
let root_pipeline_id = PipelineId(0, 0);
|
||||
|
@ -399,7 +470,7 @@ fn main() {
|
|||
txn.set_root_pipeline(root_pipeline_id);
|
||||
|
||||
if let Invalidations::Scrolling = inv_mode {
|
||||
let mut root_builder = DisplayListBuilder::new(root_pipeline_id, layout_size);
|
||||
let mut root_builder = DisplayListBuilder::new(root_pipeline_id);
|
||||
|
||||
build_display_list(
|
||||
&mut root_builder,
|
||||
|
@ -419,7 +490,7 @@ fn main() {
|
|||
);
|
||||
}
|
||||
|
||||
txn.generate_frame();
|
||||
txn.generate_frame(0);
|
||||
api.send_transaction(document_id, txn);
|
||||
|
||||
// Tick the compositor (in this sample, we don't block on UI events)
|
||||
|
@ -429,7 +500,7 @@ fn main() {
|
|||
// Update and render. This will invoke the native compositor interface implemented above
|
||||
// as required.
|
||||
renderer.update();
|
||||
renderer.render(device_size).unwrap();
|
||||
renderer.render(device_size, 0).unwrap();
|
||||
let _ = renderer.flush_pipeline_info();
|
||||
|
||||
// Construct a simple display list that can be drawn and composited by DC.
|
||||
|
@ -437,7 +508,7 @@ fn main() {
|
|||
|
||||
match inv_mode {
|
||||
Invalidations::Small | Invalidations::Large => {
|
||||
let mut root_builder = DisplayListBuilder::new(root_pipeline_id, layout_size);
|
||||
let mut root_builder = DisplayListBuilder::new(root_pipeline_id);
|
||||
|
||||
build_display_list(
|
||||
&mut root_builder,
|
||||
|
@ -466,7 +537,7 @@ fn main() {
|
|||
}
|
||||
}
|
||||
|
||||
txn.generate_frame();
|
||||
txn.generate_frame(0);
|
||||
api.send_transaction(document_id, txn);
|
||||
current_epoch.0 += 1;
|
||||
time += 0.001;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue