diff options
author | Mukilan Thiyagarajan <mukilan@igalia.com> | 2023-09-14 15:00:42 +0530 |
---|---|---|
committer | Mukilan Thiyagarajan <mukilan@igalia.com> | 2023-09-14 15:00:42 +0530 |
commit | c385b3c9737c17d59cb02e520c3b68b232cb6497 (patch) | |
tree | ad598ffbbdfbcecd6a4cf458abe2afc702d92c27 /third_party/webrender/example-compositor | |
parent | 988e05a68b48c9e744bf49459faf41a1bd9b81d7 (diff) | |
download | servo-revert-webrender.tar.gz servo-revert-webrender.zip |
Revert "Upgrade WebRender to e491e1ae637b2eed1e7195855d88357e5eb3ddf9 (#30323)"revert-webrender
This reverts commit a9d37cb85ac2c55fc630fccffe1ba60ff00f555b.
Diffstat (limited to 'third_party/webrender/example-compositor')
8 files changed, 696 insertions, 1783 deletions
diff --git a/third_party/webrender/example-compositor/compositor-wayland/Cargo.toml b/third_party/webrender/example-compositor/compositor-wayland/Cargo.toml deleted file mode 100644 index 0f5bba73b5c..00000000000 --- a/third_party/webrender/example-compositor/compositor-wayland/Cargo.toml +++ /dev/null @@ -1,11 +0,0 @@ -[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" diff --git a/third_party/webrender/example-compositor/compositor-wayland/build.rs b/third_party/webrender/example-compositor/compositor-wayland/build.rs deleted file mode 100644 index ab418b94c79..00000000000 --- a/third_party/webrender/example-compositor/compositor-wayland/build.rs +++ /dev/null @@ -1,63 +0,0 @@ -/* 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"); -} diff --git a/third_party/webrender/example-compositor/compositor-wayland/src/lib.cpp b/third_party/webrender/example-compositor/compositor-wayland/src/lib.cpp deleted file mode 100644 index 5529c987a9e..00000000000 --- a/third_party/webrender/example-compositor/compositor-wayland/src/lib.cpp +++ /dev/null @@ -1,772 +0,0 @@ -/* 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); -} -} diff --git a/third_party/webrender/example-compositor/compositor-wayland/src/lib.rs b/third_party/webrender/example-compositor/compositor-wayland/src/lib.rs deleted file mode 100644 index daddbb6495e..00000000000 --- a/third_party/webrender/example-compositor/compositor-wayland/src/lib.rs +++ /dev/null @@ -1,269 +0,0 @@ -/* 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); - } -} diff --git a/third_party/webrender/example-compositor/compositor-windows/src/lib.cpp b/third_party/webrender/example-compositor/compositor-windows/src/lib.cpp index d39726ea0ab..e17f602a2ec 100644 --- a/third_party/webrender/example-compositor/compositor-windows/src/lib.cpp +++ b/third_party/webrender/example-compositor/compositor-windows/src/lib.cpp @@ -31,664 +31,772 @@ #define VIRTUAL_OFFSET 512 * 1024 enum SyncMode { - None = 0, - Swap = 1, - Commit = 2, - Flush = 3, - Query = 4, + None = 0, + Swap = 1, + Commit = 2, + Flush = 3, + Query = 4, }; // The OS compositor representation of a picture cache tile. struct Tile { #ifndef USE_VIRTUAL_SURFACES - // Represents the underlying DirectComposition surface texture that gets drawn - // into. - IDCompositionSurface* pSurface; - // Represents the node in the visual tree that defines the properties of this - // tile (clip, position etc). - IDCompositionVisual2* pVisual; + // Represents the underlying DirectComposition surface texture that gets drawn into. + IDCompositionSurface *pSurface; + // Represents the node in the visual tree that defines the properties of this tile (clip, position etc). + IDCompositionVisual2 *pVisual; #endif }; struct TileKey { - int x; - int y; + int x; + int y; - TileKey(int ax, int ay) : x(ax), y(ay) {} + 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; +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; } + size_t operator()(const TileKey &key) const { + return key.x ^ key.y; + } }; struct Surface { - int tile_width; - int tile_height; - bool is_opaque; - std::unordered_map<TileKey, Tile, TileKeyHasher> tiles; - IDCompositionVisual2* pVisual; + int tile_width; + int tile_height; + bool is_opaque; + std::unordered_map<TileKey, Tile, TileKeyHasher> tiles; + IDCompositionVisual2 *pVisual; #ifdef USE_VIRTUAL_SURFACES - IDCompositionVirtualSurface* pVirtualSurface; + IDCompositionVirtualSurface *pVirtualSurface; #endif }; struct CachedFrameBuffer { - int width; - int height; - GLuint fboId; - GLuint depthRboId; + int width; + int height; + GLuint fboId; + GLuint depthRboId; }; struct Window { - // Win32 window details - HWND hWnd; - HINSTANCE hInstance; - bool enable_compositor; - RECT client_rect; - SyncMode sync_mode; - - // Main interfaces to D3D11 and DirectComposition - ID3D11Device* pD3D11Device; - IDCompositionDesktopDevice* pDCompDevice; - IDCompositionTarget* pDCompTarget; - IDXGIDevice* pDXGIDevice; - ID3D11Query* pQueries[NUM_QUERIES]; - int current_query; - - // ANGLE interfaces that wrap the D3D device - EGLDeviceEXT EGLDevice; - EGLDisplay EGLDisplay; - EGLContext EGLContext; - EGLConfig config; - // Framebuffer surface for debug mode when we are not using DC - EGLSurface fb_surface; - - // The currently bound surface, valid during bind() and unbind() - IDCompositionSurface* pCurrentSurface; - EGLImage mEGLImage; - GLuint mColorRBO; - - // The root of the DC visual tree. Nothing is drawn on this, but - // all child tiles are parented to here. - IDCompositionVisual2* pRoot; - IDCompositionVisualDebug* pVisualDebug; - std::vector<CachedFrameBuffer> mFrameBuffers; - - // Maintain list of layer state between frames to avoid visual tree rebuild. - std::vector<uint64_t> mCurrentLayers; - std::vector<uint64_t> mPrevLayers; - - // Maps WR surface IDs to each OS surface - std::unordered_map<uint64_t, Surface> surfaces; + // Win32 window details + HWND hWnd; + HINSTANCE hInstance; + bool enable_compositor; + RECT client_rect; + SyncMode sync_mode; + + // Main interfaces to D3D11 and DirectComposition + ID3D11Device *pD3D11Device; + IDCompositionDesktopDevice *pDCompDevice; + IDCompositionTarget *pDCompTarget; + IDXGIDevice *pDXGIDevice; + ID3D11Query *pQueries[NUM_QUERIES]; + int current_query; + + // ANGLE interfaces that wrap the D3D device + EGLDeviceEXT EGLDevice; + EGLDisplay EGLDisplay; + EGLContext EGLContext; + EGLConfig config; + // Framebuffer surface for debug mode when we are not using DC + EGLSurface fb_surface; + + // The currently bound surface, valid during bind() and unbind() + IDCompositionSurface *pCurrentSurface; + EGLImage mEGLImage; + GLuint mColorRBO; + + // The root of the DC visual tree. Nothing is drawn on this, but + // all child tiles are parented to here. + IDCompositionVisual2 *pRoot; + IDCompositionVisualDebug *pVisualDebug; + std::vector<CachedFrameBuffer> mFrameBuffers; + + // Maintain list of layer state between frames to avoid visual tree rebuild. + std::vector<uint64_t> mCurrentLayers; + std::vector<uint64_t> mPrevLayers; + + // Maps WR surface IDs to each OS surface + std::unordered_map<uint64_t, Surface> surfaces; }; -static const wchar_t* CLASS_NAME = L"WR DirectComposite"; +static const wchar_t *CLASS_NAME = L"WR DirectComposite"; -static GLuint GetOrCreateFbo(Window* window, int aWidth, int aHeight) { - GLuint fboId = 0; +static GLuint GetOrCreateFbo(Window *window, int aWidth, int aHeight) { + GLuint fboId = 0; - // Check if we have a cached FBO with matching dimensions - for (auto it = window->mFrameBuffers.begin(); - it != window->mFrameBuffers.end(); ++it) { - if (it->width == aWidth && it->height == aHeight) { - fboId = it->fboId; - break; + // Check if we have a cached FBO with matching dimensions + for (auto it = window->mFrameBuffers.begin(); it != window->mFrameBuffers.end(); ++it) { + if (it->width == aWidth && it->height == aHeight) { + fboId = it->fboId; + break; + } } - } - // If not, create a new FBO with attached depth buffer - if (fboId == 0) { - // Create the depth buffer - GLuint depthRboId; - glGenRenderbuffers(1, &depthRboId); - glBindRenderbuffer(GL_RENDERBUFFER, depthRboId); - glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, aWidth, - aHeight); - - // Create the framebuffer and attach the depth buffer to it - glGenFramebuffers(1, &fboId); - glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fboId); - glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, - GL_RENDERBUFFER, depthRboId); - - // Store this in the cache for future calls. - CachedFrameBuffer frame_buffer_info; - frame_buffer_info.width = aWidth; - frame_buffer_info.height = aHeight; - frame_buffer_info.fboId = fboId; - frame_buffer_info.depthRboId = depthRboId; - window->mFrameBuffers.push_back(frame_buffer_info); - } - - return fboId; + // If not, create a new FBO with attached depth buffer + if (fboId == 0) { + // Create the depth buffer + GLuint depthRboId; + glGenRenderbuffers(1, &depthRboId); + glBindRenderbuffer(GL_RENDERBUFFER, depthRboId); + glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, + aWidth, aHeight); + + // Create the framebuffer and attach the depth buffer to it + glGenFramebuffers(1, &fboId); + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fboId); + glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, + GL_DEPTH_ATTACHMENT, + GL_RENDERBUFFER, depthRboId); + + // Store this in the cache for future calls. + CachedFrameBuffer frame_buffer_info; + frame_buffer_info.width = aWidth; + frame_buffer_info.height = aHeight; + frame_buffer_info.fboId = fboId; + frame_buffer_info.depthRboId = depthRboId; + window->mFrameBuffers.push_back(frame_buffer_info); + } + + return fboId; } -static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, - LPARAM lParam) { - switch (message) { - case WM_DESTROY: - PostQuitMessage(0); - return 1; - } +static LRESULT CALLBACK WndProc( + HWND hwnd, + UINT message, + WPARAM wParam, + LPARAM lParam +) { + switch (message) { + case WM_DESTROY: + PostQuitMessage(0); + return 1; + } - return DefWindowProc(hwnd, message, wParam, lParam); + return DefWindowProc(hwnd, message, wParam, lParam); } extern "C" { -Window* com_dc_create_window(int width, int height, bool enable_compositor, - SyncMode sync_mode) { - // Create a simple Win32 window - Window* window = new Window; - window->hInstance = GetModuleHandle(NULL); - window->enable_compositor = enable_compositor; - window->mEGLImage = EGL_NO_IMAGE; - window->sync_mode = sync_mode; - - WNDCLASSEX wcex = {sizeof(WNDCLASSEX)}; - wcex.style = CS_HREDRAW | CS_VREDRAW; - wcex.lpfnWndProc = WndProc; - wcex.cbClsExtra = 0; - wcex.cbWndExtra = 0; - wcex.hInstance = window->hInstance; - wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); - ; - wcex.lpszMenuName = nullptr; - wcex.hCursor = LoadCursor(NULL, IDC_ARROW); - wcex.lpszClassName = CLASS_NAME; - RegisterClassEx(&wcex); - - int dpiX = 0; - int dpiY = 0; - HDC hdc = GetDC(NULL); - if (hdc) { - dpiX = GetDeviceCaps(hdc, LOGPIXELSX); - dpiY = GetDeviceCaps(hdc, LOGPIXELSY); - ReleaseDC(NULL, hdc); - } - - RECT window_rect = {0, 0, width, height}; - AdjustWindowRect(&window_rect, WS_OVERLAPPEDWINDOW, FALSE); - UINT window_width = static_cast<UINT>( - ceil(float(window_rect.right - window_rect.left) * dpiX / 96.f)); - UINT window_height = static_cast<UINT>( - ceil(float(window_rect.bottom - window_rect.top) * dpiY / 96.f)); - - LPCWSTR name; - DWORD style; - if (enable_compositor) { - name = L"example-compositor (DirectComposition)"; - style = WS_EX_NOREDIRECTIONBITMAP; - } else { - name = L"example-compositor (Simple)"; - style = 0; - } - - window->hWnd = - CreateWindowEx(style, CLASS_NAME, name, WS_OVERLAPPEDWINDOW, - CW_USEDEFAULT, CW_USEDEFAULT, window_width, window_height, - NULL, NULL, window->hInstance, NULL); - - ShowWindow(window->hWnd, SW_SHOWNORMAL); - UpdateWindow(window->hWnd); - GetClientRect(window->hWnd, &window->client_rect); - - // Create a D3D11 device - D3D_FEATURE_LEVEL featureLevelSupported; - HRESULT hr = D3D11CreateDevice(nullptr, D3D_DRIVER_TYPE_HARDWARE, NULL, - D3D11_CREATE_DEVICE_BGRA_SUPPORT, NULL, 0, - D3D11_SDK_VERSION, &window->pD3D11Device, - &featureLevelSupported, nullptr); - assert(SUCCEEDED(hr)); - - D3D11_QUERY_DESC query_desc; - memset(&query_desc, 0, sizeof(query_desc)); - query_desc.Query = D3D11_QUERY_EVENT; - for (int i = 0; i < NUM_QUERIES; ++i) { - hr = window->pD3D11Device->CreateQuery(&query_desc, &window->pQueries[i]); - assert(SUCCEEDED(hr)); - } - window->current_query = 0; - - hr = window->pD3D11Device->QueryInterface(&window->pDXGIDevice); - assert(SUCCEEDED(hr)); - - // Create a DirectComposition device - hr = DCompositionCreateDevice2(window->pDXGIDevice, - __uuidof(IDCompositionDesktopDevice), - (void**)&window->pDCompDevice); - assert(SUCCEEDED(hr)); - - // Create a DirectComposition target for a Win32 window handle - hr = window->pDCompDevice->CreateTargetForHwnd(window->hWnd, TRUE, - &window->pDCompTarget); - assert(SUCCEEDED(hr)); - - // Create an ANGLE EGL device that wraps D3D11 - window->EGLDevice = eglCreateDeviceANGLE(EGL_D3D11_DEVICE_ANGLE, - window->pD3D11Device, nullptr); - - EGLint display_attribs[] = {EGL_NONE}; - - window->EGLDisplay = eglGetPlatformDisplayEXT( - EGL_PLATFORM_DEVICE_EXT, window->EGLDevice, display_attribs); - - eglInitialize(window->EGLDisplay, nullptr, nullptr); - - EGLint num_configs = 0; - EGLint cfg_attribs[] = {EGL_SURFACE_TYPE, - EGL_WINDOW_BIT, - EGL_RENDERABLE_TYPE, - EGL_OPENGL_ES2_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]; - - if (window->enable_compositor) { - window->fb_surface = EGL_NO_SURFACE; - } else { - window->fb_surface = eglCreateWindowSurface( - window->EGLDisplay, window->config, window->hWnd, NULL); - assert(window->fb_surface != EGL_NO_SURFACE); - } - - EGLint ctx_attribs[] = {EGL_CONTEXT_CLIENT_VERSION, 3, EGL_NONE}; - - // Create an EGL context that can be used for drawing - window->EGLContext = eglCreateContext(window->EGLDisplay, window->config, - EGL_NO_CONTEXT, ctx_attribs); - - // Create the root of the DirectComposition visual tree - hr = window->pDCompDevice->CreateVisual(&window->pRoot); - assert(SUCCEEDED(hr)); - hr = window->pDCompTarget->SetRoot(window->pRoot); - assert(SUCCEEDED(hr)); - - hr = window->pRoot->QueryInterface(__uuidof(IDCompositionVisualDebug), - (void**)&window->pVisualDebug); - assert(SUCCEEDED(hr)); - - // Uncomment this to see redraw regions during composite - // window->pVisualDebug->EnableRedrawRegions(); - - EGLBoolean ok = eglMakeCurrent(window->EGLDisplay, window->fb_surface, - window->fb_surface, window->EGLContext); - assert(ok); - - return window; -} + Window *com_dc_create_window(int width, int height, bool enable_compositor, SyncMode sync_mode) { + // Create a simple Win32 window + Window *window = new Window; + window->hInstance = GetModuleHandle(NULL); + window->enable_compositor = enable_compositor; + window->mEGLImage = EGL_NO_IMAGE; + window->sync_mode = sync_mode; + + WNDCLASSEX wcex = { sizeof(WNDCLASSEX) }; + wcex.style = CS_HREDRAW | CS_VREDRAW; + wcex.lpfnWndProc = WndProc; + wcex.cbClsExtra = 0; + wcex.cbWndExtra = 0; + wcex.hInstance = window->hInstance; + wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);; + wcex.lpszMenuName = nullptr; + wcex.hCursor = LoadCursor(NULL, IDC_ARROW); + wcex.lpszClassName = CLASS_NAME; + RegisterClassEx(&wcex); + + int dpiX = 0; + int dpiY = 0; + HDC hdc = GetDC(NULL); + if (hdc) { + dpiX = GetDeviceCaps(hdc, LOGPIXELSX); + dpiY = GetDeviceCaps(hdc, LOGPIXELSY); + ReleaseDC(NULL, hdc); + } + + RECT window_rect = { 0, 0, width, height }; + AdjustWindowRect(&window_rect, WS_OVERLAPPEDWINDOW, FALSE); + UINT window_width = static_cast<UINT>(ceil(float(window_rect.right - window_rect.left) * dpiX / 96.f)); + UINT window_height = static_cast<UINT>(ceil(float(window_rect.bottom - window_rect.top) * dpiY / 96.f)); + + LPCWSTR name; + DWORD style; + if (enable_compositor) { + name = L"example-compositor (DirectComposition)"; + style = WS_EX_NOREDIRECTIONBITMAP; + } else { + name = L"example-compositor (Simple)"; + style = 0; + } + + window->hWnd = CreateWindowEx( + style, + CLASS_NAME, + name, + WS_OVERLAPPEDWINDOW, + CW_USEDEFAULT, + CW_USEDEFAULT, + window_width, + window_height, + NULL, + NULL, + window->hInstance, + NULL + ); + + ShowWindow(window->hWnd, SW_SHOWNORMAL); + UpdateWindow(window->hWnd); + GetClientRect(window->hWnd, &window->client_rect); + + // Create a D3D11 device + D3D_FEATURE_LEVEL featureLevelSupported; + HRESULT hr = D3D11CreateDevice( + nullptr, + D3D_DRIVER_TYPE_HARDWARE, + NULL, + D3D11_CREATE_DEVICE_BGRA_SUPPORT, + NULL, + 0, + D3D11_SDK_VERSION, + &window->pD3D11Device, + &featureLevelSupported, + nullptr + ); + assert(SUCCEEDED(hr)); + + D3D11_QUERY_DESC query_desc; + memset(&query_desc, 0, sizeof(query_desc)); + query_desc.Query = D3D11_QUERY_EVENT; + for (int i=0 ; i < NUM_QUERIES ; ++i) { + hr = window->pD3D11Device->CreateQuery(&query_desc, &window->pQueries[i]); + assert(SUCCEEDED(hr)); + } + window->current_query = 0; + + hr = window->pD3D11Device->QueryInterface(&window->pDXGIDevice); + assert(SUCCEEDED(hr)); + + // Create a DirectComposition device + hr = DCompositionCreateDevice2( + window->pDXGIDevice, + __uuidof(IDCompositionDesktopDevice), + (void **) &window->pDCompDevice + ); + assert(SUCCEEDED(hr)); + + // Create a DirectComposition target for a Win32 window handle + hr = window->pDCompDevice->CreateTargetForHwnd( + window->hWnd, + TRUE, + &window->pDCompTarget + ); + assert(SUCCEEDED(hr)); + + // Create an ANGLE EGL device that wraps D3D11 + window->EGLDevice = eglCreateDeviceANGLE( + EGL_D3D11_DEVICE_ANGLE, + window->pD3D11Device, + nullptr + ); + + EGLint display_attribs[] = { + EGL_NONE + }; + + window->EGLDisplay = eglGetPlatformDisplayEXT( + EGL_PLATFORM_DEVICE_EXT, + window->EGLDevice, + display_attribs + ); + + eglInitialize( + window->EGLDisplay, + nullptr, + nullptr + ); + + EGLint num_configs = 0; + EGLint cfg_attribs[] = { + EGL_SURFACE_TYPE, EGL_WINDOW_BIT, + EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_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]; + + if (window->enable_compositor) { + window->fb_surface = EGL_NO_SURFACE; + } else { + window->fb_surface = eglCreateWindowSurface( + window->EGLDisplay, + window->config, + window->hWnd, + NULL + ); + assert(window->fb_surface != EGL_NO_SURFACE); + } + + EGLint ctx_attribs[] = { + EGL_CONTEXT_CLIENT_VERSION, 3, + EGL_NONE + }; + + // Create an EGL context that can be used for drawing + window->EGLContext = eglCreateContext( + window->EGLDisplay, + window->config, + EGL_NO_CONTEXT, + ctx_attribs + ); + + // Create the root of the DirectComposition visual tree + hr = window->pDCompDevice->CreateVisual(&window->pRoot); + assert(SUCCEEDED(hr)); + hr = window->pDCompTarget->SetRoot(window->pRoot); + assert(SUCCEEDED(hr)); + + hr = window->pRoot->QueryInterface( + __uuidof(IDCompositionVisualDebug), + (void **) &window->pVisualDebug + ); + assert(SUCCEEDED(hr)); + + // Uncomment this to see redraw regions during composite + // window->pVisualDebug->EnableRedrawRegions(); + + EGLBoolean ok = eglMakeCurrent( + window->EGLDisplay, + window->fb_surface, + window->fb_surface, + window->EGLContext + ); + assert(ok); + + return window; + } -void com_dc_destroy_window(Window* window) { - for (auto surface_it = window->surfaces.begin(); - surface_it != window->surfaces.end(); ++surface_it) { - Surface& surface = surface_it->second; + void com_dc_destroy_window(Window *window) { + for (auto surface_it=window->surfaces.begin() ; surface_it != window->surfaces.end() ; ++surface_it) { + Surface &surface = surface_it->second; #ifndef USE_VIRTUAL_SURFACES - for (auto tile_it = surface.tiles.begin(); tile_it != surface.tiles.end(); - ++tile_it) { - tile_it->second.pSurface->Release(); - tile_it->second.pVisual->Release(); - } + for (auto tile_it=surface.tiles.begin() ; tile_it != surface.tiles.end() ; ++tile_it) { + tile_it->second.pSurface->Release(); + tile_it->second.pVisual->Release(); + } #endif - surface.pVisual->Release(); - } - - if (window->fb_surface != EGL_NO_SURFACE) { - eglDestroySurface(window->EGLDisplay, window->fb_surface); - } - eglDestroyContext(window->EGLDisplay, window->EGLContext); - eglTerminate(window->EGLDisplay); - eglReleaseDeviceANGLE(window->EGLDevice); - - for (int i = 0; i < NUM_QUERIES; ++i) { - window->pQueries[i]->Release(); - } - window->pRoot->Release(); - window->pVisualDebug->Release(); - window->pD3D11Device->Release(); - window->pDXGIDevice->Release(); - window->pDCompDevice->Release(); - window->pDCompTarget->Release(); - - CloseWindow(window->hWnd); - UnregisterClass(CLASS_NAME, window->hInstance); - - delete window; -} - -bool com_dc_tick(Window*) { - // Check and dispatch the windows event loop - MSG msg; - while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { - if (msg.message == WM_QUIT) { - return false; + surface.pVisual->Release(); + } + + if (window->fb_surface != EGL_NO_SURFACE) { + eglDestroySurface(window->EGLDisplay, window->fb_surface); + } + eglDestroyContext(window->EGLDisplay, window->EGLContext); + eglTerminate(window->EGLDisplay); + eglReleaseDeviceANGLE(window->EGLDevice); + + for (int i=0 ; i < NUM_QUERIES ; ++i) { + window->pQueries[i]->Release(); + } + window->pRoot->Release(); + window->pVisualDebug->Release(); + window->pD3D11Device->Release(); + window->pDXGIDevice->Release(); + window->pDCompDevice->Release(); + window->pDCompTarget->Release(); + + CloseWindow(window->hWnd); + UnregisterClass(CLASS_NAME, window->hInstance); + + delete window; } - TranslateMessage(&msg); - DispatchMessage(&msg); - } + bool com_dc_tick(Window *) { + // Check and dispatch the windows event loop + MSG msg; + while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { + if (msg.message == WM_QUIT) { + return false; + } - return true; -} + TranslateMessage(&msg); + DispatchMessage(&msg); + } -void com_dc_swap_buffers(Window* window) { - // If not using DC mode, then do a normal EGL swap buffers. - if (window->fb_surface != EGL_NO_SURFACE) { - switch (window->sync_mode) { - case SyncMode::None: - eglSwapInterval(window->EGLDisplay, 0); - break; - case SyncMode::Swap: - eglSwapInterval(window->EGLDisplay, 1); - break; - default: - assert(false); // unexpected vsync mode for simple compositor. - break; + return true; } - eglSwapBuffers(window->EGLDisplay, window->fb_surface); - } else { - switch (window->sync_mode) { - case SyncMode::None: - break; - case SyncMode::Commit: - window->pDCompDevice->WaitForCommitCompletion(); - break; - case SyncMode::Flush: - DwmFlush(); - break; - case SyncMode::Query: - // todo!!!! - break; - default: - assert(false); // unexpected vsync mode for native compositor - break; + void com_dc_swap_buffers(Window *window) { + // If not using DC mode, then do a normal EGL swap buffers. + if (window->fb_surface != EGL_NO_SURFACE) { + switch (window->sync_mode) { + case SyncMode::None: + eglSwapInterval(window->EGLDisplay, 0); + break; + case SyncMode::Swap: + eglSwapInterval(window->EGLDisplay, 1); + break; + default: + assert(false); // unexpected vsync mode for simple compositor. + break; + } + + eglSwapBuffers(window->EGLDisplay, window->fb_surface); + } else { + switch (window->sync_mode) { + case SyncMode::None: + break; + case SyncMode::Commit: + window->pDCompDevice->WaitForCommitCompletion(); + break; + case SyncMode::Flush: + DwmFlush(); + break; + case SyncMode::Query: + // todo!!!! + break; + default: + assert(false); // unexpected vsync mode for native compositor + break; + } + } } - } -} - -// Create a new DC surface -void com_dc_create_surface(Window* window, uint64_t id, int tile_width, - int tile_height, bool is_opaque) { - assert(window->surfaces.count(id) == 0); - Surface surface; - surface.tile_width = tile_width; - surface.tile_height = tile_height; - surface.is_opaque = is_opaque; - - // Create the visual node in the DC tree that stores properties - HRESULT hr = window->pDCompDevice->CreateVisual(&surface.pVisual); - assert(SUCCEEDED(hr)); + // Create a new DC surface + void com_dc_create_surface( + Window *window, + uint64_t id, + int tile_width, + int tile_height, + bool is_opaque + ) { + assert(window->surfaces.count(id) == 0); + + Surface surface; + surface.tile_width = tile_width; + surface.tile_height = tile_height; + surface.is_opaque = is_opaque; + + // Create the visual node in the DC tree that stores properties + HRESULT hr = window->pDCompDevice->CreateVisual(&surface.pVisual); + assert(SUCCEEDED(hr)); #ifdef USE_VIRTUAL_SURFACES - DXGI_ALPHA_MODE alpha_mode = surface.is_opaque - ? DXGI_ALPHA_MODE_IGNORE - : DXGI_ALPHA_MODE_PREMULTIPLIED; - - hr = window->pDCompDevice->CreateVirtualSurface( - VIRTUAL_OFFSET * 2, VIRTUAL_OFFSET * 2, DXGI_FORMAT_B8G8R8A8_UNORM, - alpha_mode, &surface.pVirtualSurface); - assert(SUCCEEDED(hr)); - - // Bind the surface memory to this visual - hr = surface.pVisual->SetContent(surface.pVirtualSurface); - assert(SUCCEEDED(hr)); + DXGI_ALPHA_MODE alpha_mode = surface.is_opaque ? DXGI_ALPHA_MODE_IGNORE : DXGI_ALPHA_MODE_PREMULTIPLIED; + + hr = window->pDCompDevice->CreateVirtualSurface( + VIRTUAL_OFFSET * 2, + VIRTUAL_OFFSET * 2, + DXGI_FORMAT_B8G8R8A8_UNORM, + alpha_mode, + &surface.pVirtualSurface + ); + assert(SUCCEEDED(hr)); + + // Bind the surface memory to this visual + hr = surface.pVisual->SetContent(surface.pVirtualSurface); + assert(SUCCEEDED(hr)); #endif - window->surfaces[id] = surface; -} + window->surfaces[id] = surface; + } -void com_dc_create_tile(Window* window, uint64_t id, int x, int y) { - assert(window->surfaces.count(id) == 1); - Surface& surface = window->surfaces[id]; + void com_dc_create_tile( + Window *window, + uint64_t id, + int x, + int y + ) { + assert(window->surfaces.count(id) == 1); + Surface &surface = window->surfaces[id]; - TileKey key(x, y); - assert(surface.tiles.count(key) == 0); + TileKey key(x, y); + assert(surface.tiles.count(key) == 0); - Tile tile; + Tile tile; #ifndef USE_VIRTUAL_SURFACES - // Create the video memory surface. - DXGI_ALPHA_MODE alpha_mode = surface.is_opaque - ? DXGI_ALPHA_MODE_IGNORE - : DXGI_ALPHA_MODE_PREMULTIPLIED; - HRESULT hr = window->pDCompDevice->CreateSurface( - surface.tile_width, surface.tile_height, DXGI_FORMAT_B8G8R8A8_UNORM, - alpha_mode, &tile.pSurface); - assert(SUCCEEDED(hr)); - - // Create the visual node in the DC tree that stores properties - hr = window->pDCompDevice->CreateVisual(&tile.pVisual); - assert(SUCCEEDED(hr)); - - // Bind the surface memory to this visual - hr = tile.pVisual->SetContent(tile.pSurface); - assert(SUCCEEDED(hr)); - - // Place the visual in local-space of this surface - float offset_x = (float)(x * surface.tile_width); - float offset_y = (float)(y * surface.tile_height); - tile.pVisual->SetOffsetX(offset_x); - tile.pVisual->SetOffsetY(offset_y); - - surface.pVisual->AddVisual(tile.pVisual, FALSE, NULL); + // Create the video memory surface. + DXGI_ALPHA_MODE alpha_mode = surface.is_opaque ? DXGI_ALPHA_MODE_IGNORE : DXGI_ALPHA_MODE_PREMULTIPLIED; + HRESULT hr = window->pDCompDevice->CreateSurface( + surface.tile_width, + surface.tile_height, + DXGI_FORMAT_B8G8R8A8_UNORM, + alpha_mode, + &tile.pSurface + ); + assert(SUCCEEDED(hr)); + + // Create the visual node in the DC tree that stores properties + hr = window->pDCompDevice->CreateVisual(&tile.pVisual); + assert(SUCCEEDED(hr)); + + // Bind the surface memory to this visual + hr = tile.pVisual->SetContent(tile.pSurface); + assert(SUCCEEDED(hr)); + + // Place the visual in local-space of this surface + float offset_x = (float) (x * surface.tile_width); + float offset_y = (float) (y * surface.tile_height); + tile.pVisual->SetOffsetX(offset_x); + tile.pVisual->SetOffsetY(offset_y); + + surface.pVisual->AddVisual( + tile.pVisual, + FALSE, + NULL + ); #endif - surface.tiles[key] = tile; -} + surface.tiles[key] = tile; + } -void com_dc_destroy_tile(Window* window, uint64_t id, int x, int y) { - assert(window->surfaces.count(id) == 1); - Surface& surface = window->surfaces[id]; + void com_dc_destroy_tile( + Window *window, + uint64_t id, + int x, + int y + ) { + assert(window->surfaces.count(id) == 1); + Surface &surface = window->surfaces[id]; - TileKey key(x, y); - assert(surface.tiles.count(key) == 1); - Tile& tile = surface.tiles[key]; + TileKey key(x, y); + assert(surface.tiles.count(key) == 1); + Tile &tile = surface.tiles[key]; #ifndef USE_VIRTUAL_SURFACES - surface.pVisual->RemoveVisual(tile.pVisual); + surface.pVisual->RemoveVisual(tile.pVisual); - tile.pVisual->Release(); - tile.pSurface->Release(); + tile.pVisual->Release(); + tile.pSurface->Release(); #endif - surface.tiles.erase(key); -} + surface.tiles.erase(key); + } -void com_dc_destroy_surface(Window* window, uint64_t id) { - assert(window->surfaces.count(id) == 1); - Surface& surface = window->surfaces[id]; + void com_dc_destroy_surface( + Window *window, + uint64_t id + ) { + assert(window->surfaces.count(id) == 1); + Surface &surface = window->surfaces[id]; - window->pRoot->RemoveVisual(surface.pVisual); + window->pRoot->RemoveVisual(surface.pVisual); #ifdef USE_VIRTUAL_SURFACES - surface.pVirtualSurface->Release(); + surface.pVirtualSurface->Release(); #else - // Release the video memory and visual in the tree - for (auto tile_it = surface.tiles.begin(); tile_it != surface.tiles.end(); - ++tile_it) { - tile_it->second.pSurface->Release(); - tile_it->second.pVisual->Release(); - } + // Release the video memory and visual in the tree + for (auto tile_it=surface.tiles.begin() ; tile_it != surface.tiles.end() ; ++tile_it) { + tile_it->second.pSurface->Release(); + tile_it->second.pVisual->Release(); + } #endif - surface.pVisual->Release(); - window->surfaces.erase(id); -} + surface.pVisual->Release(); + window->surfaces.erase(id); + } -// Bind a DC surface to allow issuing GL commands to it -GLuint com_dc_bind_surface(Window* 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) { - 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]; - - // Inform DC that we want to draw on this surface. DC uses texture - // atlases when the tiles are small. It returns an offset where the - // client code must draw into this surface when this happens. - RECT update_rect; - update_rect.left = dirty_x0; - update_rect.top = dirty_y0; - update_rect.right = dirty_x0 + dirty_width; - update_rect.bottom = dirty_y0 + dirty_height; - POINT offset; - D3D11_TEXTURE2D_DESC desc; - ID3D11Texture2D* pTexture; - HRESULT hr; - - // Store the current surface for unbinding later + // Bind a DC surface to allow issuing GL commands to it + GLuint com_dc_bind_surface( + Window *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 + ) { + 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]; + + // Inform DC that we want to draw on this surface. DC uses texture + // atlases when the tiles are small. It returns an offset where the + // client code must draw into this surface when this happens. + RECT update_rect; + update_rect.left = dirty_x0; + update_rect.top = dirty_y0; + update_rect.right = dirty_x0 + dirty_width; + update_rect.bottom = dirty_y0 + dirty_height; + POINT offset; + D3D11_TEXTURE2D_DESC desc; + ID3D11Texture2D *pTexture; + HRESULT hr; + + // Store the current surface for unbinding later #ifdef USE_VIRTUAL_SURFACES - LONG tile_offset_x = VIRTUAL_OFFSET + tile_x * surface.tile_width; - LONG tile_offset_y = VIRTUAL_OFFSET + tile_y * surface.tile_height; - - update_rect.left += tile_offset_x; - update_rect.top += tile_offset_y; - update_rect.right += tile_offset_x; - update_rect.bottom += tile_offset_y; - - hr = surface.pVirtualSurface->BeginDraw( - &update_rect, __uuidof(ID3D11Texture2D), (void**)&pTexture, &offset); - window->pCurrentSurface = surface.pVirtualSurface; + LONG tile_offset_x = VIRTUAL_OFFSET + tile_x * surface.tile_width; + LONG tile_offset_y = VIRTUAL_OFFSET + tile_y * surface.tile_height; + + update_rect.left += tile_offset_x; + update_rect.top += tile_offset_y; + update_rect.right += tile_offset_x; + update_rect.bottom += tile_offset_y; + + hr = surface.pVirtualSurface->BeginDraw( + &update_rect, + __uuidof(ID3D11Texture2D), + (void **) &pTexture, + &offset + ); + window->pCurrentSurface = surface.pVirtualSurface; #else - hr = tile.pSurface->BeginDraw(&update_rect, __uuidof(ID3D11Texture2D), - (void**)&pTexture, &offset); - window->pCurrentSurface = tile.pSurface; + hr = tile.pSurface->BeginDraw( + &update_rect, + __uuidof(ID3D11Texture2D), + (void **) &pTexture, + &offset + ); + window->pCurrentSurface = tile.pSurface; #endif - // DC includes the origin of the dirty / update rect in the draw offset, - // undo that here since WR expects it to be an absolute offset. - assert(SUCCEEDED(hr)); - offset.x -= dirty_x0; - offset.y -= dirty_y0; - pTexture->GetDesc(&desc); - *x_offset = offset.x; - *y_offset = offset.y; - - // Construct an EGLImage wrapper around the D3D texture for ANGLE. - const EGLAttrib attribs[] = {EGL_NONE}; - window->mEGLImage = eglCreateImage( - window->EGLDisplay, EGL_NO_CONTEXT, EGL_D3D11_TEXTURE_ANGLE, - static_cast<EGLClientBuffer>(pTexture), attribs); - - // Get the current FBO and RBO id, so we can restore them later - GLint currentFboId, currentRboId; - glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, ¤tFboId); - glGetIntegerv(GL_RENDERBUFFER_BINDING, ¤tRboId); - - // Create a render buffer object that is backed by the EGL image. - glGenRenderbuffers(1, &window->mColorRBO); - glBindRenderbuffer(GL_RENDERBUFFER, window->mColorRBO); - glEGLImageTargetRenderbufferStorageOES(GL_RENDERBUFFER, window->mEGLImage); - - // Get or create an FBO for the specified dimensions - GLuint fboId = GetOrCreateFbo(window, desc.Width, desc.Height); - - // Attach the new renderbuffer to the FBO - glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fboId); - glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, - GL_RENDERBUFFER, window->mColorRBO); - - // Restore previous FBO and RBO bindings - glBindFramebuffer(GL_DRAW_FRAMEBUFFER, currentFboId); - glBindRenderbuffer(GL_RENDERBUFFER, currentRboId); - - return fboId; -} - -// Unbind a currently bound DC surface -void com_dc_unbind_surface(Window* window) { - HRESULT hr = window->pCurrentSurface->EndDraw(); - assert(SUCCEEDED(hr)); + // DC includes the origin of the dirty / update rect in the draw offset, + // undo that here since WR expects it to be an absolute offset. + assert(SUCCEEDED(hr)); + offset.x -= dirty_x0; + offset.y -= dirty_y0; + pTexture->GetDesc(&desc); + *x_offset = offset.x; + *y_offset = offset.y; + + // Construct an EGLImage wrapper around the D3D texture for ANGLE. + const EGLAttrib attribs[] = { EGL_NONE }; + window->mEGLImage = eglCreateImage( + window->EGLDisplay, + EGL_NO_CONTEXT, + EGL_D3D11_TEXTURE_ANGLE, + static_cast<EGLClientBuffer>(pTexture), + attribs + ); + + // Get the current FBO and RBO id, so we can restore them later + GLint currentFboId, currentRboId; + glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, ¤tFboId); + glGetIntegerv(GL_RENDERBUFFER_BINDING, ¤tRboId); + + // Create a render buffer object that is backed by the EGL image. + glGenRenderbuffers(1, &window->mColorRBO); + glBindRenderbuffer(GL_RENDERBUFFER, window->mColorRBO); + glEGLImageTargetRenderbufferStorageOES(GL_RENDERBUFFER, window->mEGLImage); + + // Get or create an FBO for the specified dimensions + GLuint fboId = GetOrCreateFbo(window, desc.Width, desc.Height); + + // Attach the new renderbuffer to the FBO + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fboId); + glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, + GL_COLOR_ATTACHMENT0, + GL_RENDERBUFFER, + window->mColorRBO); + + // Restore previous FBO and RBO bindings + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, currentFboId); + glBindRenderbuffer(GL_RENDERBUFFER, currentRboId); + + return fboId; + } - glDeleteRenderbuffers(1, &window->mColorRBO); - window->mColorRBO = 0; + // Unbind a currently bound DC surface + void com_dc_unbind_surface(Window *window) { + HRESULT hr = window->pCurrentSurface->EndDraw(); + assert(SUCCEEDED(hr)); - eglDestroyImage(window->EGLDisplay, window->mEGLImage); - window->mEGLImage = EGL_NO_IMAGE; -} + glDeleteRenderbuffers(1, &window->mColorRBO); + window->mColorRBO = 0; -void com_dc_begin_transaction(Window*) {} + eglDestroyImage(window->EGLDisplay, window->mEGLImage); + window->mEGLImage = EGL_NO_IMAGE; + } -// Add a DC surface to the visual tree. Called per-frame to build the -// composition. -void com_dc_add_surface(Window* window, uint64_t id, int x, int y, int clip_x, - int clip_y, int clip_w, int clip_h) { - Surface surface = window->surfaces[id]; - window->mCurrentLayers.push_back(id); + void com_dc_begin_transaction(Window *) { + } - // Place the visual - this changes frame to frame based on scroll position - // of the slice. - float offset_x = (float)(x + window->client_rect.left); - float offset_y = (float)(y + window->client_rect.top); + // Add a DC surface to the visual tree. Called per-frame to build the composition. + void com_dc_add_surface( + Window *window, + uint64_t id, + int x, + int y, + int clip_x, + int clip_y, + int clip_w, + int clip_h + ) { + Surface surface = window->surfaces[id]; + window->mCurrentLayers.push_back(id); + + // Place the visual - this changes frame to frame based on scroll position + // of the slice. + float offset_x = (float) (x + window->client_rect.left); + float offset_y = (float) (y + window->client_rect.top); #ifdef USE_VIRTUAL_SURFACES - offset_x -= VIRTUAL_OFFSET; - offset_y -= VIRTUAL_OFFSET; + offset_x -= VIRTUAL_OFFSET; + offset_y -= VIRTUAL_OFFSET; #endif - surface.pVisual->SetOffsetX(offset_x); - surface.pVisual->SetOffsetY(offset_y); - - // Set the clip rect - converting from world space to the pre-offset space - // that DC requires for rectangle clips. - D2D_RECT_F clip_rect; - clip_rect.left = clip_x - offset_x; - clip_rect.top = clip_y - offset_y; - clip_rect.right = clip_rect.left + clip_w; - clip_rect.bottom = clip_rect.top + clip_h; - surface.pVisual->SetClip(clip_rect); -} - -// Finish the composition transaction, telling DC to composite -void com_dc_end_transaction(Window* window) { - bool same = window->mPrevLayers == window->mCurrentLayers; - - if (!same) { - HRESULT hr = window->pRoot->RemoveAllVisuals(); - assert(SUCCEEDED(hr)); - - for (auto it = window->mCurrentLayers.begin(); - it != window->mCurrentLayers.end(); ++it) { - Surface& surface = window->surfaces[*it]; - - // Add this visual as the last element in the visual tree (z-order is - // implicit, based on the order tiles are added). - hr = window->pRoot->AddVisual(surface.pVisual, FALSE, NULL); - assert(SUCCEEDED(hr)); + surface.pVisual->SetOffsetX(offset_x); + surface.pVisual->SetOffsetY(offset_y); + + // Set the clip rect - converting from world space to the pre-offset space + // that DC requires for rectangle clips. + D2D_RECT_F clip_rect; + clip_rect.left = clip_x - offset_x; + clip_rect.top = clip_y - offset_y; + clip_rect.right = clip_rect.left + clip_w; + clip_rect.bottom = clip_rect.top + clip_h; + surface.pVisual->SetClip(clip_rect); } - } - window->mPrevLayers.swap(window->mCurrentLayers); - window->mCurrentLayers.clear(); - - HRESULT hr = window->pDCompDevice->Commit(); - assert(SUCCEEDED(hr)); -} + // Finish the composition transaction, telling DC to composite + void com_dc_end_transaction(Window *window) { + bool same = window->mPrevLayers == window->mCurrentLayers; + + if (!same) { + HRESULT hr = window->pRoot->RemoveAllVisuals(); + assert(SUCCEEDED(hr)); + + for (auto it = window->mCurrentLayers.begin(); it != window->mCurrentLayers.end(); ++it) { + Surface &surface = window->surfaces[*it]; + + // Add this visual as the last element in the visual tree (z-order is implicit, + // based on the order tiles are added). + hr = window->pRoot->AddVisual( + surface.pVisual, + FALSE, + NULL + ); + assert(SUCCEEDED(hr)); + } + } + + window->mPrevLayers.swap(window->mCurrentLayers); + window->mCurrentLayers.clear(); + + HRESULT hr = window->pDCompDevice->Commit(); + assert(SUCCEEDED(hr)); + } -// Get a pointer to an EGL symbol -void* com_dc_get_proc_address(const char* name) { - return eglGetProcAddress(name); -} + // Get a pointer to an EGL symbol + void *com_dc_get_proc_address(const char *name) { + return eglGetProcAddress(name); + } } diff --git a/third_party/webrender/example-compositor/compositor-windows/src/lib.rs b/third_party/webrender/example-compositor/compositor-windows/src/lib.rs index df15b0348ab..18b80b5d1e9 100644 --- a/third_party/webrender/example-compositor/compositor-windows/src/lib.rs +++ b/third_party/webrender/example-compositor/compositor-windows/src/lib.rs @@ -88,8 +88,6 @@ extern { ); fn com_dc_end_transaction(window: *mut Window); - - fn deinit(window: *mut Window); } pub fn create_window( @@ -261,7 +259,3 @@ pub fn swap_buffers(window: *mut Window) { com_dc_swap_buffers(window); } } - -pub fn deinit(window: *mut Window) { - todo!() -} diff --git a/third_party/webrender/example-compositor/compositor/Cargo.toml b/third_party/webrender/example-compositor/compositor/Cargo.toml index 02c6ebe0ce2..d505e9ad295 100644 --- a/third_party/webrender/example-compositor/compositor/Cargo.toml +++ b/third_party/webrender/example-compositor/compositor/Cargo.toml @@ -7,10 +7,7 @@ license = "MPL-2.0" [dependencies] webrender = { path = "../../webrender" } -gleam = "0.15" +gleam = "0.12.0" [target.'cfg(windows)'.dependencies] compositor-windows = { path = "../compositor-windows" } - -[target.'cfg(target_os = "linux")'.dependencies] -compositor-wayland = { path = "../compositor-wayland" } diff --git a/third_party/webrender/example-compositor/compositor/src/main.rs b/third_party/webrender/example-compositor/compositor/src/main.rs index fef9438ec20..b2a7aac3a94 100644 --- a/third_party/webrender/example-compositor/compositor/src/main.rs +++ b/third_party/webrender/example-compositor/compositor/src/main.rs @@ -16,12 +16,10 @@ use euclid::Angle; use gleam::gl; use std::ffi::CString; use std::sync::mpsc; -use webrender::{CompositorSurfaceTransform, Transaction, api::*, euclid::point2}; +use webrender::api::*; 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 @@ -44,7 +42,6 @@ impl webrender::Compositor for DirectCompositeInterface { fn create_surface( &mut self, id: webrender::NativeSurfaceId, - _virtual_offset: DeviceIntPoint, tile_size: DeviceIntSize, is_opaque: bool, ) { @@ -92,7 +89,6 @@ 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, @@ -122,15 +118,14 @@ impl webrender::Compositor for DirectCompositeInterface { fn add_surface( &mut self, id: webrender::NativeSurfaceId, - transform: CompositorSurfaceTransform, + position: DeviceIntPoint, clip_rect: DeviceIntRect, - _image_rendering: ImageRendering, ) { compositor::add_surface( self.window, id.0, - transform.transform_point2d(point2(0., 0.)).unwrap().x as i32, - transform.transform_point2d(point2(0., 0.)).unwrap().y as i32, + position.x, + position.y, clip_rect.origin.x, clip_rect.origin.y, clip_rect.size.width, @@ -141,42 +136,6 @@ 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 @@ -200,7 +159,7 @@ impl RenderNotifier for Notifier { }) } - fn wake_up(&self, _composite_needed: bool) { + fn wake_up(&self) { } fn new_frame_ready(&self, @@ -222,7 +181,7 @@ fn push_rotated_rect( time: f32, ) { let color = color.scale_rgb(time); - let rotation = LayoutTransform::rotation( + let rotation = LayoutTransform::create_rotation( 0.0, 0.0, 1.0, @@ -235,16 +194,13 @@ fn push_rotated_rect( ); let transform = rotation .pre_translate(-transform_origin) - .then_translate(transform_origin); + .post_translate(transform_origin); let spatial_id = builder.push_reference_frame( LayoutPoint::zero(), spatial_id, TransformStyle::Flat, PropertyBinding::Value(transform), - ReferenceFrameKind::Transform { - is_2d_scale_translation: false, - should_snap: false, - }, + ReferenceFrameKind::Transform, ); builder.push_rect( &CommonItemProperties::new( @@ -279,7 +235,7 @@ fn build_display_list( let scroll_space_info = builder.define_scroll_frame( &fixed_space_info, - scroll_id, + Some(scroll_id), LayoutRect::new(LayoutPoint::zero(), layout_size), LayoutRect::new(LayoutPoint::zero(), layout_size), ScrollSensitivity::Script, @@ -333,32 +289,6 @@ 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)] @@ -428,15 +358,13 @@ 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(); @@ -455,9 +383,10 @@ fn main() { notifier, opts, None, + device_size, ).unwrap(); - let mut api = sender.create_api(); - let document_id = api.add_document(device_size); + let api = sender.create_api(); + let document_id = api.add_document(device_size, 0); let device_pixel_ratio = 1.0; let mut current_epoch = Epoch(0); let root_pipeline_id = PipelineId(0, 0); @@ -470,7 +399,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); + let mut root_builder = DisplayListBuilder::new(root_pipeline_id, layout_size); build_display_list( &mut root_builder, @@ -490,7 +419,7 @@ fn main() { ); } - txn.generate_frame(0); + txn.generate_frame(); api.send_transaction(document_id, txn); // Tick the compositor (in this sample, we don't block on UI events) @@ -500,7 +429,7 @@ fn main() { // Update and render. This will invoke the native compositor interface implemented above // as required. renderer.update(); - renderer.render(device_size, 0).unwrap(); + renderer.render(device_size).unwrap(); let _ = renderer.flush_pipeline_info(); // Construct a simple display list that can be drawn and composited by DC. @@ -508,7 +437,7 @@ fn main() { match inv_mode { Invalidations::Small | Invalidations::Large => { - let mut root_builder = DisplayListBuilder::new(root_pipeline_id); + let mut root_builder = DisplayListBuilder::new(root_pipeline_id, layout_size); build_display_list( &mut root_builder, @@ -537,7 +466,7 @@ fn main() { } } - txn.generate_frame(0); + txn.generate_frame(); api.send_transaction(document_id, txn); current_epoch.0 += 1; time += 0.001; |