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:
Martin Robinson 2023-09-10 14:38:56 +02:00 committed by GitHub
parent c079acb3c3
commit a9d37cb85a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
563 changed files with 48524 additions and 51657 deletions

1752
third_party/webrender/Cargo.lock generated vendored

File diff suppressed because it is too large Load diff

View file

@ -1,6 +1,5 @@
[workspace]
members = [
"direct-composition",
"examples",
"webrender",
"webrender_api",
@ -16,6 +15,13 @@ panic = "abort"
[profile.dev]
panic = "abort"
# optimizing glsl more makes a big difference in swgl build times
[profile.dev.package.glsl]
opt-level = 2
[profile.release.package.glsl]
opt-level = 2
# Running wrench on android built with master cargo-apk results in a crash
# due to a mismatched version of android_glue (a dependency of winit).
# Override it to use a suitable version of android_glue.
@ -23,3 +29,5 @@ panic = "abort"
# This can be removed once a new version of android_glue is published to crates.io.
[patch.crates-io]
android_glue = { git = "https://github.com/rust-windowing/android-rs-glue.git", rev = "e3ac6edea5814e1faca0c31ea8fac6877cb929ea" }
# this is a version that fixes some incompatibilites with newer rust/aarch64
winit = { version = "0.19", git = "https://github.com/jrmuizel/winit", branch="wr" }

View file

@ -14,15 +14,19 @@ test "$(whoami)" == 'root'
# Install stuff we need
apt-get -y update
apt-get install -y \
bison \
bzip2 \
cmake \
curl \
flex \
gcc \
git \
g++ \
libfontconfig1-dev \
libgl1-mesa-dev \
libx11-dev \
llvm-dev \
ninja-build \
openjdk-8-jdk \
pkg-config \
python \
@ -31,7 +35,10 @@ apt-get install -y \
python-setuptools \
python-voluptuous \
python-yaml \
software-properties-common
python3-pip \
python3-mako \
software-properties-common \
clang
# Other stuff we need
pip install servo-tidy==0.3.0

View file

@ -0,0 +1,18 @@
[binaries]
llvm-config = '/builds/worker/fetches/clang/bin/llvm-config'
[properties]
# When linking `libOSMesa.dylib` Meson uses options provided by `llvm-config`.
# The binary for `llvm-config` in Firefox CI comes from a native Linux clang,
# which gives the link options for the Linux libLLVM-11.so in the Linux clang.
# However, we want to link against a native macOS clang's libLLVM.dylib, which
# we have available in a separate directory.
# Meson will still have -lLLVM-11 on the command line, but the linker will
# only warn that it has the wrong format (because it's not for macOS).
cpp_link_args = ['-L/builds/worker/fetches/clang-mac/clang/lib', '-lLLVM']
[host_machine]
system = 'darwin'
cpu_family = 'x86_64'
cpu = 'i686'
endian = 'little'

View file

@ -0,0 +1,22 @@
#!/usr/bin/env bash
# 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/. */
# This file downloads and installs meson which is required for building
# osmesa-src, a dependency of wrench.
set -o errexit
set -o nounset
set -o pipefail
set -o xtrace
MESON_VER=0.55.1
MESON_BASE_URL="https://github.com/mesonbuild/meson/releases/download"
curl -L ${MESON_BASE_URL}/${MESON_VER}/meson-${MESON_VER}.tar.gz -o meson.tar.gz
tar -xf meson.tar.gz
mv meson-${MESON_VER} meson
cd meson
ln -s meson.py meson

View file

@ -32,5 +32,5 @@ cargo build ${CARGOFLAGS}
popd
cargo test ${CARGOFLAGS} \
--all --exclude compositor-windows --exclude compositor \
--exclude glsl-to-cxx --exclude swgl
--all --exclude compositor --exclude compositor-wayland \
--exclude compositor-windows --exclude glsl-to-cxx --exclude swgl

View file

@ -16,7 +16,13 @@ set -o xtrace
CARGOFLAGS=${CARGOFLAGS:-""} # default to empty if not set
pushd wrench
# Test that all shaders compile successfully.
python script/headless.py --precache test_init
python script/headless.py --precache --use-unoptimized-shaders test_init
python script/headless.py reftest
python script/headless.py rawtest
cargo build ${CARGOFLAGS} --release
python script/headless.py test_invalidation
CXX=clang++ cargo run ${CARGOFLAGS} --release --features=software -- \
--software --headless reftest
popd

View file

@ -38,5 +38,5 @@ cargo check ${CARGOFLAGS}
popd
cargo test ${CARGOFLAGS} ${CARGOTESTFLAGS} \
--all --exclude compositor-windows --exclude compositor \
--exclude glsl-to-cxx --exclude swgl
--all --exclude compositor --exclude compositor-wayland \
--exclude compositor-windows --exclude glsl-to-cxx --exclude swgl

View file

@ -19,7 +19,13 @@ CARGOFLAGS=${CARGOFLAGS:-""} # default to empty if not set
WRENCH_BINARY=${WRENCH_BINARY:-""}
pushd wrench
# Test that all shaders compile successfully.
python script/headless.py --precache test_init
python script/headless.py --precache --use-unoptimized-shaders test_init
python script/headless.py reftest
python script/headless.py test_invalidation
if [[ -z "${WRENCH_BINARY}" ]]; then
cargo build ${CARGOFLAGS} --release
WRENCH_BINARY="../target/release/wrench"

View file

@ -21,6 +21,13 @@ popd
pushd wrench
cargo test --verbose
if %ERRORLEVEL% NEQ 0 EXIT /b %ERRORLEVEL%
:: Test that all shaders compile successfully. --precache compiles all shaders
:: during initialization, therefore if init is successful then the shaders compile.
cargo run --release -- --angle --precache test_init
if %ERRORLEVEL% NEQ 0 EXIT /b %ERRORLEVEL%
cargo run --release -- --angle --precache --use-unoptimized-shaders test_init
if %ERRORLEVEL% NEQ 0 EXIT /b %ERRORLEVEL%
cargo run --release -- --angle reftest
if %ERRORLEVEL% NEQ 0 EXIT /b %ERRORLEVEL%
popd
@ -29,8 +36,3 @@ pushd examples
cargo check --verbose
if %ERRORLEVEL% NEQ 0 EXIT /b %ERRORLEVEL%
popd
pushd direct-composition
cargo check --verbose
if %ERRORLEVEL% NEQ 0 EXIT /b %ERRORLEVEL%
popd

View file

@ -1,6 +0,0 @@
{
"presets": [
["env", { "modules": false }],
"stage-3"
]
}

View file

@ -1,11 +0,0 @@
.DS_Store
node_modules/
npm-debug.log
yarn-error.log
# Editor directories and files
.idea
*.suo
*.ntvs*
*.njsproj
*.sln

View file

@ -1,23 +0,0 @@
# WebRender Debugger
A web based debugger for WebRender.
## Using the debugger
Build your application with the debugger feature enabled, for example in wrench:
```
cargo build --features=debugger
```
Now, open your browser and open the debugger/index.html file. Click Connect and
the debugger will attempt to connect to WR via websocket.
## Using the debugger with Gecko
In the Gecko source tree, open ```gfx/webrender_bindings/Cargo.toml``` in a text editor.
Add ```features = ['debugger']``` to the end of the file (in the ```dependencies.webrender``` section).
Vendor the rust dependencies locally for the debugger (we don't want these committed to the repo):
```./mach vendor rust```
Now, build and run as usual, and the debugger will be available.

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -1,11 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>WebRender Debugger</title>
</head>
<body>
<div id="app"></div>
<script src="dist/build.js"></script>
</body>
</html>

File diff suppressed because it is too large Load diff

View file

@ -1,36 +0,0 @@
{
"name": "debugger",
"description": "WebRender Debugger",
"version": "1.0.0",
"author": "Glenn Watson <github@intuitionlibrary.com>",
"license": "MIT",
"private": true,
"scripts": {
"dev": "cross-env NODE_ENV=development webpack-dev-server --open --hot",
"build": "cross-env NODE_ENV=production webpack --progress --hide-modules"
},
"dependencies": {
"buefy": "^0.6.7",
"vue": "^2.5.11",
"vue-material-design-icons": "^0.8.2",
"vuex": "^3.0.1"
},
"browserslist": [
"> 1%",
"last 2 versions",
"not ie <= 8"
],
"devDependencies": {
"babel-core": "^6.26.0",
"babel-loader": "^7.1.2",
"babel-preset-env": "^1.6.0",
"babel-preset-stage-3": "^6.24.1",
"cross-env": "^5.0.5",
"css-loader": "^0.28.7",
"file-loader": "^1.1.4",
"vue-loader": "^13.0.5",
"vue-template-compiler": "^2.4.4",
"webpack": "^3.6.0",
"webpack-dev-server": "^2.9.1"
}
}

View file

@ -1,55 +0,0 @@
<template>
<div>
<app-navbar></app-navbar>
<div class="section">
<div class="container">
<div class="columns">
<div class="column is-3">
<app-navmenu></app-navmenu>
</div>
<div class="column">
<app-options v-if="page == 'options'"></app-options>
<app-passview v-if="page == 'passes'"></app-passview>
<app-rendertaskview v-if="page == 'render_tasks'"></app-rendertaskview>
<app-documentview v-if="page == 'documents'"></app-documentview>
<app-clipscrolltreeview v-if="page == 'clip_scroll_tree'"></app-clipscrolltreeview>
<app-screenshotview v-if="page == 'screenshot'"></app-screenshotview>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import NavBar from './components/NavBar.vue'
import NavMenu from './components/NavMenu.vue'
import OptionsPage from './components/OptionsPage.vue'
import PassViewPage from './components/PassViewPage.vue'
import RenderTaskViewPage from './components/RenderTaskViewPage.vue'
import DocumentViewPage from './components/DocumentViewPage.vue'
import ClipScrollTreeViewPage from './components/ClipScrollTreeViewPage.vue'
import ScreenshotPage from './components/ScreenshotPage.vue'
export default {
name: 'app',
components: {
'app-navbar': NavBar,
'app-navmenu': NavMenu,
'app-options': OptionsPage,
'app-passview': PassViewPage,
'app-rendertaskview': RenderTaskViewPage,
'app-documentview': DocumentViewPage,
'app-clipscrolltreeview': ClipScrollTreeViewPage,
'app-screenshotview': ScreenshotPage,
},
computed: {
page() {
return this.$store.state.page;
}
},
}
</script>
<style>
</style>

View file

@ -1,37 +0,0 @@
<template>
<div class="box">
<h1 class="title">Clip-Scroll Tree <a :disabled="disabled" v-on:click="fetch" class="button is-info">Refresh</a></h1>
<hr/>
<div>
<ul>
<app-treeview :model=clip_scroll_tree></app-treeview>
</ul>
</div>
</div>
</template>
<script>
import TreeView from './TreeView.vue'
export default {
components: {
'app-treeview': TreeView,
},
methods: {
fetch: function() {
this.$store.dispatch('sendMessage', "fetch_clip_scroll_tree");
}
},
computed: {
disabled() {
return !this.$store.state.connected
},
clip_scroll_tree() {
return this.$store.state.clip_scroll_tree
}
},
}
</script>
<style>
</style>

View file

@ -1,37 +0,0 @@
<template>
<div class="box">
<h1 class="title">Documents <a :disabled="disabled" v-on:click="fetch" class="button is-info">Refresh</a></h1>
<hr/>
<div>
<ul>
<app-treeview :model=documents></app-treeview>
</ul>
</div>
</div>
</template>
<script>
import TreeView from './TreeView.vue'
export default {
components: {
'app-treeview': TreeView,
},
methods: {
fetch: function() {
this.$store.dispatch('sendMessage', "fetch_documents");
}
},
computed: {
disabled() {
return !this.$store.state.connected
},
documents() {
return this.$store.state.documents
}
},
}
</script>
<style>
</style>

View file

@ -1,41 +0,0 @@
<template>
<nav class="navbar has-shadow">
<div class="navbar-brand">
<a class="navbar-item" href="#">WebRender Debugger</a>
</div>
<div class="navbar-menu">
<div class="navbar-start"></div>
<div class="navbar-end">
<div class="navbar-item">
<p class="control">
<button v-if="isConnected" @click="disconnect" class="button is-danger">Disconnect</button>
<button v-else @click="connect" class="button is-success">Connect</button>
</p>
</div>
</div>
</div>
</nav>
</template>
<script>
export default {
computed: {
isConnected() {
return this.$store.state.connected;
},
},
methods: {
connect() {
this.$store.dispatch('connect');
},
disconnect() {
this.$store.dispatch('disconnect');
},
}
}
</script>
<style>
</style>

View file

@ -1,33 +0,0 @@
<template>
<aside class="menu">
<p class="menu-label">
Pages
</p>
<ul class="menu-list">
<li><a @click="setPage('options')" :class="{ 'is-active': page == 'options' }">Debug Options</a></li>
<li><a @click="setPage('passes')" :class="{ 'is-active': page == 'passes' }">Passes</a></li>
<li><a @click="setPage('render_tasks')" :class="{ 'is-active': page == 'render_tasks' }">Render Tasks</a></li>
<li><a @click="setPage('documents')" :class="{ 'is-active': page == 'documents' }">Documents</a></li>
<li><a @click="setPage('clip_scroll_tree')" v-bind:class="{ 'is-active': page == 'clip_scroll_tree' }">Clip-Scroll Tree</a></li>
<li><a @click="setPage('screenshot')" v-bind:class="{ 'is-active': page == 'screenshot' }">Screenshot</a></li>
</ul>
</aside>
</template>
<script>
export default {
methods: {
setPage(name) {
this.$store.commit('setPage', name);
},
},
computed: {
page() {
return this.$store.state.page;
}
},
}
</script>
<style>
</style>

View file

@ -1,162 +0,0 @@
<template>
<div class="box">
<div class="field">
<label class="checkbox">
<input type="checkbox" :disabled="disabled" v-on:click="setProfiler($event.target.checked)">
Profiler
</label>
</div>
<div class="field">
<label class="checkbox">
<input type="checkbox" :disabled="disabled" v-on:click="setTextureCacheDebugger($event.target.checked)">
Texture cache debugger
</label>
</div>
<div class="field">
<label class="checkbox">
<input type="checkbox" :disabled="disabled" v-on:click="setRenderTargetDebugger($event.target.checked)">
Render target debugger
</label>
</div>
<div class="field">
<label class="checkbox">
<input type="checkbox" :disabled="disabled" v-on:click="setAlphaRectsDebugger($event.target.checked)">
Alpha primitive rects debugger
</label>
</div>
<div class="field">
<label class="checkbox">
<input type="checkbox" :disabled="disabled" v-on:click="setGpuTimeQueries($event.target.checked)">
Enable GPU time queries
</label>
</div>
<div class="field">
<label class="checkbox">
<input type="checkbox" :disabled="disabled" v-on:click="setGpuSampleQueries($event.target.checked)">
Enable GPU sample queries
</label>
</div>
<div class="field">
<label class="checkbox">
<input type="checkbox" :disabled="disabled" v-on:click="setOpaquePass(!$event.target.checked)">
Disable opaque pass
</label>
</div>
<div class="field">
<label class="checkbox">
<input type="checkbox" :disabled="disabled" v-on:click="setAlphaPass(!$event.target.checked)">
Disable alpha pass
</label>
</div>
<div class="field">
<label class="checkbox">
<input type="checkbox" :disabled="disabled" v-on:click="setClipMasks(!$event.target.checked)">
Disable clip masks
</label>
</div>
<div class="field">
<label class="checkbox">
<input type="checkbox" :disabled="disabled" v-on:click="setTextPrims(!$event.target.checked)">
Disable text primitives
</label>
</div>
<div class="field">
<label class="checkbox">
<input type="checkbox" :disabled="disabled" v-on:click="setGradientPrims(!$event.target.checked)">
Disable gradient primitives
</label>
</div>
</div>
</template>
<script>
export default {
computed: {
disabled() {
return !this.$store.state.connected
}
},
methods: {
setProfiler(enabled) {
if (enabled) {
this.$store.dispatch('sendMessage', "enable_profiler");
} else {
this.$store.dispatch('sendMessage', "disable_profiler");
}
},
setTextureCacheDebugger(enabled) {
if (enabled) {
this.$store.dispatch('sendMessage', "enable_texture_cache_debug");
} else {
this.$store.dispatch('sendMessage', "disable_texture_cache_debug");
}
},
setRenderTargetDebugger(enabled) {
if (enabled) {
this.$store.dispatch('sendMessage', "enable_render_target_debug");
} else {
this.$store.dispatch('sendMessage', "disable_render_target_debug");
}
},
setAlphaRectsDebugger(enabled) {
if (enabled) {
this.$store.dispatch('sendMessage', "enable_alpha_rects_debug");
} else {
this.$store.dispatch('sendMessage', "disable_alpha_rects_debug");
}
},
setGpuTimeQueries(enabled) {
if (enabled) {
this.$store.dispatch('sendMessage', "enable_gpu_time_queries");
} else {
this.$store.dispatch('sendMessage', "disable_gpu_time_queries");
}
},
setGpuSampleQueries(enabled) {
if (enabled) {
this.$store.dispatch('sendMessage', "enable_gpu_sample_queries");
} else {
this.$store.dispatch('sendMessage', "disable_gpu_sample_queries");
}
},
setOpaquePass(enabled) {
if (enabled) {
this.$store.dispatch('sendMessage', "enable_opaque_pass");
} else {
this.$store.dispatch('sendMessage', "disable_opaque_pass");
}
},
setAlphaPass(enabled) {
if (enabled) {
this.$store.dispatch('sendMessage', "enable_alpha_pass");
} else {
this.$store.dispatch('sendMessage', "disable_alpha_pass");
}
},
setClipMasks(enabled) {
if (enabled) {
this.$store.dispatch('sendMessage', "enable_clip_masks");
} else {
this.$store.dispatch('sendMessage', "disable_clip_masks");
}
},
setTextPrims(enabled) {
if (enabled) {
this.$store.dispatch('sendMessage', "enable_text_prims");
} else {
this.$store.dispatch('sendMessage', "disable_text_prims");
}
},
setGradientPrims(enabled) {
if (enabled) {
this.$store.dispatch('sendMessage', "enable_gradient_prims");
} else {
this.$store.dispatch('sendMessage', "disable_gradient_prims");
}
}
},
}
</script>
<style>
</style>

View file

@ -1,37 +0,0 @@
<template>
<div class="box">
<h1 class="title">Passes <a :disabled="disabled" v-on:click="fetch" class="button is-info">Refresh</a></h1>
<hr/>
<div v-for="(pass, pass_index) in passes">
<p class="has-text-black-bis">Pass {{pass_index}}</p>
<div v-for="(target, target_index) in pass.targets">
<p style="text-indent: 2em;" class="has-text-grey-dark">Target {{target_index}} ({{target.kind}})</p>
<div v-for="(batch, batch_index) in target.batches">
<p style="text-indent: 4em;" class="has-text-grey">Batch {{batch_index}} ({{batch.description}}, {{batch.kind}}, {{batch.count}} instances)</p>
</div>
</div>
<hr/>
</div>
</div>
</template>
<script>
export default {
methods: {
fetch: function() {
this.$store.dispatch('sendMessage', "fetch_passes");
}
},
computed: {
disabled() {
return !this.$store.state.connected
},
passes() {
return this.$store.state.passes
}
},
}
</script>
<style>
</style>

View file

@ -1,37 +0,0 @@
<template>
<div class="box">
<h1 class="title">Render Tasks <a :disabled="disabled" v-on:click="fetch" class="button is-info">Refresh</a></h1>
<hr/>
<div>
<ul>
<app-treeview :model=render_tasks></app-treeview>
</ul>
</div>
</div>
</template>
<script>
import TreeView from './TreeView.vue'
export default {
components: {
'app-treeview': TreeView,
},
methods: {
fetch: function() {
this.$store.dispatch('sendMessage', "fetch_render_tasks");
}
},
computed: {
disabled() {
return !this.$store.state.connected
},
render_tasks() {
return this.$store.state.render_tasks
}
},
}
</script>
<style>
</style>

View file

@ -1,32 +0,0 @@
<template>
<div class="box">
<h1 class="title">Screenshot <a :disabled="disabled" v-on:click="fetch" class="button is-info">Refresh</a></h1>
<hr/>
<div>
<ul>
<img v-if="screenshot.length > 0" style="transform: scaleY(-1); width: 1024px; height:768px" :src="'data:image/png;base64,' + screenshot" />
</ul>
</div>
</div>
</template>
<script>
export default {
computed: {
disabled() {
return !this.$store.state.connected
},
screenshot() {
return this.$store.state.screenshot
},
},
methods: {
fetch: function() {
this.$store.dispatch('sendMessage', "fetch_screenshot");
}
},
}
</script>
<style>
</style>

View file

@ -1,40 +0,0 @@
<template>
<li>
<div v-on:click="toggle">
<span v-if="isFolder">[{{open ? '-' : '+'}}]</span>
{{model.description}}
</div>
<ul style="padding-left: 1em; line-height: 1.5em;" v-show="open" v-if="isFolder">
<treeview v-for="model in model.children" :model="model"></treeview>
</ul>
</li>
</template>
<script>
export default {
name: 'treeview',
props: [
'model',
],
data: function () {
return {
open: false
}
},
computed: {
isFolder: function () {
return this.model.children && this.model.children.length
}
},
methods: {
toggle: function () {
if (this.isFolder) {
this.open = !this.open
}
},
},
}
</script>
<style>
</style>

View file

@ -1,14 +0,0 @@
import Vue from 'vue';
import Buefy from 'buefy';
import 'buefy/dist/buefy.css';
import "vue-material-design-icons/styles.css";
import App from './App.vue';
import store from './store';
Vue.use(Buefy);
new Vue({
el: '#app',
store,
render: h => h(App)
})

View file

@ -1,105 +0,0 @@
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
class Connection {
constructor() {
this.ws = null;
}
connect(context) {
var ws = new WebSocket("ws://127.0.0.1:3583");
ws.onopen = function() {
context.commit('setConnected', true);
}
ws.onmessage = function(evt) {
var json = JSON.parse(evt.data);
if (json['kind'] == "passes") {
context.commit('setPasses', json['passes']);
} else if (json['kind'] == "render_tasks") {
context.commit('setRenderTasks', json['root']);
} else if (json['kind'] == "documents") {
context.commit('setDocuments', json['root']);
} else if (json['kind'] == "clip_scroll_tree") {
context.commit('setClipScrollTree', json['root']);
} else if (json['kind'] == "screenshot") {
context.commit('setScreenshot', json['data']);
} else {
console.warn("unknown message kind: " + json['kind']);
}
}
ws.onclose = function() {
context.commit('setConnected', false);
}
this.ws = ws;
}
send(msg) {
if (this.ws !== null) {
this.ws.send(msg);
}
}
disconnect() {
if (this.ws !== null) {
this.ws.close();
this.ws = null;
}
}
}
var connection = new Connection();
const store = new Vuex.Store({
strict: true,
state: {
connected: false,
page: 'options',
passes: [],
render_tasks: [],
documents: [],
clip_scroll_tree: [],
screenshot: [],
},
mutations: {
setConnected(state, connected) {
state.connected = connected;
},
setPage(state, name) {
state.page = name;
},
setPasses(state, passes) {
state.passes = passes;
},
setRenderTasks(state, render_tasks) {
state.render_tasks = render_tasks;
},
setDocuments(state, documents) {
state.documents = documents;
},
setClipScrollTree(state, clip_scroll_tree) {
state.clip_scroll_tree = clip_scroll_tree;
},
setScreenshot(state, screenshot) {
state.screenshot = screenshot;
},
},
actions: {
connect(context) {
connection.connect(context);
},
disconnect(context) {
connection.disconnect();
},
sendMessage(context, msg) {
connection.send(msg);
}
}
});
export default store;

View file

@ -1,81 +0,0 @@
var path = require('path')
var webpack = require('webpack')
module.exports = {
entry: './src/main.js',
output: {
path: path.resolve(__dirname, './dist'),
publicPath: '/dist/',
filename: 'build.js'
},
module: {
rules: [
{
test: /\.css$/,
use: [
'vue-style-loader',
'css-loader'
],
}, {
test: /\.vue$/,
loader: 'vue-loader',
options: {
loaders: {
}
// other vue-loader options go here
}
},
{
test: /\.js$/,
loader: 'babel-loader',
exclude: /node_modules/
},
{
test: /\.(png|jpg|gif|svg)$/,
loader: 'file-loader',
options: {
name: '[name].[ext]?[hash]'
}
}
]
},
resolve: {
alias: {
'vue$': 'vue/dist/vue.esm.js'
},
alias : {
"icons": path.resolve(__dirname, "node_modules/vue-material-design-icons")
},
extensions: ['*', '.js', '.vue', '.json']
},
devServer: {
historyApiFallback: true,
noInfo: true,
overlay: true
},
performance: {
hints: false
},
devtool: '#eval-source-map'
}
if (process.env.NODE_ENV === 'production') {
module.exports.devtool = '#source-map'
// http://vue-loader.vuejs.org/en/workflow/production.html
module.exports.plugins = (module.exports.plugins || []).concat([
new webpack.DefinePlugin({
'process.env': {
NODE_ENV: '"production"'
}
}),
new webpack.optimize.UglifyJsPlugin({
sourceMap: true,
compress: {
warnings: false
}
}),
new webpack.LoaderOptionsPlugin({
minimize: true
})
])
}

View file

@ -1,14 +0,0 @@
[package]
name = "direct-composition"
version = "0.1.0"
authors = ["Simon Sapin <simon.sapin@exyr.org>"]
license = "MPL-2.0"
edition = "2018"
[target.'cfg(windows)'.dependencies]
euclid = "0.22"
gleam = "0.12"
mozangle = {version = "0.3.1", features = ["egl"]}
webrender = {path = "../webrender"}
winapi = {version = "0.3", features = ["winerror", "d3d11", "dcomp"]}
winit = "0.19"

View file

@ -1,112 +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::ops;
use std::ptr;
use winapi::Interface;
use winapi::ctypes::c_void;
use winapi::shared::guiddef::GUID;
use winapi::shared::winerror::HRESULT;
use winapi::shared::winerror::SUCCEEDED;
use winapi::um::unknwnbase::IUnknown;
pub fn as_ptr<T>(x: &T) -> *mut T {
x as *const T as _
}
pub trait CheckHResult {
fn check_hresult(self);
}
impl CheckHResult for HRESULT {
fn check_hresult(self) {
if !SUCCEEDED(self) {
panic_com(self)
}
}
}
fn panic_com(hresult: HRESULT) -> ! {
panic!("COM error 0x{:08X}", hresult as u32)
}
/// Forked from <https://github.com/retep998/wio-rs/blob/44093f7db8/src/com.rs>
#[derive(PartialEq, Debug)]
pub struct ComPtr<T>(*mut T) where T: Interface;
impl<T> ComPtr<T> where T: Interface {
/// Creates a `ComPtr` to wrap a raw pointer.
/// It takes ownership over the pointer which means it does __not__ call `AddRef`.
/// `T` __must__ be a COM interface that inherits from `IUnknown`.
pub unsafe fn from_raw(ptr: *mut T) -> ComPtr<T> {
assert!(!ptr.is_null());
ComPtr(ptr)
}
/// For use with APIs that take an interface UUID and
/// "return" a new COM object through a `*mut *mut c_void` out-parameter.
pub unsafe fn new_with_uuid<F>(f: F) -> Self
where F: FnOnce(&GUID, *mut *mut c_void) -> HRESULT
{
Self::new_with(|ptr| f(&T::uuidof(), ptr as _))
}
/// For use with APIs that "return" a new COM object through a `*mut *mut T` out-parameter.
pub unsafe fn new_with<F>(f: F) -> Self
where F: FnOnce(*mut *mut T) -> HRESULT
{
let mut ptr = ptr::null_mut();
let hresult = f(&mut ptr);
if SUCCEEDED(hresult) {
ComPtr::from_raw(ptr)
} else {
if !ptr.is_null() {
let ptr = ptr as *mut IUnknown;
(*ptr).Release();
}
panic_com(hresult)
}
}
pub fn as_raw(&self) -> *mut T {
self.0
}
fn as_unknown(&self) -> &IUnknown {
unsafe {
&*(self.0 as *mut IUnknown)
}
}
/// Performs QueryInterface fun.
pub fn cast<U>(&self) -> ComPtr<U> where U: Interface {
unsafe {
ComPtr::<U>::new_with_uuid(|uuid, ptr| self.as_unknown().QueryInterface(uuid, ptr))
}
}
}
impl<T> ops::Deref for ComPtr<T> where T: Interface {
type Target = T;
fn deref(&self) -> &T {
unsafe { &*self.0 }
}
}
impl<T> Clone for ComPtr<T> where T: Interface {
fn clone(&self) -> Self {
unsafe {
self.as_unknown().AddRef();
ComPtr(self.0)
}
}
}
impl<T> Drop for ComPtr<T> where T: Interface {
fn drop(&mut self) {
unsafe {
self.as_unknown().Release();
}
}
}

View file

@ -1,174 +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 mozangle::egl::ffi::*;
use std::os::raw::c_void;
use std::ptr;
use std::rc::Rc;
use winapi::um::d3d11::ID3D11Device;
use winapi::um::d3d11::ID3D11Texture2D;
pub use mozangle::egl::get_proc_address;
pub struct SharedEglThings {
device: EGLDeviceEXT,
display: types::EGLDisplay,
config: types::EGLConfig,
context: types::EGLContext,
}
fn cast_attributes(slice: &[types::EGLenum]) -> &EGLint {
unsafe {
&*(slice.as_ptr() as *const EGLint)
}
}
macro_rules! attributes {
($( $key: expr => $value: expr, )*) => {
cast_attributes(&[
$( $key, $value, )*
NONE,
])
}
}
impl SharedEglThings {
pub unsafe fn new(d3d_device: *mut ID3D11Device) -> Rc<Self> {
let device = eglCreateDeviceANGLE(
D3D11_DEVICE_ANGLE,
d3d_device as *mut c_void,
ptr::null(),
).check();
let display = GetPlatformDisplayEXT(
PLATFORM_DEVICE_EXT,
device,
attributes! [
EXPERIMENTAL_PRESENT_PATH_ANGLE => EXPERIMENTAL_PRESENT_PATH_FAST_ANGLE,
],
).check();
Initialize(display, ptr::null_mut(), ptr::null_mut()).check();
// Adapted from
// https://searchfox.org/mozilla-central/rev/056a4057/gfx/gl/GLContextProviderEGL.cpp#635
let mut configs = [ptr::null(); 64];
let mut num_configs = 0;
ChooseConfig(
display,
attributes! [
SURFACE_TYPE => WINDOW_BIT,
RENDERABLE_TYPE => OPENGL_ES2_BIT,
RED_SIZE => 8,
GREEN_SIZE => 8,
BLUE_SIZE => 8,
ALPHA_SIZE => 8,
],
configs.as_mut_ptr(),
configs.len() as i32,
&mut num_configs,
).check();
let config = pick_config(&configs[..num_configs as usize]);
let context = CreateContext(
display, config, NO_CONTEXT,
attributes![
CONTEXT_CLIENT_VERSION => 3,
]
).check();
MakeCurrent(display, NO_SURFACE, NO_SURFACE, context).check();
Rc::new(SharedEglThings { device, display, config, context })
}
}
fn pick_config(configs: &[types::EGLConfig]) -> types::EGLConfig {
// FIXME: better criteria to make this choice?
// Firefox uses GetConfigAttrib to find a config that has the requested r/g/b/a sizes
// https://searchfox.org/mozilla-central/rev/056a4057/gfx/gl/GLContextProviderEGL.cpp#662-685
configs[0]
}
impl Drop for SharedEglThings {
fn drop(&mut self) {
unsafe {
// FIXME does EGLDisplay or EGLConfig need clean up? How?
DestroyContext(self.display, self.context).check();
eglReleaseDeviceANGLE(self.device).check();
}
}
}
pub struct PerVisualEglThings {
shared: Rc<SharedEglThings>,
surface: types::EGLSurface,
}
impl PerVisualEglThings {
pub unsafe fn new(shared: Rc<SharedEglThings>, buffer: *const ID3D11Texture2D,
width: u32, height: u32)
-> Self {
let surface = CreatePbufferFromClientBuffer(
shared.display,
D3D_TEXTURE_ANGLE,
buffer as types::EGLClientBuffer,
shared.config,
attributes! [
WIDTH => width,
HEIGHT => height,
FLEXIBLE_SURFACE_COMPATIBILITY_SUPPORTED_ANGLE => TRUE,
],
).check();
PerVisualEglThings { shared, surface }
}
pub fn make_current(&self) {
unsafe {
MakeCurrent(self.shared.display, self.surface, self.surface, self.shared.context).check();
}
}
}
impl Drop for PerVisualEglThings {
fn drop(&mut self) {
unsafe {
DestroySurface(self.shared.display, self.surface).check();
}
}
}
fn check_error() {
unsafe {
let error = GetError() as types::EGLenum;
assert_eq!(error, SUCCESS, "0x{:x} != 0x{:x}", error, SUCCESS);
}
}
trait Check {
fn check(self) -> Self;
}
impl Check for *const c_void {
fn check(self) -> Self {
check_error();
assert!(!self.is_null());
self
}
}
impl Check for *mut c_void {
fn check(self) -> Self {
check_error();
assert!(!self.is_null());
self
}
}
impl Check for types::EGLBoolean {
fn check(self) -> Self {
check_error();
assert_eq!(self, TRUE);
self
}
}

View file

@ -1,179 +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/. */
#![cfg(windows)]
use gleam;
use mozangle;
use winapi;
use com::{ComPtr, CheckHResult, as_ptr};
use std::ptr;
use std::rc::Rc;
use winapi::shared::dxgi1_2::DXGI_SWAP_CHAIN_DESC1;
use winapi::shared::dxgi1_2::IDXGIFactory2;
use winapi::shared::minwindef::{TRUE, FALSE};
use winapi::shared::windef::HWND;
use winapi::um::d3d11::ID3D11Device;
use winapi::um::dcomp::IDCompositionDevice;
use winapi::um::dcomp::IDCompositionTarget;
use winapi::um::dcomp::IDCompositionVisual;
mod com;
mod egl;
pub struct DirectComposition {
d3d_device: ComPtr<ID3D11Device>,
dxgi_factory: ComPtr<IDXGIFactory2>,
egl: Rc<egl::SharedEglThings>,
pub gleam: Rc<dyn gleam::gl::Gl>,
composition_device: ComPtr<IDCompositionDevice>,
root_visual: ComPtr<IDCompositionVisual>,
#[allow(unused)] // Needs to be kept alive
composition_target: ComPtr<IDCompositionTarget>,
}
impl DirectComposition {
/// Initialize DirectComposition in the given window
///
/// # Safety
///
/// `hwnd` must be a valid handle to a window.
pub unsafe fn new(hwnd: HWND) -> Self {
let d3d_device = ComPtr::new_with(|ptr_ptr| winapi::um::d3d11::D3D11CreateDevice(
ptr::null_mut(),
winapi::um::d3dcommon::D3D_DRIVER_TYPE_HARDWARE,
ptr::null_mut(),
winapi::um::d3d11::D3D11_CREATE_DEVICE_BGRA_SUPPORT |
if cfg!(debug_assertions) {
winapi::um::d3d11::D3D11_CREATE_DEVICE_DEBUG
} else {
0
},
ptr::null_mut(),
0,
winapi::um::d3d11::D3D11_SDK_VERSION,
ptr_ptr,
&mut 0,
ptr::null_mut(),
));
let egl = egl::SharedEglThings::new(d3d_device.as_raw());
let gleam = gleam::gl::GlesFns::load_with(egl::get_proc_address);
let dxgi_device = d3d_device.cast::<winapi::shared::dxgi::IDXGIDevice>();
// https://msdn.microsoft.com/en-us/library/windows/desktop/hh404556(v=vs.85).aspx#code-snippet-1
// “Because you can create a Direct3D device without creating a swap chain,
// you might need to retrieve the factory that is used to create the device
// in order to create a swap chain.”
let adapter = ComPtr::new_with(|ptr_ptr| dxgi_device.GetAdapter(ptr_ptr));
let dxgi_factory = ComPtr::<IDXGIFactory2>::new_with_uuid(|uuid, ptr_ptr| {
adapter.GetParent(uuid, ptr_ptr)
});
// Create the DirectComposition device object.
let composition_device = ComPtr::<IDCompositionDevice>::new_with_uuid(|uuid, ptr_ptr| {
winapi::um::dcomp::DCompositionCreateDevice(&*dxgi_device, uuid, ptr_ptr)
});
// Create the composition target object based on the
// specified application window.
let composition_target = ComPtr::new_with(|ptr_ptr| {
composition_device.CreateTargetForHwnd(hwnd, TRUE, ptr_ptr)
});
let root_visual = ComPtr::new_with(|ptr_ptr| composition_device.CreateVisual(ptr_ptr));
composition_target.SetRoot(&*root_visual).check_hresult();
DirectComposition {
d3d_device, dxgi_factory,
egl, gleam,
composition_device, composition_target, root_visual,
}
}
/// Execute changes to the DirectComposition scene.
pub fn commit(&self) {
unsafe {
self.composition_device.Commit().check_hresult()
}
}
pub fn create_angle_visual(&self, width: u32, height: u32) -> AngleVisual {
unsafe {
let desc = DXGI_SWAP_CHAIN_DESC1 {
Width: width,
Height: height,
Format: winapi::shared::dxgiformat::DXGI_FORMAT_B8G8R8A8_UNORM,
Stereo: FALSE,
SampleDesc: winapi::shared::dxgitype::DXGI_SAMPLE_DESC {
Count: 1,
Quality: 0,
},
BufferUsage: winapi::shared::dxgitype::DXGI_USAGE_RENDER_TARGET_OUTPUT,
BufferCount: 2,
Scaling: winapi::shared::dxgi1_2::DXGI_SCALING_STRETCH,
SwapEffect: winapi::shared::dxgi::DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL,
AlphaMode: winapi::shared::dxgi1_2::DXGI_ALPHA_MODE_PREMULTIPLIED,
Flags: 0,
};
let swap_chain = ComPtr::<winapi::shared::dxgi1_2::IDXGISwapChain1>::new_with(|ptr_ptr| {
self.dxgi_factory.CreateSwapChainForComposition(
as_ptr(&self.d3d_device),
&desc,
ptr::null_mut(),
ptr_ptr,
)
});
let back_buffer = ComPtr::<winapi::um::d3d11::ID3D11Texture2D>::new_with_uuid(|uuid, ptr_ptr| {
swap_chain.GetBuffer(0, uuid, ptr_ptr)
});
let egl = egl::PerVisualEglThings::new(self.egl.clone(), &*back_buffer, width, height);
let gleam = self.gleam.clone();
let visual = ComPtr::new_with(|ptr_ptr| self.composition_device.CreateVisual(ptr_ptr));
visual.SetContent(&*****swap_chain).check_hresult();
self.root_visual.AddVisual(&*visual, FALSE, ptr::null_mut()).check_hresult();
AngleVisual { visual, swap_chain, egl, gleam }
}
}
}
/// A DirectComposition "visual" configured for rendering with Direct3D.
pub struct AngleVisual {
visual: ComPtr<IDCompositionVisual>,
swap_chain: ComPtr<winapi::shared::dxgi1_2::IDXGISwapChain1>,
egl: egl::PerVisualEglThings,
pub gleam: Rc<dyn gleam::gl::Gl>,
}
impl AngleVisual {
pub fn set_offset_x(&self, offset_x: f32) {
unsafe {
self.visual.SetOffsetX_1(offset_x).check_hresult()
}
}
pub fn set_offset_y(&self, offset_y: f32) {
unsafe {
self.visual.SetOffsetY_1(offset_y).check_hresult()
}
}
pub fn make_current(&self) {
self.egl.make_current()
}
pub fn present(&self) {
self.gleam.finish();
unsafe {
self.swap_chain.Present(0, 0).check_hresult()
}
}
}

View file

@ -1,212 +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 direct_composition;
use euclid;
use gleam;
use webrender;
use winit;
use euclid::size2;
use direct_composition::DirectComposition;
use std::sync::mpsc;
use webrender::api;
use winit::os::windows::{WindowExt, WindowBuilderExt};
use winit::dpi::LogicalSize;
fn main() {
let mut events_loop = winit::EventsLoop::new();
let (tx, rx) = mpsc::channel();
let notifier = Box::new(Notifier { events_proxy: events_loop.create_proxy(), tx });
let window = winit::WindowBuilder::new()
.with_title("WebRender + ANGLE + DirectComposition")
.with_dimensions(LogicalSize::new(1024., 768.))
.with_decorations(true)
.with_transparency(true)
.with_no_redirection_bitmap(true)
.build(&events_loop)
.unwrap();
let composition = direct_composition_from_window(&window);
let factor = window.get_hidpi_factor() as f32;
let mut clicks: usize = 0;
let mut offset_y = 100.;
let mut rects = [
Rectangle::new(&composition, &notifier, factor, size2(300, 200), 0., 0.2, 0.4, 1.),
Rectangle::new(&composition, &notifier, factor, size2(400, 300), 0., 0.5, 0., 0.5),
];
rects[0].render(factor, &rx);
rects[1].render(factor, &rx);
rects[0].visual.set_offset_x(100.);
rects[0].visual.set_offset_y(50.);
rects[1].visual.set_offset_x(200.);
rects[1].visual.set_offset_y(offset_y);
composition.commit();
events_loop.run_forever(|event| {
if let winit::Event::WindowEvent { event, .. } = event {
match event {
winit::WindowEvent::CloseRequested => {
return winit::ControlFlow::Break
}
winit::WindowEvent::MouseWheel { delta, .. } => {
let dy = match delta {
winit::MouseScrollDelta::LineDelta(_, dy) => dy,
winit::MouseScrollDelta::PixelDelta(pos) => pos.y as f32,
};
offset_y = (offset_y - 10. * dy).max(0.).min(468.);
rects[1].visual.set_offset_y(offset_y);
composition.commit();
}
winit::WindowEvent::MouseInput {
button: winit::MouseButton::Left,
state: winit::ElementState::Pressed,
..
} => {
clicks += 1;
let rect = &mut rects[clicks % 2];
rect.color.g += 0.1;
rect.color.g %= 1.;
rect.render(factor, &rx)
}
_ => {}
}
}
winit::ControlFlow::Continue
});
}
fn direct_composition_from_window(window: &winit::Window) -> DirectComposition {
unsafe {
DirectComposition::new(window.get_hwnd() as _)
}
}
struct Rectangle {
visual: direct_composition::AngleVisual,
renderer: Option<webrender::Renderer>,
api: api::RenderApi,
document_id: api::DocumentId,
size: api::units::DeviceIntSize,
color: api::ColorF,
}
impl Rectangle {
fn new(composition: &DirectComposition, notifier: &Box<Notifier>,
device_pixel_ratio: f32, size: api::units::DeviceIntSize, r: f32, g: f32, b: f32, a: f32)
-> Self {
let visual = composition.create_angle_visual(size.width as u32, size.height as u32);
visual.make_current();
let (renderer, sender) = webrender::Renderer::new(
composition.gleam.clone(),
notifier.clone(),
webrender::RendererOptions {
clear_color: Some(api::ColorF::new(0., 0., 0., 0.)),
device_pixel_ratio,
..webrender::RendererOptions::default()
},
None,
size,
).unwrap();
let api = sender.create_api();
Rectangle {
visual,
renderer: Some(renderer),
document_id: api.add_document(size, 0),
api,
size,
color: api::ColorF { r, g, b, a },
}
}
fn render(&mut self, device_pixel_ratio: f32, rx: &mpsc::Receiver<()>) {
self.visual.make_current();
let pipeline_id = api::PipelineId(0, 0);
let layout_size = self.size.to_f32() / euclid::Scale::new(device_pixel_ratio);
let mut builder = api::DisplayListBuilder::new(pipeline_id, layout_size);
let rect = euclid::Rect::new(euclid::Point2D::zero(), layout_size);
let region = api::ComplexClipRegion::new(
rect,
api::BorderRadius::uniform(20.),
api::ClipMode::Clip
);
let clip_id = builder.define_clip_rounded_rect(
&api::SpaceAndClipInfo::root_scroll(pipeline_id),
region,
);
builder.push_rect(
&api::CommonItemProperties::new(
rect,
api::SpaceAndClipInfo {
spatial_id: api::SpatialId::root_scroll_node(pipeline_id),
clip_id,
},
),
rect,
self.color,
);
let mut transaction = api::Transaction::new();
transaction.set_display_list(
api::Epoch(0),
None,
layout_size,
builder.finalize(),
true,
);
transaction.set_root_pipeline(pipeline_id);
transaction.generate_frame();
self.api.send_transaction(self.document_id, transaction);
rx.recv().unwrap();
let renderer = self.renderer.as_mut().unwrap();
renderer.update();
renderer.render(self.size).unwrap();
let _ = renderer.flush_pipeline_info();
self.visual.present();
}
}
impl Drop for Rectangle {
fn drop(&mut self) {
self.renderer.take().unwrap().deinit()
}
}
#[derive(Clone)]
struct Notifier {
events_proxy: winit::EventsLoopProxy,
tx: mpsc::Sender<()>,
}
impl api::RenderNotifier for Notifier {
fn clone(&self) -> Box<dyn api::RenderNotifier> {
Box::new(Clone::clone(self))
}
fn wake_up(&self) {
self.tx.send(()).unwrap();
let _ = self.events_proxy.wakeup();
}
fn new_frame_ready(&self,
_: api::DocumentId,
_: bool,
_: bool,
_: Option<u64>) {
self.wake_up();
}
}

View 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"

View 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");
}

View 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, &registry_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);
}
}

View 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

View file

@ -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!()
}

View file

@ -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" }

View file

@ -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;

View file

@ -26,10 +26,6 @@ path = "blob.rs"
name = "document"
path = "document.rs"
[[bin]]
name = "frame_output"
path = "frame_output.rs"
[[bin]]
name = "iframe"
path = "iframe.rs"
@ -55,13 +51,13 @@ name = "yuv"
path = "yuv.rs"
[features]
debug = ["webrender/capture", "webrender/debugger", "webrender/profiler"]
debug = ["webrender/capture", "webrender/profiler"]
[dependencies]
app_units = "0.7"
env_logger = "0.5"
euclid = "0.22"
gleam = "0.12"
gleam = "0.15"
glutin = "0.21"
rayon = "1"
webrender = { path = "../webrender" }

View file

@ -2,11 +2,11 @@
* 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 euclid;
use gleam;
use glutin;
use webrender;
use winit;
extern crate euclid;
extern crate gleam;
extern crate glutin;
extern crate webrender;
extern crate winit;
#[path = "common/boilerplate.rs"]
mod boilerplate;
@ -14,6 +14,7 @@ mod boilerplate;
use crate::boilerplate::{Example, HandyDandyRectBuilder};
use std::cmp;
use webrender::api::*;
use webrender::render_api::*;
use webrender::api::units::DeviceIntSize;

View file

@ -10,11 +10,11 @@
//! rounded cornered rectangle, which is done automatically during the
//! scene building for render optimization.
use euclid;
use gleam;
use glutin;
use webrender;
use winit;
extern crate euclid;
extern crate gleam;
extern crate glutin;
extern crate webrender;
extern crate winit;
#[path = "common/boilerplate.rs"]
mod boilerplate;
@ -22,6 +22,7 @@ mod boilerplate;
use crate::boilerplate::{Example, HandyDandyRectBuilder};
use euclid::Angle;
use webrender::api::*;
use webrender::render_api::*;
use webrender::api::units::*;
@ -62,7 +63,10 @@ impl App {
SpatialId::root_scroll_node(pipeline_id),
TransformStyle::Flat,
PropertyBinding::Binding(property_key, LayoutTransform::identity()),
ReferenceFrameKind::Transform,
ReferenceFrameKind::Transform {
is_2d_scale_translation: false,
should_snap: false,
},
);
builder.push_simple_stacking_context_with_filters(
@ -194,7 +198,7 @@ impl Example for App {
colors: vec![],
},
);
txn.generate_frame();
txn.generate_frame(0);
api.send_transaction(document_id, txn);
}
_ => (),

View file

@ -2,11 +2,11 @@
* 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 euclid;
use gleam;
use glutin;
use webrender;
use winit;
extern crate euclid;
extern crate gleam;
extern crate glutin;
extern crate webrender;
extern crate winit;
#[path = "common/boilerplate.rs"]
mod boilerplate;
@ -17,6 +17,7 @@ use winit::TouchPhase;
use std::collections::HashMap;
use webrender::ShaderPrecacheFlags;
use webrender::api::*;
use webrender::render_api::*;
use webrender::api::units::*;
@ -190,7 +191,7 @@ impl Example for App {
pipeline_id: PipelineId,
_document_id: DocumentId,
) {
let content_bounds = LayoutRect::new(LayoutPoint::zero(), builder.content_size());
let content_bounds = LayoutRect::new(LayoutPoint::zero(), LayoutSize::new(800.0, 600.0));
let root_space_and_clip = SpaceAndClipInfo::root_scroll(pipeline_id);
let spatial_id = root_space_and_clip.spatial_id;
@ -220,6 +221,8 @@ impl Example for App {
let mask_clip_id = builder.define_clip_image_mask(
&root_space_and_clip,
mask,
&vec![],
FillRule::Nonzero,
);
let clip_id = builder.define_clip_rounded_rect(
&SpaceAndClipInfo {
@ -312,7 +315,7 @@ impl Example for App {
}
if !txn.is_empty() {
txn.generate_frame();
txn.generate_frame(0);
api.send_transaction(document_id, txn);
}

View file

@ -2,11 +2,11 @@
* 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 gleam;
use glutin;
use rayon;
use webrender;
use winit;
extern crate gleam;
extern crate glutin;
extern crate rayon;
extern crate webrender;
extern crate winit;
#[path = "common/boilerplate.rs"]
mod boilerplate;
@ -16,9 +16,10 @@ use rayon::{ThreadPool, ThreadPoolBuilder};
use rayon::prelude::*;
use std::collections::HashMap;
use std::sync::Arc;
use webrender::api::{self, DisplayListBuilder, DocumentId, PipelineId, PrimitiveFlags, RenderApi, Transaction};
use webrender::api::{self, DisplayListBuilder, DocumentId, PipelineId, PrimitiveFlags};
use webrender::api::{ColorF, CommonItemProperties, SpaceAndClipInfo, ImageDescriptorFlags};
use webrender::api::units::*;
use webrender::render_api::*;
use webrender::euclid::size2;
// This example shows how to implement a very basic BlobImageHandler that can only render

View file

@ -10,6 +10,7 @@ use webrender;
use winit;
use webrender::{DebugFlags, ShaderPrecacheFlags};
use webrender::api::*;
use webrender::render_api::*;
use webrender::api::units::*;
struct Notifier {
@ -29,7 +30,7 @@ impl RenderNotifier for Notifier {
})
}
fn wake_up(&self) {
fn wake_up(&self, _composite_needed: bool) {
#[cfg(not(target_os = "android"))]
let _ = self.events_proxy.wakeup();
}
@ -37,9 +38,9 @@ impl RenderNotifier for Notifier {
fn new_frame_ready(&self,
_: DocumentId,
_scrolled: bool,
_composite_needed: bool,
composite_needed: bool,
_render_time: Option<u64>) {
self.wake_up();
self.wake_up(composite_needed);
}
}
@ -88,12 +89,11 @@ pub trait Example {
) -> bool {
false
}
fn get_image_handlers(
fn get_image_handler(
&mut self,
_gl: &dyn gl::Gl,
) -> (Option<Box<dyn ExternalImageHandler>>,
Option<Box<dyn OutputImageHandler>>) {
(None, None)
) -> Option<Box<dyn ExternalImageHandler>> {
None
}
fn draw_custom(&mut self, _gl: &dyn gl::Gl) {
}
@ -183,16 +183,11 @@ pub fn main_wrapper<E: Example>(
notifier,
opts,
None,
device_size,
).unwrap();
let mut api = sender.create_api();
let document_id = api.add_document(device_size, 0);
let document_id = api.add_document(device_size);
let (external, output) = example.get_image_handlers(&*gl);
if let Some(output_image_handler) = output {
renderer.set_output_image_handler(output_image_handler);
}
let external = example.get_image_handler(&*gl);
if let Some(external_image_handler) = external {
renderer.set_external_image_handler(external_image_handler);
@ -201,7 +196,7 @@ pub fn main_wrapper<E: Example>(
let epoch = Epoch(0);
let pipeline_id = PipelineId(0, 0);
let layout_size = device_size.to_f32() / euclid::Scale::new(device_pixel_ratio);
let mut builder = DisplayListBuilder::new(pipeline_id, layout_size);
let mut builder = DisplayListBuilder::new(pipeline_id);
let mut txn = Transaction::new();
example.render(
@ -220,7 +215,7 @@ pub fn main_wrapper<E: Example>(
true,
);
txn.set_root_pipeline(pipeline_id);
txn.generate_frame();
txn.generate_frame(0);
api.send_transaction(document_id, txn);
println!("Entering event loop");
@ -259,14 +254,10 @@ pub fn main_wrapper<E: Example>(
winit::VirtualKeyCode::P => debug_flags.toggle(DebugFlags::PROFILER_DBG),
winit::VirtualKeyCode::O => debug_flags.toggle(DebugFlags::RENDER_TARGET_DBG),
winit::VirtualKeyCode::I => debug_flags.toggle(DebugFlags::TEXTURE_CACHE_DBG),
winit::VirtualKeyCode::S => debug_flags.toggle(DebugFlags::COMPACT_PROFILER),
winit::VirtualKeyCode::T => debug_flags.toggle(DebugFlags::PICTURE_CACHING_DBG),
winit::VirtualKeyCode::Q => debug_flags.toggle(
DebugFlags::GPU_TIME_QUERIES | DebugFlags::GPU_SAMPLE_QUERIES
),
winit::VirtualKeyCode::F => debug_flags.toggle(
DebugFlags::NEW_FRAME_INDICATOR | DebugFlags::NEW_SCENE_INDICATOR
),
winit::VirtualKeyCode::G => debug_flags.toggle(DebugFlags::GPU_CACHE_DBG),
winit::VirtualKeyCode::Key1 => txn.set_document_view(
device_size.into(),
@ -304,7 +295,7 @@ pub fn main_wrapper<E: Example>(
}
if custom_event {
let mut builder = DisplayListBuilder::new(pipeline_id, layout_size);
let mut builder = DisplayListBuilder::new(pipeline_id);
example.render(
&mut api,
@ -321,12 +312,12 @@ pub fn main_wrapper<E: Example>(
builder.finalize(),
true,
);
txn.generate_frame();
txn.generate_frame(0);
}
api.send_transaction(document_id, txn);
renderer.update();
renderer.render(device_size).unwrap();
renderer.render(device_size, 0).unwrap();
let _ = renderer.flush_pipeline_info();
example.draw_custom(&*gl);
windowed_context.swap_buffers().ok();

View file

@ -2,11 +2,11 @@
* 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 euclid;
use gleam;
use glutin;
use webrender;
use winit;
extern crate euclid;
extern crate gleam;
extern crate glutin;
extern crate webrender;
extern crate winit;
#[path = "common/boilerplate.rs"]
mod boilerplate;
@ -14,6 +14,7 @@ mod boilerplate;
use crate::boilerplate::Example;
use euclid::Scale;
use webrender::api::*;
use webrender::render_api::*;
use webrender::api::units::*;
// This example creates multiple documents overlapping each other with
@ -39,35 +40,31 @@ impl App {
let init_data = vec![
(
PipelineId(1, 0),
-2,
ColorF::new(0.0, 1.0, 0.0, 1.0),
DeviceIntPoint::new(0, 0),
),
(
PipelineId(2, 0),
-1,
ColorF::new(1.0, 1.0, 0.0, 1.0),
DeviceIntPoint::new(200, 0),
),
(
PipelineId(3, 0),
0,
ColorF::new(1.0, 0.0, 0.0, 1.0),
DeviceIntPoint::new(200, 200),
),
(
PipelineId(4, 0),
1,
ColorF::new(1.0, 0.0, 1.0, 1.0),
DeviceIntPoint::new(0, 200),
),
];
for (pipeline_id, layer, color, offset) in init_data {
for (pipeline_id, color, offset) in init_data {
let size = DeviceIntSize::new(250, 250);
let bounds = DeviceIntRect::new(offset, size);
let document_id = api.add_document(size, layer);
let document_id = api.add_document(size);
let mut txn = Transaction::new();
txn.set_document_view(bounds, device_pixel_ratio);
txn.set_root_pipeline(pipeline_id);
@ -90,25 +87,22 @@ impl Example for App {
fn render(
&mut self,
api: &mut RenderApi,
base_builder: &mut DisplayListBuilder,
_base_builder: &mut DisplayListBuilder,
_txn: &mut Transaction,
device_size: DeviceIntSize,
_device_size: DeviceIntSize,
_pipeline_id: PipelineId,
_: DocumentId,
) {
if self.documents.is_empty() {
let device_pixel_ratio = device_size.width as f32 /
base_builder.content_size().width;
// this is the first run, hack around the boilerplate,
// which assumes an example only needs one document
self.init(api, device_pixel_ratio);
self.init(api, 1.0);
}
for doc in &self.documents {
let space_and_clip = SpaceAndClipInfo::root_scroll(doc.pipeline_id);
let mut builder = DisplayListBuilder::new(
doc.pipeline_id,
doc.content_rect.size,
);
let local_rect = LayoutRect::new(
LayoutPoint::zero(),
@ -135,7 +129,7 @@ impl Example for App {
builder.finalize(),
true,
);
txn.generate_frame();
txn.generate_frame(0);
api.send_transaction(doc.id, txn);
}
}

View file

@ -1,238 +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 euclid;
use gleam;
use glutin;
use webrender;
use winit;
#[path = "common/boilerplate.rs"]
mod boilerplate;
use crate::boilerplate::{Example, HandyDandyRectBuilder};
use euclid::Scale;
use gleam::gl;
use webrender::api::*;
use webrender::api::units::*;
// This example demonstrates using the frame output feature to copy
// the output of a WR framebuffer to a custom texture.
#[derive(Debug)]
struct Document {
id: DocumentId,
pipeline_id: PipelineId,
content_rect: LayoutRect,
color: ColorF,
}
struct App {
external_image_key: Option<ImageKey>,
output_document: Option<Document>
}
struct OutputHandler {
texture_id: gl::GLuint
}
struct ExternalHandler {
texture_id: gl::GLuint
}
impl OutputImageHandler for OutputHandler {
fn lock(&mut self, _id: PipelineId) -> Option<(u32, FramebufferIntSize)> {
Some((self.texture_id, FramebufferIntSize::new(500, 500)))
}
fn unlock(&mut self, _id: PipelineId) {}
}
impl ExternalImageHandler for ExternalHandler {
fn lock(
&mut self,
_key: ExternalImageId,
_channel_index: u8,
_rendering: ImageRendering
) -> ExternalImage {
ExternalImage {
uv: TexelRect::new(0.0, 0.0, 1.0, 1.0),
source: ExternalImageSource::NativeTexture(self.texture_id),
}
}
fn unlock(&mut self, _key: ExternalImageId, _channel_index: u8) {}
}
impl App {
fn init_output_document(
&mut self,
api: &mut RenderApi,
device_size: DeviceIntSize,
device_pixel_ratio: f32,
) {
// Generate the external image key that will be used to render the output document to the root document.
self.external_image_key = Some(api.generate_image_key());
let pipeline_id = PipelineId(1, 0);
let layer = 1;
let color = ColorF::new(1., 1., 0., 1.);
let document_id = api.add_document(device_size, layer);
api.enable_frame_output(document_id, pipeline_id, true);
api.set_document_view(
document_id,
device_size.into(),
device_pixel_ratio,
);
let document = Document {
id: document_id,
pipeline_id,
content_rect: LayoutRect::new(
LayoutPoint::zero(),
device_size.to_f32() / Scale::new(device_pixel_ratio),
),
color,
};
let mut txn = Transaction::new();
txn.add_image(
self.external_image_key.unwrap(),
ImageDescriptor::new(100, 100, ImageFormat::BGRA8, ImageDescriptorFlags::IS_OPAQUE),
ImageData::External(ExternalImageData {
id: ExternalImageId(0),
channel_index: 0,
image_type: ExternalImageType::TextureHandle(TextureTarget::Default),
}),
None,
);
let space_and_clip = SpaceAndClipInfo::root_scroll(pipeline_id);
let mut builder = DisplayListBuilder::new(
document.pipeline_id,
document.content_rect.size,
);
builder.push_simple_stacking_context(
document.content_rect.origin,
space_and_clip.spatial_id,
PrimitiveFlags::IS_BACKFACE_VISIBLE,
);
builder.push_rect(
&CommonItemProperties::new(document.content_rect, space_and_clip),
document.content_rect,
ColorF::new(1.0, 1.0, 0.0, 1.0)
);
builder.pop_stacking_context();
txn.set_root_pipeline(pipeline_id);
txn.set_display_list(
Epoch(0),
Some(document.color),
document.content_rect.size,
builder.finalize(),
true,
);
txn.generate_frame();
api.send_transaction(document.id, txn);
self.output_document = Some(document);
}
}
impl Example for App {
fn render(
&mut self,
api: &mut RenderApi,
builder: &mut DisplayListBuilder,
_txn: &mut Transaction,
device_size: DeviceIntSize,
pipeline_id: PipelineId,
_document_id: DocumentId,
) {
if self.output_document.is_none() {
let device_pixel_ratio = device_size.width as f32 /
builder.content_size().width;
self.init_output_document(api, DeviceIntSize::new(200, 200), device_pixel_ratio);
}
let bounds = (100, 100).to(200, 200);
let space_and_clip = SpaceAndClipInfo::root_scroll(pipeline_id);
builder.push_simple_stacking_context(
bounds.origin,
space_and_clip.spatial_id,
PrimitiveFlags::IS_BACKFACE_VISIBLE,
);
builder.push_image(
&CommonItemProperties::new(bounds, space_and_clip),
bounds,
ImageRendering::Auto,
AlphaType::PremultipliedAlpha,
self.external_image_key.unwrap(),
ColorF::WHITE,
);
builder.pop_stacking_context();
}
fn get_image_handlers(
&mut self,
gl: &dyn gl::Gl,
) -> (Option<Box<dyn ExternalImageHandler>>,
Option<Box<dyn OutputImageHandler>>) {
let texture_id = gl.gen_textures(1)[0];
gl.bind_texture(gl::TEXTURE_2D, texture_id);
gl.tex_parameter_i(
gl::TEXTURE_2D,
gl::TEXTURE_MAG_FILTER,
gl::LINEAR as gl::GLint,
);
gl.tex_parameter_i(
gl::TEXTURE_2D,
gl::TEXTURE_MIN_FILTER,
gl::LINEAR as gl::GLint,
);
gl.tex_parameter_i(
gl::TEXTURE_2D,
gl::TEXTURE_WRAP_S,
gl::CLAMP_TO_EDGE as gl::GLint,
);
gl.tex_parameter_i(
gl::TEXTURE_2D,
gl::TEXTURE_WRAP_T,
gl::CLAMP_TO_EDGE as gl::GLint,
);
gl.tex_image_2d(
gl::TEXTURE_2D,
0,
gl::RGBA as gl::GLint,
100,
100,
0,
gl::BGRA,
gl::UNSIGNED_BYTE,
None,
);
gl.bind_texture(gl::TEXTURE_2D, 0);
(
Some(Box::new(ExternalHandler { texture_id })),
Some(Box::new(OutputHandler { texture_id }))
)
}
}
fn main() {
let mut app = App {
external_image_key: None,
output_document: None
};
boilerplate::main_wrapper(&mut app, None);
}

View file

@ -2,16 +2,17 @@
* 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 gleam;
use glutin;
use webrender;
use winit;
extern crate gleam;
extern crate glutin;
extern crate webrender;
extern crate winit;
#[path = "common/boilerplate.rs"]
mod boilerplate;
use crate::boilerplate::{Example, HandyDandyRectBuilder};
use webrender::api::*;
use webrender::render_api::*;
use webrender::api::units::*;
// This example uses the push_iframe API to nest a second pipeline's displaylist
@ -35,7 +36,7 @@ impl Example for App {
let sub_bounds = (0, 0).to(sub_size.width as i32, sub_size.height as i32);
let sub_pipeline_id = PipelineId(pipeline_id.0, 42);
let mut sub_builder = DisplayListBuilder::new(sub_pipeline_id, sub_bounds.size);
let mut sub_builder = DisplayListBuilder::new(sub_pipeline_id);
let mut space_and_clip = SpaceAndClipInfo::root_scroll(pipeline_id);
sub_builder.push_simple_stacking_context(
@ -67,7 +68,10 @@ impl Example for App {
space_and_clip.spatial_id,
TransformStyle::Flat,
PropertyBinding::Binding(PropertyBindingKey::new(42), LayoutTransform::identity()),
ReferenceFrameKind::Transform,
ReferenceFrameKind::Transform {
is_2d_scale_translation: false,
should_snap: false,
},
);
// And this is for the root pipeline

View file

@ -2,10 +2,10 @@
* 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 gleam;
use glutin;
use webrender;
use winit;
extern crate gleam;
extern crate glutin;
extern crate webrender;
extern crate winit;
#[path = "common/boilerplate.rs"]
mod boilerplate;
@ -14,6 +14,7 @@ mod image_helper;
use crate::boilerplate::{Example, HandyDandyRectBuilder};
use webrender::api::*;
use webrender::render_api::*;
use webrender::api::units::*;
struct App {
@ -103,7 +104,7 @@ impl Example for App {
&DirtyRect::All,
);
let mut txn = Transaction::new();
txn.generate_frame();
txn.generate_frame(0);
api.send_transaction(document_id, txn);
}
_ => {}

View file

@ -2,11 +2,11 @@
* 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 euclid;
use gleam;
use glutin;
use webrender;
use winit;
extern crate euclid;
extern crate gleam;
extern crate glutin;
extern crate webrender;
extern crate winit;
use gleam::gl;
use glutin::NotCurrent;
@ -14,6 +14,7 @@ use std::fs::File;
use std::io::Read;
use webrender::api::*;
use webrender::api::units::*;
use webrender::render_api::*;
use webrender::DebugFlags;
use winit::dpi::LogicalSize;
@ -34,7 +35,7 @@ impl RenderNotifier for Notifier {
})
}
fn wake_up(&self) {
fn wake_up(&self, _composite_needed: bool) {
#[cfg(not(target_os = "android"))]
let _ = self.events_proxy.wakeup();
}
@ -42,9 +43,9 @@ impl RenderNotifier for Notifier {
fn new_frame_ready(&self,
_: DocumentId,
_scrolled: bool,
_composite_needed: bool,
composite_needed: bool,
_render_time: Option<u64>) {
self.wake_up();
self.wake_up(composite_needed);
}
}
@ -104,9 +105,9 @@ impl Window {
DeviceIntSize::new(size.width as i32, size.height as i32)
};
let notifier = Box::new(Notifier::new(events_loop.create_proxy()));
let (renderer, sender) = webrender::Renderer::new(gl.clone(), notifier, opts, None, device_size).unwrap();
let (renderer, sender) = webrender::Renderer::new(gl.clone(), notifier, opts, None).unwrap();
let mut api = sender.create_api();
let document_id = api.add_document(device_size, 0);
let document_id = api.add_document(device_size);
let epoch = Epoch(0);
let pipeline_id = PipelineId(0, 0);
@ -183,10 +184,10 @@ impl Window {
};
let layout_size = device_size.to_f32() / euclid::Scale::new(device_pixel_ratio);
let mut txn = Transaction::new();
let mut builder = DisplayListBuilder::new(self.pipeline_id, layout_size);
let mut builder = DisplayListBuilder::new(self.pipeline_id);
let space_and_clip = SpaceAndClipInfo::root_scroll(self.pipeline_id);
let bounds = LayoutRect::new(LayoutPoint::zero(), builder.content_size());
let bounds = LayoutRect::new(LayoutPoint::zero(), layout_size);
builder.push_simple_stacking_context(
bounds.origin,
space_and_clip.spatial_id,
@ -284,11 +285,11 @@ impl Window {
true,
);
txn.set_root_pipeline(self.pipeline_id);
txn.generate_frame();
txn.generate_frame(0);
api.send_transaction(self.document_id, txn);
renderer.update();
renderer.render(device_size).unwrap();
renderer.render(device_size, 0).unwrap();
context.swap_buffers().ok();
self.context = Some(unsafe { context.make_not_current().unwrap() });

View file

@ -2,11 +2,11 @@
* 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 euclid;
use gleam;
use glutin;
use webrender;
use winit;
extern crate euclid;
extern crate gleam;
extern crate glutin;
extern crate webrender;
extern crate winit;
#[path = "common/boilerplate.rs"]
mod boilerplate;
@ -14,12 +14,17 @@ mod boilerplate;
use crate::boilerplate::{Example, HandyDandyRectBuilder};
use euclid::SideOffsets2D;
use webrender::api::*;
use webrender::render_api::*;
use webrender::api::units::*;
use winit::dpi::LogicalPosition;
const EXT_SCROLL_ID_ROOT: u64 = 1;
const EXT_SCROLL_ID_CONTENT: u64 = 2;
struct App {
cursor_position: WorldPoint,
scroll_origin: LayoutPoint,
}
impl Example for App {
@ -51,7 +56,7 @@ impl Example for App {
// set the scrolling clip
let space_and_clip1 = builder.define_scroll_frame(
&root_space_and_clip,
None,
ExternalScrollId(EXT_SCROLL_ID_ROOT, PipelineId::dummy()),
(0, 0).by(1000, 1000),
scrollbox,
ScrollSensitivity::ScriptAndInputEvents,
@ -60,22 +65,22 @@ impl Example for App {
// now put some content into it.
// start with a white background
let mut info = CommonItemProperties::new((0, 0).to(1000, 1000), space_and_clip1);
info.hit_info = Some((0, 1));
let info = CommonItemProperties::new((0, 0).to(1000, 1000), space_and_clip1);
builder.push_hit_test(&info, (0, 1));
builder.push_rect(&info, info.clip_rect, ColorF::new(1.0, 1.0, 1.0, 1.0));
// let's make a 50x50 blue square as a visual reference
let mut info = CommonItemProperties::new((0, 0).to(50, 50), space_and_clip1);
info.hit_info = Some((0, 2));
let info = CommonItemProperties::new((0, 0).to(50, 50), space_and_clip1);
builder.push_hit_test(&info, (0, 2));
builder.push_rect(&info, info.clip_rect, ColorF::new(0.0, 0.0, 1.0, 1.0));
// and a 50x50 green square next to it with an offset clip
// to see what that looks like
let mut info = CommonItemProperties::new(
let info = CommonItemProperties::new(
(50, 0).to(100, 50).intersection(&(60, 10).to(110, 60)).unwrap(),
space_and_clip1,
);
info.hit_info = Some((0, 3));
builder.push_hit_test(&info, (0, 3));
builder.push_rect(&info, info.clip_rect, ColorF::new(0.0, 1.0, 0.0, 1.0));
// Below the above rectangles, set up a nested scrollbox. It's still in
@ -83,7 +88,7 @@ impl Example for App {
// be relative to the stacking context.
let space_and_clip2 = builder.define_scroll_frame(
&space_and_clip1,
None,
ExternalScrollId(EXT_SCROLL_ID_CONTENT, PipelineId::dummy()),
(0, 100).to(300, 1000),
(0, 100).to(200, 300),
ScrollSensitivity::ScriptAndInputEvents,
@ -92,17 +97,17 @@ impl Example for App {
// give it a giant gray background just to distinguish it and to easily
// visually identify the nested scrollbox
let mut info = CommonItemProperties::new(
let info = CommonItemProperties::new(
(-1000, -1000).to(5000, 5000),
space_and_clip2,
);
info.hit_info = Some((0, 4));
builder.push_hit_test(&info, (0, 4));
builder.push_rect(&info, info.clip_rect, ColorF::new(0.5, 0.5, 0.5, 1.0));
// add a teal square to visualize the scrolling/clipping behaviour
// as you scroll the nested scrollbox
let mut info = CommonItemProperties::new((0, 200).to(50, 250), space_and_clip2);
info.hit_info = Some((0, 5));
let info = CommonItemProperties::new((0, 200).to(50, 250), space_and_clip2);
builder.push_hit_test(&info, (0, 5));
builder.push_rect(&info, info.clip_rect, ColorF::new(0.0, 1.0, 1.0, 1.0));
// Add a sticky frame. It will "stick" twice while scrolling, once
@ -118,14 +123,14 @@ impl Example for App {
LayoutVector2D::new(0.0, 0.0)
);
let mut info = CommonItemProperties::new(
let info = CommonItemProperties::new(
(50, 350).by(50, 50),
SpaceAndClipInfo {
spatial_id: sticky_id,
clip_id: space_and_clip2.clip_id,
},
);
info.hit_info = Some((0, 6));
builder.push_hit_test(&info, (0, 6));
builder.push_rect(
&info,
info.clip_rect,
@ -134,11 +139,11 @@ impl Example for App {
// just for good measure add another teal square further down and to
// the right, which can be scrolled into view by the user
let mut info = CommonItemProperties::new(
let info = CommonItemProperties::new(
(250, 350).to(300, 400),
space_and_clip2,
);
info.hit_info = Some((0, 7));
builder.push_hit_test(&info, (0, 7));
builder.push_rect(&info, info.clip_rect, ColorF::new(0.0, 1.0, 1.0, 1.0));
builder.pop_stacking_context();
@ -159,10 +164,10 @@ impl Example for App {
..
} => {
let offset = match key {
winit::VirtualKeyCode::Down => Some((0.0, -10.0)),
winit::VirtualKeyCode::Up => Some((0.0, 10.0)),
winit::VirtualKeyCode::Right => Some((-10.0, 0.0)),
winit::VirtualKeyCode::Left => Some((10.0, 0.0)),
winit::VirtualKeyCode::Down => Some(LayoutVector2D::new(0.0, -10.0)),
winit::VirtualKeyCode::Up => Some(LayoutVector2D::new(0.0, 10.0)),
winit::VirtualKeyCode::Right => Some(LayoutVector2D::new(-10.0, 0.0)),
winit::VirtualKeyCode::Left => Some(LayoutVector2D::new(10.0, 0.0)),
_ => None,
};
let zoom = match key {
@ -173,15 +178,18 @@ impl Example for App {
};
if let Some(offset) = offset {
txn.scroll(
ScrollLocation::Delta(LayoutVector2D::new(offset.0, offset.1)),
self.cursor_position,
self.scroll_origin += offset;
txn.scroll_node_with_id(
self.scroll_origin,
ExternalScrollId(EXT_SCROLL_ID_CONTENT, PipelineId::dummy()),
ScrollClamping::ToContentBounds,
);
txn.generate_frame();
txn.generate_frame(0);
}
if let Some(zoom) = zoom {
txn.set_pinch_zoom(ZoomFactor::new(zoom));
txn.generate_frame();
txn.generate_frame(0);
}
}
winit::WindowEvent::CursorMoved { position: LogicalPosition { x, y }, .. } => {
@ -194,18 +202,21 @@ impl Example for App {
winit::MouseScrollDelta::PixelDelta(pos) => (pos.x as f32, pos.y as f32),
};
txn.scroll(
ScrollLocation::Delta(LayoutVector2D::new(dx, dy)),
self.cursor_position,
self.scroll_origin += LayoutVector2D::new(dx, dy);
txn.scroll_node_with_id(
self.scroll_origin,
ExternalScrollId(EXT_SCROLL_ID_CONTENT, PipelineId::dummy()),
ScrollClamping::ToContentBounds,
);
txn.generate_frame();
txn.generate_frame(0);
}
winit::WindowEvent::MouseInput { .. } => {
let results = api.hit_test(
document_id,
None,
self.cursor_position,
HitTestFlags::FIND_ALL
);
println!("Hit test results:");
@ -226,6 +237,7 @@ impl Example for App {
fn main() {
let mut app = App {
cursor_position: WorldPoint::zero(),
scroll_origin: LayoutPoint::zero(),
};
boilerplate::main_wrapper(&mut app, None);
}

View file

@ -2,10 +2,10 @@
* 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 gleam;
use glutin;
use webrender;
use winit;
extern crate gleam;
extern crate glutin;
extern crate webrender;
extern crate winit;
#[path = "common/boilerplate.rs"]
mod boilerplate;
@ -14,6 +14,7 @@ use crate::boilerplate::{Example, HandyDandyRectBuilder};
use gleam::gl;
use std::mem;
use webrender::api::*;
use webrender::render_api::*;
use webrender::api::units::*;
@ -301,12 +302,11 @@ impl Example for App {
false
}
fn get_image_handlers(
fn get_image_handler(
&mut self,
_gl: &dyn gl::Gl,
) -> (Option<Box<dyn ExternalImageHandler>>,
Option<Box<dyn OutputImageHandler>>) {
(Some(Box::new(ImageGenerator::new())), None)
) -> Option<Box<dyn ExternalImageHandler>> {
Some(Box::new(ImageGenerator::new()))
}
}

View file

@ -2,10 +2,10 @@
* 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 gleam;
use glutin;
use webrender;
use winit;
extern crate gleam;
extern crate glutin;
extern crate webrender;
extern crate winit;
#[path = "common/boilerplate.rs"]
mod boilerplate;
@ -13,6 +13,7 @@ mod boilerplate;
use crate::boilerplate::Example;
use gleam::gl;
use webrender::api::*;
use webrender::render_api::*;
use webrender::api::units::*;
@ -93,7 +94,7 @@ impl Example for App {
pipeline_id: PipelineId,
_document_id: DocumentId,
) {
let bounds = LayoutRect::new(LayoutPoint::zero(), builder.content_size());
let bounds = LayoutRect::new(LayoutPoint::zero(), LayoutSize::new(500.0, 500.0));
let space_and_clip = SpaceAndClipInfo::root_scroll(pipeline_id);
builder.push_simple_stacking_context(
@ -113,7 +114,7 @@ impl Example for App {
id: ExternalImageId(0),
channel_index: 0,
image_type: ExternalImageType::TextureHandle(
TextureTarget::Default,
ImageBufferKind::Texture2D,
),
}),
None,
@ -125,7 +126,7 @@ impl Example for App {
id: ExternalImageId(1),
channel_index: 0,
image_type: ExternalImageType::TextureHandle(
TextureTarget::Default,
ImageBufferKind::Texture2D,
),
}),
None,
@ -137,7 +138,7 @@ impl Example for App {
id: ExternalImageId(2),
channel_index: 0,
image_type: ExternalImageType::TextureHandle(
TextureTarget::Default,
ImageBufferKind::Texture2D,
),
}),
None,
@ -149,7 +150,7 @@ impl Example for App {
id: ExternalImageId(3),
channel_index: 0,
image_type: ExternalImageType::TextureHandle(
TextureTarget::Default,
ImageBufferKind::Texture2D,
),
}),
None,
@ -195,14 +196,13 @@ impl Example for App {
false
}
fn get_image_handlers(
fn get_image_handler(
&mut self,
gl: &dyn gl::Gl,
) -> (Option<Box<dyn ExternalImageHandler>>,
Option<Box<dyn OutputImageHandler>>) {
) -> Option<Box<dyn ExternalImageHandler>> {
let provider = YuvImageProvider::new(gl);
self.texture_id = provider.texture_ids[0];
(Some(Box::new(provider)), None)
Some(Box::new(provider))
}
fn draw_custom(&mut self, gl: &dyn gl::Gl) {
@ -218,7 +218,6 @@ fn main() {
};
let opts = webrender::RendererOptions {
debug_flags: webrender::DebugFlags::NEW_FRAME_INDICATOR | webrender::DebugFlags::NEW_SCENE_INDICATOR,
..Default::default()
};

View file

@ -2,7 +2,7 @@
name = "glsl-to-cxx"
version = "0.1.0"
license = "MPL-2.0"
authors = ["The Mozilla Project Developers"]
authors = ["The Mozilla Project Developers", "Dimitri Sabadie"]
edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

View file

@ -1,3 +1,21 @@
A GLSL to C++ translator.
Translates GLSL to vectorized C++. Intended for use with WebRender software backend.
Architecture
------------
GLSL code is parsed by the glsl crate. In hir.rs we traverse the resulting AST
and build a higher level representation by doing type checking and name
resolution. The resulting hir tree is traversed by lib.rs to output C++ code.
The generated C++ code is 4x wider then the original glsl. i.e. a glsl 'float'
becomes a C++ 'Float' which is represented by a xmm register (a vector of 4 floats).
Likewise, a vec4 becomes a struct of 4 'Float's for a total of 4 xmm registers and
16 floating point values.
Vector branching is flattened to non-branching code that unconditionally runs both
sides of the branch and combines the results with a mask based on the condition.
The compiler also supports scalarization. Values that are known to be the same
across all vector lanes are translated to scalars instead of vectors. Branches on
scalars are translated as actual branches.

File diff suppressed because it is too large Load diff

View file

@ -2,7 +2,7 @@
* 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 glsl;
extern crate glsl;
mod hir;
@ -61,8 +61,6 @@ pub fn translate(args: &mut dyn Iterator<Item = String>) -> String {
.to_string_lossy()
.to_string();
let frag_include = args.next();
let (vs_state, vs_hir, vs_is_frag) = parse_shader(vertex_file);
let (fs_state, fs_hir, fs_is_frag) = parse_shader(frag_file);
@ -79,7 +77,6 @@ pub fn translate(args: &mut dyn Iterator<Item = String>) -> String {
vs_hir,
vs_is_frag,
&uniform_indices,
None,
);
result += "\n";
result += &translate_shader(
@ -88,7 +85,6 @@ pub fn translate(args: &mut dyn Iterator<Item = String>) -> String {
fs_hir,
fs_is_frag,
&uniform_indices,
frag_include,
);
result
}
@ -120,7 +116,6 @@ fn translate_shader(
hir: hir::TranslationUnit,
is_frag: bool,
uniform_indices: &UniformIndices,
include_file: Option<String>,
) -> String {
//println!("{:#?}", state);
@ -185,8 +180,6 @@ fn translate_shader(
uses_discard: false,
used_fragcoord: Cell::new(0),
use_perspective: false,
has_draw_span_rgba8: false,
has_draw_span_r8: false,
used_globals: RefCell::new(Vec::new()),
texel_fetches: RefCell::new(Vec::new()),
};
@ -215,10 +208,6 @@ fn translate_shader(
show_translation_unit(&mut state, &hir);
if let Some(include_file) = include_file {
write_include_file(&mut state, include_file);
}
let pruned_inputs: Vec<_> = inputs
.iter()
.filter(|i| state.used_globals.borrow().contains(i))
@ -250,6 +239,7 @@ fn translate_shader(
write!(state, " return this;\n}}\n");
write!(state, "FragmentShaderImpl* get_fragment_shader() override {{\n");
write!(state, " return this;\n}}\n");
write!(state, "const char* get_name() const override {{ return \"{}\"; }}\n", name);
write!(state, "static ProgramImpl* loader() {{ return new {}_program; }}\n", name);
write!(state, "}};\n\n");
}
@ -302,8 +292,7 @@ fn write_program_samplers(state: &mut OutputState, uniform_indices: &UniformIndi
match tk {
hir::TypeKind::Sampler2D
| hir::TypeKind::Sampler2DRect
| hir::TypeKind::ISampler2D
| hir::TypeKind::Sampler2DArray => {
| hir::TypeKind::ISampler2D => {
write!(state, " ");
show_type_kind(state, &tk);
let suffix = if let hir::StorageClass::Sampler(format) = storage {
@ -326,8 +315,7 @@ fn write_program_samplers(state: &mut OutputState, uniform_indices: &UniformIndi
match tk {
hir::TypeKind::Sampler2D
| hir::TypeKind::Sampler2DRect
| hir::TypeKind::ISampler2D
| hir::TypeKind::Sampler2DArray => {
| hir::TypeKind::ISampler2D => {
write!(state, " case {}:\n", index);
write!(state, " {}_slot = value;\n", name);
write!(state, " return true;\n");
@ -355,9 +343,6 @@ fn write_bind_textures(state: &mut OutputState, uniforms: &UniformIndices) {
hir::TypeKind::ISampler2D => write!(state,
" {0} = lookup_isampler(&samplers.{0}_impl, samplers.{0}_slot);\n",
name),
hir::TypeKind::Sampler2DArray => write!(state,
" {0} = lookup_sampler_array(&samplers.{0}_impl, samplers.{0}_slot);\n",
name),
_ => {}
};
}
@ -408,9 +393,8 @@ fn write_set_uniform_4fv(
if float4_compatible(tk.clone()) {
write!(
state,
" self->{} = {}_scalar(value);\n",
name,
tk.glsl_primitive_type_name().unwrap(),
" self->{} = vec4_scalar::load_from_ptr(value);\n",
name
);
} else {
write!(state, " assert(0); // {}\n", name);
@ -551,6 +535,9 @@ fn write_load_attribs(state: &mut OutputState, attribs: &[hir::SymRef]) {
fn write_store_outputs(state: &mut OutputState, outputs: &[hir::SymRef]) {
let is_scalar = state.is_scalar.replace(true);
write!(state, "public:\nstruct InterpOutputs {{\n");
if state.hir.used_clip_dist != 0 {
state.write(" Float swgl_ClipDistance;\n");
}
for i in outputs {
let sym = state.hir.sym(*i);
match &sym.decl {
@ -576,6 +563,15 @@ fn write_store_outputs(state: &mut OutputState, outputs: &[hir::SymRef]) {
state,
" auto* dest = reinterpret_cast<InterpOutputs*>(dest_ptr);\n"
);
if state.hir.used_clip_dist != 0 {
for (i, comp) in "xyzw".chars().enumerate() {
if (state.hir.used_clip_dist & (1 << i)) != 0 {
write!(state, " dest->swgl_ClipDistance.{} = get_nth(gl_ClipDistance[{}], n);\n", comp, i);
} else {
write!(state, " dest->swgl_ClipDistance.{} = 0.0f;\n", comp);
}
}
}
for i in outputs {
let sym = state.hir.sym(*i);
match &sym.decl {
@ -626,7 +622,7 @@ fn write_read_inputs(state: &mut OutputState, inputs: &[hir::SymRef]) {
write!(state,
"static void read_interp_inputs(\
Self *self, const InterpInputs *init, const InterpInputs *step, float step_width) {{\n");
Self *self, const InterpInputs *init, const InterpInputs *step) {{\n");
for i in inputs {
let sym = state.hir.sym(*i);
match &sym.decl {
@ -640,7 +636,7 @@ fn write_read_inputs(state: &mut OutputState, inputs: &[hir::SymRef]) {
);
write!(
state,
" self->interp_step.{0} = step->{0} * step_width;\n",
" self->interp_step.{0} = step->{0} * 4.0f;\n",
name
);
}
@ -657,7 +653,7 @@ fn write_read_inputs(state: &mut OutputState, inputs: &[hir::SymRef]) {
if state.use_perspective {
write!(state,
"static void read_perspective_inputs(\
Self *self, const InterpInputs *init, const InterpInputs *step, float step_width) {{\n");
Self *self, const InterpInputs *init, const InterpInputs *step) {{\n");
if has_varying {
write!(state, " Float w = 1.0f / self->gl_FragCoord.w;\n");
}
@ -675,7 +671,7 @@ fn write_read_inputs(state: &mut OutputState, inputs: &[hir::SymRef]) {
write!(state, " self->{0} = self->interp_perspective.{0} * w;\n", name);
write!(
state,
" self->interp_step.{0} = step->{0} * step_width;\n",
" self->interp_step.{0} = step->{0} * 4.0f;\n",
name
);
}
@ -686,9 +682,12 @@ fn write_read_inputs(state: &mut OutputState, inputs: &[hir::SymRef]) {
write!(state, "}}\n");
}
write!(state, "ALWAYS_INLINE void step_interp_inputs() {{\n");
write!(state, "ALWAYS_INLINE void step_interp_inputs(int steps = 4) {{\n");
if (used_fragcoord & 1) != 0 {
write!(state, " step_fragcoord();\n");
write!(state, " step_fragcoord(steps);\n");
}
if !inputs.is_empty() {
write!(state, " float chunks = steps * 0.25f;\n");
}
for i in inputs {
let sym = state.hir.sym(*i);
@ -696,7 +695,7 @@ fn write_read_inputs(state: &mut OutputState, inputs: &[hir::SymRef]) {
hir::SymDecl::Global(_, _, _, run_class) => {
if *run_class != hir::RunClass::Scalar {
let name = sym.name.as_str();
write!(state, " {0} += interp_step.{0};\n", name);
write!(state, " {0} += interp_step.{0} * chunks;\n", name);
}
}
_ => panic!(),
@ -705,11 +704,14 @@ fn write_read_inputs(state: &mut OutputState, inputs: &[hir::SymRef]) {
write!(state, "}}\n");
if state.use_perspective {
write!(state, "ALWAYS_INLINE void step_perspective_inputs() {{\n");
write!(state, "ALWAYS_INLINE void step_perspective_inputs(int steps = 4) {{\n");
if (used_fragcoord & 1) != 0 {
write!(state, " step_fragcoord();\n");
write!(state, " step_fragcoord(steps);\n");
}
write!(state, " step_perspective(steps);\n");
if !inputs.is_empty() {
write!(state, " float chunks = steps * 0.25f;\n");
}
write!(state, " step_perspective();\n");
if has_varying {
write!(state, " Float w = 1.0f / gl_FragCoord.w;\n");
}
@ -719,7 +721,7 @@ fn write_read_inputs(state: &mut OutputState, inputs: &[hir::SymRef]) {
hir::SymDecl::Global(_, _, _, run_class) => {
if *run_class != hir::RunClass::Scalar {
let name = sym.name.as_str();
write!(state, " interp_perspective.{0} += interp_step.{0};\n", name);
write!(state, " interp_perspective.{0} += interp_step.{0} * chunks;\n", name);
write!(state, " {0} = w * interp_perspective.{0};\n", name);
}
}
@ -728,58 +730,6 @@ fn write_read_inputs(state: &mut OutputState, inputs: &[hir::SymRef]) {
}
write!(state, "}}\n");
}
if state.has_draw_span_rgba8 || state.has_draw_span_r8 {
write!(
state,
"ALWAYS_INLINE void step_interp_inputs(int chunks) {{\n"
);
if (used_fragcoord & 1) != 0 {
write!(state, " step_fragcoord(chunks);\n");
}
for i in inputs {
let sym = state.hir.sym(*i);
match &sym.decl {
hir::SymDecl::Global(_, _, _, run_class) => {
if *run_class != hir::RunClass::Scalar {
let name = sym.name.as_str();
write!(state, " {0} += interp_step.{0} * chunks;\n", name);
}
}
_ => panic!(),
}
}
write!(state, "}}\n");
}
}
fn write_include_file(state: &mut OutputState, include_file: String) {
let include_contents = std::fs::read_to_string(&include_file).unwrap();
let mut offset = 0;
while offset < include_contents.len() {
let s = &include_contents[offset ..];
if let Some(start_proto) = s.find("draw_span") {
let s = &s[start_proto ..];
if let Some(end_proto) = s.find(')') {
let proto = &s[.. end_proto];
if proto.contains("uint32_t") {
state.has_draw_span_rgba8 = true;
} else if proto.contains("uint8_t") {
state.has_draw_span_r8 = true;
}
offset += start_proto + end_proto;
continue;
}
}
break;
}
let include_name = std::path::Path::new(&include_file)
.file_name()
.unwrap()
.to_string_lossy();
write!(state, "\n#include \"{}\"\n\n", include_name);
}
pub struct OutputState {
@ -804,8 +754,6 @@ pub struct OutputState {
uses_discard: bool,
used_fragcoord: Cell<i32>,
use_perspective: bool,
has_draw_span_rgba8: bool,
has_draw_span_r8: bool,
used_globals: RefCell<Vec<hir::SymRef>>,
texel_fetches: RefCell<Vec<(hir::SymRef, hir::SymRef, hir::TexelFetchOffsets)>>,
}
@ -874,7 +822,7 @@ fn add_used_global(state: &OutputState, i: &hir::SymRef) {
pub fn show_sym(state: &OutputState, i: &hir::SymRef) {
let sym = state.hir.sym(*i);
match &sym.decl {
hir::SymDecl::NativeFunction(_, ref cxx_name) => {
hir::SymDecl::NativeFunction(_, ref cxx_name, _) => {
let mut name = sym.name.as_str();
if state.output_cxx {
name = cxx_name.unwrap_or(name);
@ -1567,8 +1515,10 @@ fn expr_run_class(state: &OutputState, expr: &hir::Expr) -> hir::RunClass {
});
match fun {
hir::FunIdentifier::Identifier(ref sym) => match &state.hir.sym(*sym).decl {
hir::SymDecl::NativeFunction(..) => {
if arg_mask != 0 {
hir::SymDecl::NativeFunction(_, _, ref ret_class) => {
if *ret_class != hir::RunClass::Unknown {
*ret_class
} else if arg_mask != 0 {
hir::RunClass::Vector
} else {
hir::RunClass::Scalar
@ -1896,33 +1846,21 @@ pub fn show_hir_expr_inner(state: &OutputState, expr: &hir::Expr, top_level: boo
&state.hir, &args[0], &args[1], &args[3],
) {
let base_sym = state.hir.sym(base);
if symbol_run_class(&base_sym.decl, state.vector_mask)
== hir::RunClass::Scalar
{
let sampler_sym = state.hir.sym(sampler);
add_used_global(state, &sampler);
if let hir::SymDecl::Global(..) = &base_sym.decl {
add_used_global(state, &base);
}
if y != 0 {
write!(
state,
"{}_{}_fetch[{}+{}*{}->stride]",
sampler_sym.name,
base_sym.name,
x,
y,
sampler_sym.name
);
} else {
write!(
state,
"{}_{}_fetch[{}]",
sampler_sym.name, base_sym.name, x
);
}
return;
let sampler_sym = state.hir.sym(sampler);
add_used_global(state, &sampler);
if let hir::SymDecl::Global(..) = &base_sym.decl {
add_used_global(state, &base);
}
write!(
state,
"texelFetchUnchecked({}, {}_{}_fetch, {}, {})",
sampler_sym.name,
sampler_sym.name,
base_sym.name,
x,
y,
);
return;
}
}
show_sym(state, name)
@ -2358,15 +2296,12 @@ pub fn show_declaration(state: &mut OutputState, d: &hir::Declaration) {
let base = list.head.name;
let base_sym = state.hir.sym(base);
if let hir::SymDecl::Local(..) = &base_sym.decl {
if symbol_run_class(&base_sym.decl, state.vector_mask) == hir::RunClass::Scalar
let mut texel_fetches = state.texel_fetches.borrow_mut();
while let Some(idx) = texel_fetches.iter().position(|&(_, b, _)| b == base)
{
let mut texel_fetches = state.texel_fetches.borrow_mut();
while let Some(idx) = texel_fetches.iter().position(|&(_, b, _)| b == base)
{
let (sampler, _, offsets) = texel_fetches.remove(idx);
let sampler_sym = state.hir.sym(sampler);
define_texel_fetch_ptr(state, &base_sym, &sampler_sym, &offsets);
}
let (sampler, _, offsets) = texel_fetches.remove(idx);
let sampler_sym = state.hir.sym(sampler);
define_texel_fetch_ptr(state, &base_sym, &sampler_sym, &offsets);
}
}
}
@ -2384,19 +2319,22 @@ pub fn show_declaration(state: &mut OutputState, d: &hir::Declaration) {
//state.write(";\n");
}
hir::Declaration::Global(ref qual, ref identifiers) => {
show_type_qualifier(state, &qual);
// We only want to output GLSL layout qualifiers if not C++
if !state.output_cxx {
show_type_qualifier(state, &qual);
if !identifiers.is_empty() {
let mut iter = identifiers.iter();
let first = iter.next().unwrap();
show_identifier(state, first);
if !identifiers.is_empty() {
let mut iter = identifiers.iter();
let first = iter.next().unwrap();
show_identifier(state, first);
for identifier in iter {
let _ = write!(state, ", {}", identifier);
for identifier in iter {
let _ = write!(state, ", {}", identifier);
}
}
}
state.write(";\n");
state.write(";\n");
}
}
hir::Declaration::StructDefinition(ref sym) => {
show_sym_decl(state, sym);
@ -2672,32 +2610,32 @@ fn define_texel_fetch_ptr(
offsets: &hir::TexelFetchOffsets,
) {
show_indent(state);
if let hir::SymDecl::Global(_, _, ty, _) = &sampler_sym.decl {
match ty.kind {
hir::TypeKind::Sampler2D
| hir::TypeKind::Sampler2DRect => {
write!(
state,
"vec4_scalar* {}_{}_fetch = ",
sampler_sym.name, base_sym.name
);
let ptr_type = if let hir::SymDecl::Global(_, _, ty, _) = &sampler_sym.decl {
if symbol_run_class(&base_sym.decl, state.vector_mask) == hir::RunClass::Scalar {
match ty.kind {
hir::TypeKind::Sampler2D
| hir::TypeKind::Sampler2DRect => "vec4_scalar*",
hir::TypeKind::ISampler2D => "ivec4_scalar*",
_ => panic!(),
}
hir::TypeKind::ISampler2D => {
write!(
state,
"ivec4_scalar* {}_{}_fetch = ",
sampler_sym.name, base_sym.name
);
}
_ => panic!(),
} else {
"I32"
}
} else {
panic!();
}
};
write!(
state,
"texelFetchPtr({}, {}, {}, {}, {}, {});\n",
sampler_sym.name, base_sym.name, offsets.min_x, offsets.max_x, offsets.min_y, offsets.max_y
"{} {}_{}_fetch = texelFetchPtr({}, {}, {}, {}, {}, {});\n",
ptr_type,
sampler_sym.name,
base_sym.name,
sampler_sym.name,
base_sym.name,
offsets.min_x,
offsets.max_x,
offsets.min_y,
offsets.max_y,
);
}
@ -2750,27 +2688,64 @@ pub fn show_function_definition(
}
if state.output_cxx {
match fd.prototype.name.as_str() {
"swgl_drawSpanRGBA8" |
"swgl_drawSpanR8" => {
// Partial spans are not drawn using span shaders, but rather drawn with a fragment shader
// where the span shader left off. We need to undo any changes to the interpolants made by
// the span shaders so that we can reset the interpolants to where the fragment shader
// expects them. We do this by saving them in an _Undo_ struct on entry to the span shader,
// and then restore them in the _Undo_ struct destructor.
let mut needs_undo = vec![];
for global in &fd.globals {
let sym = state.hir.sym(*global);
match &sym.decl {
hir::SymDecl::Global(hir::StorageClass::In, _, ty, hir::RunClass::Vector) => {
if needs_undo.is_empty() {
state.write("struct _Undo_ {\nSelf* self;\n");
}
show_type(state, ty);
write!(state, " {};\n", sym.name);
needs_undo.push(sym.name.clone());
}
_ => {}
}
}
if !needs_undo.is_empty() {
state.write("explicit _Undo_(Self* self) : self(self)");
for name in &needs_undo {
write!(state, ", {0}(self->{0})", name);
}
state.write(" {}\n");
state.write("~_Undo_() {\n");
for name in &needs_undo {
write!(state, "self->{0} = {0};\n", name);
}
state.write("}} _undo_(this);\n");
}
}
_ => {}
}
let mut texel_fetches = state.texel_fetches.borrow_mut();
texel_fetches.clear();
for ((sampler, base), offsets) in fd.texel_fetches.iter() {
add_used_global(state, sampler);
let sampler_sym = state.hir.sym(*sampler);
let base_sym = state.hir.sym(*base);
if symbol_run_class(&base_sym.decl, vector_mask) == hir::RunClass::Scalar {
add_used_global(state, sampler);
let sampler_sym = state.hir.sym(*sampler);
match &base_sym.decl {
hir::SymDecl::Global(..) => {
add_used_global(state, base);
define_texel_fetch_ptr(state, &base_sym, &sampler_sym, &offsets);
}
hir::SymDecl::Local(..) => {
if fd.prototype.has_parameter(*base) {
define_texel_fetch_ptr(state, &base_sym, &sampler_sym, &offsets);
} else {
texel_fetches.push((*sampler, *base, offsets.clone()));
}
}
_ => panic!(),
match &base_sym.decl {
hir::SymDecl::Global(..) => {
add_used_global(state, base);
define_texel_fetch_ptr(state, &base_sym, &sampler_sym, &offsets);
}
hir::SymDecl::Local(..) => {
if fd.prototype.has_parameter(*base) {
define_texel_fetch_ptr(state, &base_sym, &sampler_sym, &offsets);
} else {
texel_fetches.push((*sampler, *base, offsets.clone()));
}
}
_ => panic!(),
}
}
}
@ -3195,7 +3170,7 @@ pub fn show_iteration_statement(state: &mut OutputState, ist: &hir::IterationSta
show_statement(state, body);
state.write(" while (");
show_hir_expr(state, cond);
state.write(")\n");
state.write(");\n");
}
hir::IterationStatement::For(ref init, ref rest, ref body) => {
state.write("for (");
@ -3266,7 +3241,7 @@ pub fn show_jump_statement(state: &mut OutputState, j: &hir::JumpStatement) {
if state.output_cxx {
state.uses_discard = true;
if let Some(mask) = &state.mask {
state.write("isPixelDiscarded |= (");
state.write("swgl_IsPixelDiscarded |= (");
show_hir_expr(state, mask);
state.write(")");
if state.return_declared {
@ -3274,7 +3249,7 @@ pub fn show_jump_statement(state: &mut OutputState, j: &hir::JumpStatement) {
}
state.write(";\n");
} else {
state.write("isPixelDiscarded = true;\n");
state.write("swgl_IsPixelDiscarded = true;\n");
}
} else {
state.write("discard;\n");
@ -3579,9 +3554,11 @@ pub fn show_translation_unit(state: &mut OutputState, tu: &hir::TranslationUnit)
state.flush_buffer();
}
if state.output_cxx {
if let Some(name) = state.hir.lookup("main") {
show_cxx_function_definition(state, name, 0);
state.flush_buffer();
for name in &["main", "swgl_drawSpanRGBA8", "swgl_drawSpanR8"] {
if let Some(sym) = state.hir.lookup(name) {
show_cxx_function_definition(state, sym, 0);
state.flush_buffer();
}
}
}
}
@ -3591,37 +3568,33 @@ fn write_abi(state: &mut OutputState) {
ShaderKind::Fragment => {
state.write("static void run(Self *self) {\n");
if state.uses_discard {
state.write(" self->isPixelDiscarded = false;\n");
state.write(" self->swgl_IsPixelDiscarded = false;\n");
}
state.write(" self->main();\n");
state.write(" self->step_interp_inputs();\n");
state.write("}\n");
state.write("static void skip(Self* self, int chunks) {\n");
state.write(" self->step_interp_inputs();\n");
state.write(" while (--chunks > 0) self->step_interp_inputs();\n");
state.write("static void skip(Self* self, int steps) {\n");
state.write(" self->step_interp_inputs(steps);\n");
state.write("}\n");
if state.use_perspective {
state.write("static void run_perspective(Self *self) {\n");
if state.uses_discard {
state.write(" self->isPixelDiscarded = false;\n");
state.write(" self->swgl_IsPixelDiscarded = false;\n");
}
state.write(" self->main();\n");
state.write(" self->step_perspective_inputs();\n");
state.write("}\n");
state.write("static void skip_perspective(Self* self, int chunks) {\n");
state.write(" self->step_perspective_inputs();\n");
state.write(" while (--chunks > 0) self->step_perspective_inputs();\n");
state.write("static void skip_perspective(Self* self, int steps) {\n");
state.write(" self->step_perspective_inputs(steps);\n");
state.write("}\n");
}
if state.has_draw_span_rgba8 {
if state.hir.lookup("swgl_drawSpanRGBA8").is_some() {
state.write(
"static void draw_span_RGBA8(Self* self, uint32_t* buf, int len) { \
DISPATCH_DRAW_SPAN(self, buf, len); }\n");
"static int draw_span_RGBA8(Self* self) { DISPATCH_DRAW_SPAN(self, RGBA8); }\n");
}
if state.has_draw_span_r8 {
if state.hir.lookup("swgl_drawSpanR8").is_some() {
state.write(
"static void draw_span_R8(Self* self, uint8_t* buf, int len) { \
DISPATCH_DRAW_SPAN(self, buf, len); }\n");
"static int draw_span_R8(Self* self) { DISPATCH_DRAW_SPAN(self, R8); }\n");
}
write!(state, "public:\n{}_frag() {{\n", state.name);
@ -3643,10 +3616,10 @@ fn write_abi(state: &mut OutputState) {
state.write(" init_span_func = (InitSpanFunc)&read_interp_inputs;\n");
state.write(" run_func = (RunFunc)&run;\n");
state.write(" skip_func = (SkipFunc)&skip;\n");
if state.has_draw_span_rgba8 {
if state.hir.lookup("swgl_drawSpanRGBA8").is_some() {
state.write(" draw_span_RGBA8_func = (DrawSpanRGBA8Func)&draw_span_RGBA8;\n");
}
if state.has_draw_span_r8 {
if state.hir.lookup("swgl_drawSpanR8").is_some() {
state.write(" draw_span_R8_func = (DrawSpanR8Func)&draw_span_R8;\n");
}
if state.uses_discard {
@ -3670,6 +3643,9 @@ fn write_abi(state: &mut OutputState) {
state.write(" init_batch_func = (InitBatchFunc)&init_batch;\n");
state.write(" load_attribs_func = (LoadAttribsFunc)&load_attribs;\n");
state.write(" run_primitive_func = (RunPrimitiveFunc)&run;\n");
if state.hir.used_clip_dist != 0 {
state.write(" enable_clip_distance();\n");
}
}
}
state.write("}\n");

View file

@ -1,226 +0,0 @@
From 34d968adeda2e06b057a13d14a88df5766b38eda Mon Sep 17 00:00:00 2001
From: Josh Matthews <josh@joshmatthews.net>
Date: Mon, 6 Jul 2020 14:37:42 -0400
Subject: [PATCH] Add signal handler to catch segfault in build script.
---
Cargo.lock | 11 +++++
webrender/Cargo.toml | 5 ++
webrender/backtrace.rs | 103 +++++++++++++++++++++++++++++++++++++++++
webrender/build.rs | 30 ++++++++++++
4 files changed, 149 insertions(+)
create mode 100644 webrender/backtrace.rs
diff --git a/Cargo.lock b/Cargo.lock
index afdd336ae..cf91162d5 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1477,6 +1477,14 @@ dependencies = [
"libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)",
]
+[[package]]
+name = "sig"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
[[package]]
name = "slab"
version = "0.4.2"
@@ -1750,6 +1758,7 @@ dependencies = [
name = "webrender"
version = "0.61.0"
dependencies = [
+ "backtrace 0.3.46 (registry+https://github.com/rust-lang/crates.io-index)",
"base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)",
"bincode 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1780,6 +1789,7 @@ dependencies = [
"ron 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.106 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_json 1.0.51 (registry+https://github.com/rust-lang/crates.io-index)",
+ "sig 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"smallvec 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"svg_fmt 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
"time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -2178,6 +2188,7 @@ dependencies = [
"checksum servo-freetype-sys 4.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "2c4ccb6d0d32d277d3ef7dea86203d8210945eb7a45fba89dd445b3595dd0dfc"
"checksum sha-1 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f7d94d0bede923b3cea61f3f1ff57ff8cdfd77b400fb8f9998949e0cf04163df"
"checksum shared_library 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "5a9e7e0f2bfae24d8a5b5a66c5b257a83c7412304311512a0c054cd5e619da11"
+"checksum sig 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6567e29578f9bfade6a5d94a32b9a4256348358d2a3f448cab0021f9a02614a2"
"checksum slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8"
"checksum smallvec 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)" = "f7b0758c52e15a8b5e3691eae6cc559f08eee9406e548a4477ba4e67770a82b6"
"checksum smallvec 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "05720e22615919e4734f6a99ceae50d00226c3c5aca406e102ebc33298214e0a"
diff --git a/webrender/Cargo.toml b/webrender/Cargo.toml
index dcf26d913..f7679da57 100644
--- a/webrender/Cargo.toml
+++ b/webrender/Cargo.toml
@@ -59,6 +59,11 @@ tracy-rs = { version = "0.1" }
mozangle = "0.3.1"
rand = "0.4"
+[target.'cfg(any(target_os = "macos", target_os = "linux"))'.build-dependencies]
+backtrace = "0.3"
+sig = "1.0"
+libc = "0.2"
+
[target.'cfg(any(target_os = "android", all(unix, not(target_os = "macos"))))'.dependencies]
freetype = { version = "0.4", default-features = false }
libc = "0.2"
diff --git a/webrender/backtrace.rs b/webrender/backtrace.rs
new file mode 100644
index 000000000..aa6bb6b32
--- /dev/null
+++ b/webrender/backtrace.rs
@@ -0,0 +1,103 @@
+/* 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 https://mozilla.org/MPL/2.0/. */
+
+//! Similar to `println!("{:?}", Backtrace::new())`, but doesnt allocate.
+//!
+//! Seems to fix some deadlocks: https://github.com/servo/servo/issues/24881
+//!
+//! FIXME: if/when a future version of the `backtrace` crate has
+//! https://github.com/rust-lang/backtrace-rs/pull/265, use that instead.
+
+use std::fmt::{self, Write};
+use backtrace::{BytesOrWideString, PrintFmt};
+
+#[inline(never)]
+pub(crate) fn print(w: &mut dyn std::io::Write) -> Result<(), std::io::Error> {
+ write!(w, "{:?}", Print {
+ print_fn_address: print as usize,
+ })
+}
+
+struct Print {
+ print_fn_address: usize,
+}
+
+impl fmt::Debug for Print {
+ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+ // Safety: were in a signal handler that is about to call `libc::_exit`.
+ // Potential data races from using `*_unsynchronized` functions are perhaps
+ // less bad than potential deadlocks?
+ unsafe {
+ let mut print_fn_frame = 0;
+ let mut frame_count = 0;
+ backtrace::trace_unsynchronized(|frame| {
+ let found = frame.symbol_address() as usize == self.print_fn_address;
+ if found {
+ print_fn_frame = frame_count;
+ }
+ frame_count += 1;
+ !found
+ });
+
+ let mode = PrintFmt::Short;
+ let mut p = print_path;
+ let mut f = backtrace::BacktraceFmt::new(fmt, mode, &mut p);
+ f.add_context()?;
+ let mut result = Ok(());
+ let mut frame_count = 0;
+ backtrace::trace_unsynchronized(|frame| {
+ let skip = frame_count < print_fn_frame;
+ frame_count += 1;
+ if skip {
+ return true
+ }
+
+ let mut frame_fmt = f.frame();
+ let mut any_symbol = false;
+ backtrace::resolve_frame_unsynchronized(frame, |symbol| {
+ any_symbol = true;
+ if let Err(e) = frame_fmt.symbol(frame, symbol) {
+ result = Err(e)
+ }
+ });
+ if !any_symbol {
+ if let Err(e) = frame_fmt.print_raw(frame.ip(), None, None, None) {
+ result = Err(e)
+ }
+ }
+ result.is_ok()
+ });
+ result?;
+ f.finish()
+ }
+ }
+}
+
+fn print_path(fmt: &mut fmt::Formatter, path: BytesOrWideString) -> fmt::Result {
+ match path {
+ BytesOrWideString::Bytes(mut bytes) => {
+ loop {
+ match std::str::from_utf8(bytes) {
+ Ok(s) => {
+ fmt.write_str(s)?;
+ break;
+ }
+ Err(err) => {
+ fmt.write_char(std::char::REPLACEMENT_CHARACTER)?;
+ match err.error_len() {
+ Some(len) => bytes = &bytes[err.valid_up_to() + len..],
+ None => break,
+ }
+ }
+ }
+ }
+ }
+ BytesOrWideString::Wide(wide) => {
+ for c in std::char::decode_utf16(wide.iter().cloned()) {
+ fmt.write_char(c.unwrap_or(std::char::REPLACEMENT_CHARACTER))?
+ }
+ }
+ }
+ Ok(())
+}
diff --git a/webrender/build.rs b/webrender/build.rs
index 3521d1342..36a7f17a8 100644
--- a/webrender/build.rs
+++ b/webrender/build.rs
@@ -244,7 +244,37 @@ fn write_optimized_shaders(shader_dir: &Path, shader_file: &mut File, out_dir: &
Ok(())
}
+#[cfg(any(target_os = "macos", target_os = "linux"))]
+mod backtrace;
+
+#[cfg(any(target_os = "macos", target_os = "linux"))]
+extern "C" fn handler(sig: i32) {
+ use std::sync::atomic;
+ static BEEN_HERE_BEFORE: atomic::AtomicBool = atomic::AtomicBool::new(false);
+ if !BEEN_HERE_BEFORE.swap(true, atomic::Ordering::SeqCst) {
+ let stdout = std::io::stdout();
+ let mut stdout = stdout.lock();
+ let _ = write!(&mut stdout, "Stack trace");
+ if let Some(name) = std::thread::current().name() {
+ let _ = write!(&mut stdout, " for thread \"{}\"", name);
+ }
+ let _ = write!(&mut stdout, "\n");
+ let _ = backtrace::print(&mut stdout);
+ }
+ unsafe {
+ libc::_exit(sig);
+ }
+}
+
fn main() -> Result<(), std::io::Error> {
+ #[cfg(any(target_os = "macos", target_os = "linux"))]
+ {
+ sig::signal!(sig::ffi::Sig::SEGV, handler); // handle segfaults
+ sig::signal!(sig::ffi::Sig::ILL, handler); // handle stack overflow and unsupported CPUs
+ sig::signal!(sig::ffi::Sig::IOT, handler); // handle double panics
+ sig::signal!(sig::ffi::Sig::BUS, handler); // handle invalid memory access
+ }
+
let out_dir = env::var("OUT_DIR").unwrap_or("out".to_owned());
let shaders_file_path = Path::new(&out_dir).join("shaders.rs");
--
2.39.2

View file

@ -1,174 +0,0 @@
From 299c4db222eb9f0acd9623b66b8f3d0a8a8f77f2 Mon Sep 17 00:00:00 2001
From: Jeff Muizelaar <jmuizelaar@mozilla.com>
Date: Fri, 19 Jun 2020 04:10:02 +0000
Subject: [PATCH 2/6] Bug 1646741 - Update gleam to 0.12. r=kvark
For stride calculation and SSBOs
Differential Revision: https://phabricator.services.mozilla.com/D80191
[ghsync] From https://hg.mozilla.org/mozilla-central/rev/ef8485a16d099e24f4832178664c5a93a28396ec
---
Cargo.lock | 16 ++++++++--------
direct-composition/Cargo.toml | 2 +-
example-compositor/compositor/Cargo.toml | 2 +-
examples/Cargo.toml | 2 +-
swgl/Cargo.toml | 2 +-
webrender/Cargo.toml | 2 +-
wrench/Cargo.toml | 2 +-
7 files changed, 14 insertions(+), 14 deletions(-)
diff --git a/Cargo.lock b/Cargo.lock
index cf91162d5..3eb484f26 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -257,7 +257,7 @@ name = "compositor"
version = "0.1.0"
dependencies = [
"compositor-windows 0.1.0",
- "gleam 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "gleam 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
"webrender 0.61.0",
]
@@ -435,7 +435,7 @@ name = "direct-composition"
version = "0.1.0"
dependencies = [
"euclid 0.20.10 (registry+https://github.com/rust-lang/crates.io-index)",
- "gleam 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "gleam 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
"mozangle 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
"webrender 0.61.0",
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -617,7 +617,7 @@ dependencies = [
[[package]]
name = "gleam"
-version = "0.11.0"
+version = "0.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"gl_generator 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1545,7 +1545,7 @@ name = "swgl"
version = "0.1.0"
dependencies = [
"cc 1.0.50 (registry+https://github.com/rust-lang/crates.io-index)",
- "gleam 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "gleam 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
"glsl-to-cxx 0.1.0",
"webrender_build 0.0.1",
]
@@ -1773,7 +1773,7 @@ dependencies = [
"euclid 0.20.10 (registry+https://github.com/rust-lang/crates.io-index)",
"freetype 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
"fxhash 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "gleam 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "gleam 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
"glslopt 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"image 0.23.3 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1808,7 +1808,7 @@ dependencies = [
"core-foundation 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"env_logger 0.5.13 (registry+https://github.com/rust-lang/crates.io-index)",
"euclid 0.20.10 (registry+https://github.com/rust-lang/crates.io-index)",
- "gleam 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "gleam 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
"glutin 0.21.2 (registry+https://github.com/rust-lang/crates.io-index)",
"rayon 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"webrender 0.61.0",
@@ -1938,7 +1938,7 @@ dependencies = [
"env_logger 0.5.13 (registry+https://github.com/rust-lang/crates.io-index)",
"euclid 0.20.10 (registry+https://github.com/rust-lang/crates.io-index)",
"font-loader 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "gleam 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "gleam 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
"glutin 0.21.2 (registry+https://github.com/rust-lang/crates.io-index)",
"image 0.23.3 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -2087,7 +2087,7 @@ dependencies = [
"checksum getrandom 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "7abc8dd8451921606d809ba32e95b6111925cd2906060d2dcc29c070220503eb"
"checksum gl_generator 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ca98bbde17256e02d17336a6bdb5a50f7d0ccacee502e191d3e3d0ec2f96f84a"
"checksum gl_generator 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1a95dfc23a2b4a9a2f5ab41d194f8bfda3cabec42af4e39f08c339eb2a0c124d"
-"checksum gleam 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d9a13b5bb12ab457c15400b43cbba5971df5c1898b6a9c30cc8c52cb01baa112"
+"checksum gleam 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a8d023b0b00c16960f0f82816f2f546dabe937e75b25c7d6ce09a63e6a52d71e"
"checksum gleam 0.6.19 (registry+https://github.com/rust-lang/crates.io-index)" = "cae10d7c99d0e77b4766e850a60898a17c1abaf01075531f1066f03dc7dc5fc5"
"checksum glsl 4.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "766443890761b3c4edcce86cafaac97971b200662fbdd0446eb7c6b99b4401ea"
"checksum glslopt 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f22b383fcf6f85c4a268af39a0758ec40970e5f9f8fe9809e4415d48409b8379"
diff --git a/direct-composition/Cargo.toml b/direct-composition/Cargo.toml
index d099402d8..3506aec02 100644
--- a/direct-composition/Cargo.toml
+++ b/direct-composition/Cargo.toml
@@ -7,7 +7,7 @@ edition = "2018"
[target.'cfg(windows)'.dependencies]
euclid = "0.20"
-gleam = "0.11"
+gleam = "0.12"
mozangle = {version = "0.3.1", features = ["egl"]}
webrender = {path = "../webrender"}
winapi = {version = "0.3", features = ["winerror", "d3d11", "dcomp"]}
diff --git a/example-compositor/compositor/Cargo.toml b/example-compositor/compositor/Cargo.toml
index ce4d61928..d505e9ad2 100644
--- a/example-compositor/compositor/Cargo.toml
+++ b/example-compositor/compositor/Cargo.toml
@@ -7,7 +7,7 @@ license = "MPL-2.0"
[dependencies]
webrender = { path = "../../webrender" }
-gleam = "0.11.0"
+gleam = "0.12.0"
[target.'cfg(windows)'.dependencies]
compositor-windows = { path = "../compositor-windows" }
diff --git a/examples/Cargo.toml b/examples/Cargo.toml
index 31c695f98..09e658ca2 100644
--- a/examples/Cargo.toml
+++ b/examples/Cargo.toml
@@ -61,7 +61,7 @@ debug = ["webrender/capture", "webrender/debugger", "webrender/profiler"]
app_units = "0.7"
env_logger = "0.5"
euclid = "0.20"
-gleam = "0.11"
+gleam = "0.12"
glutin = "0.21"
rayon = "1"
webrender = { path = "../webrender" }
diff --git a/swgl/Cargo.toml b/swgl/Cargo.toml
index 3d57edbab..bc5a04b0a 100644
--- a/swgl/Cargo.toml
+++ b/swgl/Cargo.toml
@@ -12,4 +12,4 @@ glsl-to-cxx = { path = "../glsl-to-cxx" }
webrender_build = { path = "../webrender_build" }
[dependencies]
-gleam = "0.11.0"
+gleam = "0.12.0"
diff --git a/webrender/Cargo.toml b/webrender/Cargo.toml
index f7679da57..2b0ab14fb 100644
--- a/webrender/Cargo.toml
+++ b/webrender/Cargo.toml
@@ -34,7 +34,7 @@ cfg-if = "0.1.2"
cstr = "0.1.2"
euclid = { version = "0.20.0", features = ["serde"] }
fxhash = "0.2.1"
-gleam = "0.11.0"
+gleam = "0.12.0"
image_loader = { optional = true, version = "0.23", package = "image", default-features = false, features = ["png"] }
lazy_static = "1"
log = "0.4"
diff --git a/wrench/Cargo.toml b/wrench/Cargo.toml
index 988e2537a..4ba95e4c4 100644
--- a/wrench/Cargo.toml
+++ b/wrench/Cargo.toml
@@ -12,7 +12,7 @@ bincode = "1.0"
byteorder = "1.0"
env_logger = { version = "0.5", optional = true }
euclid = "0.20"
-gleam = "0.11"
+gleam = "0.12"
glutin = "0.21"
app_units = "0.7"
clap = { version = "2", features = ["yaml"] }
--
2.39.2

View file

@ -1,107 +0,0 @@
From 3767bd8938b5b849bc23bb7ac490cb0c27655560 Mon Sep 17 00:00:00 2001
From: Jeff Muizelaar <jmuizelaar@mozilla.com>
Date: Sat, 11 Jul 2020 09:42:33 +0000
Subject: [PATCH 3/6] Bug 1651889. Update to gleam 0.12.1. r=kvark
This should fix a crash caused by an unexpected pixel type.
Differential Revision: https://phabricator.services.mozilla.com/D83167
[ghsync] From https://hg.mozilla.org/mozilla-central/rev/b850773b54e129888b8fb2f1e3bc68f528aeccbf
---
Cargo.lock | 16 ++++++++--------
webrender/Cargo.toml | 2 +-
2 files changed, 9 insertions(+), 9 deletions(-)
diff --git a/Cargo.lock b/Cargo.lock
index 3eb484f26..24f92084c 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -257,7 +257,7 @@ name = "compositor"
version = "0.1.0"
dependencies = [
"compositor-windows 0.1.0",
- "gleam 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "gleam 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)",
"webrender 0.61.0",
]
@@ -435,7 +435,7 @@ name = "direct-composition"
version = "0.1.0"
dependencies = [
"euclid 0.20.10 (registry+https://github.com/rust-lang/crates.io-index)",
- "gleam 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "gleam 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)",
"mozangle 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
"webrender 0.61.0",
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -617,7 +617,7 @@ dependencies = [
[[package]]
name = "gleam"
-version = "0.12.0"
+version = "0.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"gl_generator 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1545,7 +1545,7 @@ name = "swgl"
version = "0.1.0"
dependencies = [
"cc 1.0.50 (registry+https://github.com/rust-lang/crates.io-index)",
- "gleam 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "gleam 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)",
"glsl-to-cxx 0.1.0",
"webrender_build 0.0.1",
]
@@ -1773,7 +1773,7 @@ dependencies = [
"euclid 0.20.10 (registry+https://github.com/rust-lang/crates.io-index)",
"freetype 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
"fxhash 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "gleam 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "gleam 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)",
"glslopt 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"image 0.23.3 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1808,7 +1808,7 @@ dependencies = [
"core-foundation 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"env_logger 0.5.13 (registry+https://github.com/rust-lang/crates.io-index)",
"euclid 0.20.10 (registry+https://github.com/rust-lang/crates.io-index)",
- "gleam 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "gleam 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)",
"glutin 0.21.2 (registry+https://github.com/rust-lang/crates.io-index)",
"rayon 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"webrender 0.61.0",
@@ -1938,7 +1938,7 @@ dependencies = [
"env_logger 0.5.13 (registry+https://github.com/rust-lang/crates.io-index)",
"euclid 0.20.10 (registry+https://github.com/rust-lang/crates.io-index)",
"font-loader 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "gleam 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "gleam 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)",
"glutin 0.21.2 (registry+https://github.com/rust-lang/crates.io-index)",
"image 0.23.3 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -2087,7 +2087,7 @@ dependencies = [
"checksum getrandom 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "7abc8dd8451921606d809ba32e95b6111925cd2906060d2dcc29c070220503eb"
"checksum gl_generator 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ca98bbde17256e02d17336a6bdb5a50f7d0ccacee502e191d3e3d0ec2f96f84a"
"checksum gl_generator 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1a95dfc23a2b4a9a2f5ab41d194f8bfda3cabec42af4e39f08c339eb2a0c124d"
-"checksum gleam 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a8d023b0b00c16960f0f82816f2f546dabe937e75b25c7d6ce09a63e6a52d71e"
+"checksum gleam 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3fdef5b9df6d3a261b80a5ac55e13bf93945725df2463c1b0a2e5a527dce0d37"
"checksum gleam 0.6.19 (registry+https://github.com/rust-lang/crates.io-index)" = "cae10d7c99d0e77b4766e850a60898a17c1abaf01075531f1066f03dc7dc5fc5"
"checksum glsl 4.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "766443890761b3c4edcce86cafaac97971b200662fbdd0446eb7c6b99b4401ea"
"checksum glslopt 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f22b383fcf6f85c4a268af39a0758ec40970e5f9f8fe9809e4415d48409b8379"
diff --git a/webrender/Cargo.toml b/webrender/Cargo.toml
index 2b0ab14fb..3fa6630bd 100644
--- a/webrender/Cargo.toml
+++ b/webrender/Cargo.toml
@@ -34,7 +34,7 @@ cfg-if = "0.1.2"
cstr = "0.1.2"
euclid = { version = "0.20.0", features = ["serde"] }
fxhash = "0.2.1"
-gleam = "0.12.0"
+gleam = "0.12.1"
image_loader = { optional = true, version = "0.23", package = "image", default-features = false, features = ["png"] }
lazy_static = "1"
log = "0.4"
--
2.39.2

View file

@ -1,328 +0,0 @@
From 920168aff79a7cf52980b0c90965a591f2f4204a Mon Sep 17 00:00:00 2001
From: Jeff Muizelaar <jmuizelaar@mozilla.com>
Date: Fri, 24 Jul 2020 09:54:10 +0000
Subject: [PATCH 4/6] Bug 1654699. Update core-foundation/core-graphics.
r=kvark,keeler,chunmin
This includes updates to authenticator, cubeb-coreaudio,
metal, gfx-backend-vulkan, gfx-backend-metal, freetype
libloading is duplicated because of ash
Differential Revision: https://phabricator.services.mozilla.com/D84688
[ghsync] From https://hg.mozilla.org/mozilla-central/rev/45fc4a780b2b4a9e047eceba73b39b988f719c58
---
Cargo.lock | 110 +++++++++++++++++++++++++--------------
webrender/Cargo.toml | 10 ++--
webrender_api/Cargo.toml | 4 +-
wrench/Cargo.toml | 6 +--
4 files changed, 80 insertions(+), 50 deletions(-)
diff --git a/Cargo.lock b/Cargo.lock
index 24f92084c..617092292 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -286,6 +286,15 @@ dependencies = [
"libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)",
]
+[[package]]
+name = "core-foundation"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "core-foundation-sys 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
[[package]]
name = "core-foundation-sys"
version = "0.6.2"
@@ -296,6 +305,11 @@ name = "core-foundation-sys"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
+[[package]]
+name = "core-foundation-sys"
+version = "0.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
[[package]]
name = "core-graphics"
version = "0.17.3"
@@ -309,22 +323,34 @@ dependencies = [
[[package]]
name = "core-graphics"
-version = "0.19.0"
+version = "0.22.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "core-foundation 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "core-foundation 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "core-graphics-types 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "foreign-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "core-graphics-types"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "core-foundation 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
"foreign-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "core-text"
-version = "15.0.0"
+version = "19.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "core-foundation 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "core-graphics 0.19.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "core-foundation 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "core-graphics 0.22.0 (registry+https://github.com/rust-lang/crates.io-index)",
"foreign-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)",
]
@@ -510,13 +536,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "font-loader"
-version = "0.9.0"
+version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "core-foundation 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "core-text 15.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "core-foundation 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "core-text 19.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)",
- "servo-fontconfig 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "servo-fontconfig 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
@@ -535,11 +561,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "freetype"
-version = "0.4.1"
+version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
+ "freetype-sys 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)",
- "servo-freetype-sys 4.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "freetype-sys"
+version = "0.13.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "cmake 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)",
+ "pkg-config 0.3.17 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -1431,29 +1467,20 @@ dependencies = [
[[package]]
name = "servo-fontconfig"
-version = "0.4.0"
+version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)",
- "servo-fontconfig-sys 4.0.9 (registry+https://github.com/rust-lang/crates.io-index)",
+ "servo-fontconfig-sys 5.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "servo-fontconfig-sys"
-version = "4.0.9"
+version = "5.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"expat-sys 2.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
- "pkg-config 0.3.17 (registry+https://github.com/rust-lang/crates.io-index)",
- "servo-freetype-sys 4.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "servo-freetype-sys"
-version = "4.0.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "cmake 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)",
+ "freetype-sys 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)",
"pkg-config 0.3.17 (registry+https://github.com/rust-lang/crates.io-index)",
]
@@ -1765,13 +1792,13 @@ dependencies = [
"build-parallel 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
"cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
- "core-foundation 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "core-graphics 0.19.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "core-text 15.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "core-foundation 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "core-graphics 0.22.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "core-text 19.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"cstr 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
"dwrote 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
"euclid 0.20.10 (registry+https://github.com/rust-lang/crates.io-index)",
- "freetype 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "freetype 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"fxhash 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"gleam 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)",
"glslopt 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1822,8 +1849,8 @@ dependencies = [
"app_units 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
"bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
- "core-foundation 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "core-graphics 0.19.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "core-foundation 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "core-graphics 0.22.0 (registry+https://github.com/rust-lang/crates.io-index)",
"derive_more 0.99.5 (registry+https://github.com/rust-lang/crates.io-index)",
"euclid 0.20.10 (registry+https://github.com/rust-lang/crates.io-index)",
"malloc_size_of_derive 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1931,13 +1958,13 @@ dependencies = [
"byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
"chrono 0.2.25 (registry+https://github.com/rust-lang/crates.io-index)",
"clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "core-foundation 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "core-graphics 0.19.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "core-foundation 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "core-graphics 0.22.0 (registry+https://github.com/rust-lang/crates.io-index)",
"crossbeam 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)",
"dwrote 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
"env_logger 0.5.13 (registry+https://github.com/rust-lang/crates.io-index)",
"euclid 0.20.10 (registry+https://github.com/rust-lang/crates.io-index)",
- "font-loader 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "font-loader 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
"gleam 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)",
"glutin 0.21.2 (registry+https://github.com/rust-lang/crates.io-index)",
"image 0.23.3 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -2051,11 +2078,14 @@ dependencies = [
"checksum cocoa 0.18.5 (registry+https://github.com/rust-lang/crates.io-index)" = "1706996401131526e36b3b49f0c4d912639ce110996f3ca144d78946727bce54"
"checksum core-foundation 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = "25b9e03f145fd4f2bf705e07b900cd41fc636598fe5dc452fd0db1441c3f496d"
"checksum core-foundation 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "57d24c7a13c43e870e37c1556b74555437870a04514f7685f5b354e090567171"
+"checksum core-foundation 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3b5ed8e7e76c45974e15e41bfa8d5b0483cd90191639e01d8f5f1e606299d3fb"
"checksum core-foundation-sys 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e7ca8a5221364ef15ce201e8ed2f609fc312682a8f4e0e3d4aa5879764e0fa3b"
"checksum core-foundation-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b3a71ab494c0b5b860bdc8407ae08978052417070c2ced38573a9157ad75b8ac"
+"checksum core-foundation-sys 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9a21fa21941700a3cd8fcb4091f361a6a712fac632f85d9f487cc892045d55c6"
"checksum core-graphics 0.17.3 (registry+https://github.com/rust-lang/crates.io-index)" = "56790968ab1c8a1202a102e6de05fc6e1ec87da99e4e93e9a7d13efbfc1e95a9"
-"checksum core-graphics 0.19.0 (registry+https://github.com/rust-lang/crates.io-index)" = "59e78b2e0aaf43f08e7ae0d6bc96895ef72ff0921c7d4ff4762201b2dba376dd"
-"checksum core-text 15.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "131b3fd1f8bd5db9f2b398fa4fdb6008c64afc04d447c306ac2c7e98fba2a61d"
+"checksum core-graphics 0.22.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f6082396a349fa49674ba1bda4077332a18bf150e8fa75745ece07085e29a113"
+"checksum core-graphics-types 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e92f5d519093a4178296707dbaa3880eae85a5ef5386675f361a1cf25376e93c"
+"checksum core-text 19.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "04dfae50af11e72657fe7174cddb1ecddc5398037f7f6f39533ad69207c9a4e2"
"checksum crc32fast 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ba125de2af0df55319f41944744ad91c71113bf74a4646efff39afe1f6842db1"
"checksum crossbeam 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)" = "bd66663db5a988098a89599d4857919b3acf7f61402e61365acfd3919857b9be"
"checksum crossbeam-deque 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "9f02af974daeee82218205558e51ec8768b48cf524bd01d550abe5573a608285"
@@ -2075,10 +2105,11 @@ dependencies = [
"checksum euclid 0.20.10 (registry+https://github.com/rust-lang/crates.io-index)" = "0c6a5b0c779cd0b744c73a1d2083faf181080d696903cdad99a3b03d015d7030"
"checksum expat-sys 2.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "658f19728920138342f68408b7cf7644d90d4784353d8ebc32e7e8663dbe45fa"
"checksum fake-simd 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed"
-"checksum font-loader 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "933a61458662fbc8e3cd22cdb8331edbd78545fc044e1e2cd3d742f6ce06aa41"
+"checksum font-loader 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c49d6b4c11dca1a1dd931a34a9f397e2da91abe3de4110505f3530a80e560b52"
"checksum foreign-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1"
"checksum foreign-types-shared 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b"
-"checksum freetype 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "11926b2b410b469d0e9399eca4cbbe237a9ef02176c485803b29216307e8e028"
+"checksum freetype 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bee38378a9e3db1cc693b4f88d166ae375338a0ff75cb8263e1c601d51f35dc6"
+"checksum freetype-sys 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a37d4011c0cc628dfa766fcc195454f4b068d7afdc2adfd28861191d866e731a"
"checksum fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba"
"checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82"
"checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7"
@@ -2183,9 +2214,8 @@ dependencies = [
"checksum serde_bytes 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)" = "325a073952621257820e7a3469f55ba4726d8b28657e7e36653d1c36dc2c84ae"
"checksum serde_derive 1.0.106 (registry+https://github.com/rust-lang/crates.io-index)" = "9e549e3abf4fb8621bd1609f11dfc9f5e50320802273b12f3811a67e6716ea6c"
"checksum serde_json 1.0.51 (registry+https://github.com/rust-lang/crates.io-index)" = "da07b57ee2623368351e9a0488bb0b261322a15a6e0ae53e243cbdc0f4208da9"
-"checksum servo-fontconfig 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a088f8d775a5c5314aae09bd77340bc9c67d72b9a45258be34c83548b4814cd9"
-"checksum servo-fontconfig-sys 4.0.9 (registry+https://github.com/rust-lang/crates.io-index)" = "62b3e166450f523f4db06c14f02a2d39e76d49b5d8cbd224338d93e3595c156c"
-"checksum servo-freetype-sys 4.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "2c4ccb6d0d32d277d3ef7dea86203d8210945eb7a45fba89dd445b3595dd0dfc"
+"checksum servo-fontconfig 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c7e3e22fe5fd73d04ebf0daa049d3efe3eae55369ce38ab16d07ddd9ac5c217c"
+"checksum servo-fontconfig-sys 5.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e36b879db9892dfa40f95da1c38a835d41634b825fbd8c4c418093d53c24b388"
"checksum sha-1 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f7d94d0bede923b3cea61f3f1ff57ff8cdfd77b400fb8f9998949e0cf04163df"
"checksum shared_library 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "5a9e7e0f2bfae24d8a5b5a66c5b257a83c7412304311512a0c054cd5e619da11"
"checksum sig 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6567e29578f9bfade6a5d94a32b9a4256348358d2a3f448cab0021f9a02614a2"
diff --git a/webrender/Cargo.toml b/webrender/Cargo.toml
index 3fa6630bd..d05cf5979 100644
--- a/webrender/Cargo.toml
+++ b/webrender/Cargo.toml
@@ -10,7 +10,7 @@ edition = "2018"
[features]
default = ["freetype-lib"]
-freetype-lib = ["freetype/servo-freetype-sys"]
+freetype-lib = ["freetype/freetype-sys"]
profiler = ["tracy-rs/enable_profiler"]
debugger = ["ws", "serde_json", "serde", "image_loader", "base64"]
capture = ["api/serialize", "ron", "serde", "smallvec/serde"]
@@ -65,13 +65,13 @@ sig = "1.0"
libc = "0.2"
[target.'cfg(any(target_os = "android", all(unix, not(target_os = "macos"))))'.dependencies]
-freetype = { version = "0.4", default-features = false }
+freetype = { version = "0.7", default-features = false }
libc = "0.2"
[target.'cfg(target_os = "windows")'.dependencies]
dwrote = "0.11"
[target.'cfg(target_os = "macos")'.dependencies]
-core-foundation = "0.7"
-core-graphics = "0.19"
-core-text = { version = "15", default-features = false }
+core-foundation = "0.9"
+core-graphics = "0.22"
+core-text = { version = "19", default-features = false }
diff --git a/webrender_api/Cargo.toml b/webrender_api/Cargo.toml
index 6b8b1e5f2..4ed7ce8e2 100644
--- a/webrender_api/Cargo.toml
+++ b/webrender_api/Cargo.toml
@@ -28,5 +28,5 @@ malloc_size_of = { version = "0.0.1", path = "../wr_malloc_size_of", package = "
peek-poke = { version = "0.2", path = "../peek-poke", features = ["extras"] }
[target.'cfg(target_os = "macos")'.dependencies]
-core-foundation = "0.7"
-core-graphics = "0.19"
+core-foundation = "0.9"
+core-graphics = "0.22"
diff --git a/wrench/Cargo.toml b/wrench/Cargo.toml
index 4ba95e4c4..33679485a 100644
--- a/wrench/Cargo.toml
+++ b/wrench/Cargo.toml
@@ -38,8 +38,8 @@ default-features = false
features = ["png"]
[target.'cfg(target_os = "macos")'.dependencies]
-core-graphics = "0.19"
-core-foundation = "0.7"
+core-graphics = "0.22"
+core-foundation = "0.9"
[features]
default = [ "env_logger" ]
@@ -51,7 +51,7 @@ dwrote = "0.11"
mozangle = {version = "0.3.1", features = ["egl"]}
[target.'cfg(all(unix, not(target_os = "android")))'.dependencies]
-font-loader = "0.9"
+font-loader = "0.11"
# Configuration information used when building wrench as an APK.
[package.metadata.android]
--
2.39.2

View file

@ -1,53 +0,0 @@
From 415b9ba32648667313f6f4ce7965752285bf0b26 Mon Sep 17 00:00:00 2001
From: Martin Robinson <mrobinson@igalia.com>
Date: Thu, 12 Jan 2023 12:35:31 +0100
Subject: [PATCH 2/2] Bump procedural-masquerade to 0.1.7
This fixes a build issue in this branch.
---
Cargo.lock | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/Cargo.lock b/Cargo.lock
index b6085604cae8e18de3273bcddac43fa0a7e1abd1..b7055733e57fcd0acff07881ef72369b560c2abe 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -417,7 +417,7 @@ version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"cstr-macros 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
- "procedural-masquerade 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "procedural-masquerade 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -425,7 +425,7 @@ name = "cstr-macros"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "procedural-masquerade 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "procedural-masquerade 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)",
]
@@ -1212,7 +1212,7 @@ dependencies = [
[[package]]
name = "procedural-masquerade"
-version = "0.1.6"
+version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
@@ -2182,7 +2182,7 @@ dependencies = [
"checksum ppv-lite86 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "74490b50b9fbe561ac330df47c08f3f33073d2d00c150f719147d7c54522fa1b"
"checksum proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)" = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759"
"checksum proc-macro2 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)" = "df246d292ff63439fea9bc8c0a270bed0e390d5ebd4db4ba15aba81111b5abe3"
-"checksum procedural-masquerade 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "9a1574a51c3fd37b26d2c0032b649d08a7d51d4cca9c41bbc5bf7118fa4509d0"
+"checksum procedural-masquerade 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "8f1383dff4092fe903ac180e391a8d4121cc48f08ccf850614b0290c6673b69d"
"checksum quick-error 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0"
"checksum quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)" = "6ce23b6b870e8f94f81fb0a363d65d86675884b34a09043c81e5562f11c1f8e1"
"checksum quote 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2bdc6c187c65bca4260c9011c9e3132efe4909da44726bad24cf7572ae338d7f"
--
2.39.2

View file

@ -1,601 +0,0 @@
diff --git a/direct-composition/src/lib.rs b/direct-composition/src/lib.rs
index fadb8f2b72..fa94b4b0e3 100644
--- a/direct-composition/src/lib.rs
+++ b/direct-composition/src/lib.rs
@@ -4,9 +4,9 @@
#![cfg(windows)]
-extern crate gleam;
-extern crate mozangle;
-extern crate winapi;
+use gleam;
+use mozangle;
+use winapi;
use com::{ComPtr, CheckHResult, as_ptr};
use std::ptr;
diff --git a/direct-composition/src/main_windows.rs b/direct-composition/src/main_windows.rs
index 18f1300a51..ff6608b4f0 100644
--- a/direct-composition/src/main_windows.rs
+++ b/direct-composition/src/main_windows.rs
@@ -2,11 +2,11 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-extern crate direct_composition;
-extern crate euclid;
-extern crate gleam;
-extern crate webrender;
-extern crate winit;
+use direct_composition;
+use euclid;
+use gleam;
+use webrender;
+use winit;
use euclid::size2;
use direct_composition::DirectComposition;
diff --git a/examples/alpha_perf.rs b/examples/alpha_perf.rs
index 56dc5b1abe..9200e65c8d 100644
--- a/examples/alpha_perf.rs
+++ b/examples/alpha_perf.rs
@@ -2,11 +2,11 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-extern crate euclid;
-extern crate gleam;
-extern crate glutin;
-extern crate webrender;
-extern crate winit;
+use euclid;
+use gleam;
+use glutin;
+use webrender;
+use winit;
#[path = "common/boilerplate.rs"]
mod boilerplate;
diff --git a/examples/animation.rs b/examples/animation.rs
index 612d891178..2e87e78b17 100644
--- a/examples/animation.rs
+++ b/examples/animation.rs
@@ -10,11 +10,11 @@
//! rounded cornered rectangle, which is done automatically during the
//! scene building for render optimization.
-extern crate euclid;
-extern crate gleam;
-extern crate glutin;
-extern crate webrender;
-extern crate winit;
+use euclid;
+use gleam;
+use glutin;
+use webrender;
+use winit;
#[path = "common/boilerplate.rs"]
mod boilerplate;
diff --git a/examples/basic.rs b/examples/basic.rs
index 79e0a87c46..0844994400 100644
--- a/examples/basic.rs
+++ b/examples/basic.rs
@@ -2,11 +2,11 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-extern crate euclid;
-extern crate gleam;
-extern crate glutin;
-extern crate webrender;
-extern crate winit;
+use euclid;
+use gleam;
+use glutin;
+use webrender;
+use winit;
#[path = "common/boilerplate.rs"]
mod boilerplate;
diff --git a/examples/blob.rs b/examples/blob.rs
index dd58b17f38..ea6536cea8 100644
--- a/examples/blob.rs
+++ b/examples/blob.rs
@@ -2,11 +2,11 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-extern crate gleam;
-extern crate glutin;
-extern crate rayon;
-extern crate webrender;
-extern crate winit;
+use gleam;
+use glutin;
+use rayon;
+use webrender;
+use winit;
#[path = "common/boilerplate.rs"]
mod boilerplate;
diff --git a/examples/document.rs b/examples/document.rs
index 56f5eedc8f..e33eff4665 100644
--- a/examples/document.rs
+++ b/examples/document.rs
@@ -2,11 +2,11 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-extern crate euclid;
-extern crate gleam;
-extern crate glutin;
-extern crate webrender;
-extern crate winit;
+use euclid;
+use gleam;
+use glutin;
+use webrender;
+use winit;
#[path = "common/boilerplate.rs"]
mod boilerplate;
diff --git a/examples/frame_output.rs b/examples/frame_output.rs
index dc1c1d83f0..2cd612c9b4 100644
--- a/examples/frame_output.rs
+++ b/examples/frame_output.rs
@@ -2,11 +2,11 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-extern crate euclid;
-extern crate gleam;
-extern crate glutin;
-extern crate webrender;
-extern crate winit;
+use euclid;
+use gleam;
+use glutin;
+use webrender;
+use winit;
#[path = "common/boilerplate.rs"]
mod boilerplate;
diff --git a/examples/iframe.rs b/examples/iframe.rs
index 50e8b46f30..32c0b3a8fe 100644
--- a/examples/iframe.rs
+++ b/examples/iframe.rs
@@ -2,10 +2,10 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-extern crate gleam;
-extern crate glutin;
-extern crate webrender;
-extern crate winit;
+use gleam;
+use glutin;
+use webrender;
+use winit;
#[path = "common/boilerplate.rs"]
mod boilerplate;
diff --git a/examples/image_resize.rs b/examples/image_resize.rs
index f45add1e7a..e28dd8e03d 100644
--- a/examples/image_resize.rs
+++ b/examples/image_resize.rs
@@ -2,10 +2,10 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-extern crate gleam;
-extern crate glutin;
-extern crate webrender;
-extern crate winit;
+use gleam;
+use glutin;
+use webrender;
+use winit;
#[path = "common/boilerplate.rs"]
mod boilerplate;
diff --git a/examples/multiwindow.rs b/examples/multiwindow.rs
index 9b20960a94..2183b94144 100644
--- a/examples/multiwindow.rs
+++ b/examples/multiwindow.rs
@@ -2,11 +2,11 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-extern crate euclid;
-extern crate gleam;
-extern crate glutin;
-extern crate webrender;
-extern crate winit;
+use euclid;
+use gleam;
+use glutin;
+use webrender;
+use winit;
use gleam::gl;
use glutin::NotCurrent;
diff --git a/examples/scrolling.rs b/examples/scrolling.rs
index 34cd14304f..745c4f9bd3 100644
--- a/examples/scrolling.rs
+++ b/examples/scrolling.rs
@@ -2,11 +2,11 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-extern crate euclid;
-extern crate gleam;
-extern crate glutin;
-extern crate webrender;
-extern crate winit;
+use euclid;
+use gleam;
+use glutin;
+use webrender;
+use winit;
#[path = "common/boilerplate.rs"]
mod boilerplate;
diff --git a/examples/texture_cache_stress.rs b/examples/texture_cache_stress.rs
index d2e6818302..a065649b73 100644
--- a/examples/texture_cache_stress.rs
+++ b/examples/texture_cache_stress.rs
@@ -2,10 +2,10 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-extern crate gleam;
-extern crate glutin;
-extern crate webrender;
-extern crate winit;
+use gleam;
+use glutin;
+use webrender;
+use winit;
#[path = "common/boilerplate.rs"]
mod boilerplate;
diff --git a/examples/yuv.rs b/examples/yuv.rs
index a8f36b33d7..3943bd23a6 100644
--- a/examples/yuv.rs
+++ b/examples/yuv.rs
@@ -2,10 +2,10 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-extern crate gleam;
-extern crate glutin;
-extern crate webrender;
-extern crate winit;
+use gleam;
+use glutin;
+use webrender;
+use winit;
#[path = "common/boilerplate.rs"]
mod boilerplate;
diff --git a/glsl-to-cxx/src/lib.rs b/glsl-to-cxx/src/lib.rs
index e40418aaab..409af02d58 100644
--- a/glsl-to-cxx/src/lib.rs
+++ b/glsl-to-cxx/src/lib.rs
@@ -2,7 +2,7 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-extern crate glsl;
+use glsl;
mod hir;
diff --git a/peek-poke/peek-poke-derive/src/lib.rs b/peek-poke/peek-poke-derive/src/lib.rs
index 7000f28bf1..92d538e516 100644
--- a/peek-poke/peek-poke-derive/src/lib.rs
+++ b/peek-poke/peek-poke-derive/src/lib.rs
@@ -223,7 +223,7 @@ fn peek_poke_derive(mut s: Structure) -> TokenStream {
};
let poke_impl = s.gen_impl(quote! {
- extern crate peek_poke;
+ use peek_poke;
gen unsafe impl peek_poke::Poke for @Self {
#max_size_fn
@@ -249,7 +249,7 @@ fn peek_poke_derive(mut s: Structure) -> TokenStream {
let peek_impl = quote! {
#[allow(non_upper_case_globals)]
const #dummy_const: () = {
- extern crate peek_poke;
+ use peek_poke;
impl #impl_generics peek_poke::Peek for #name #ty_generics #where_clause {
#peek_from_fn
diff --git a/swgl/build.rs b/swgl/build.rs
index 1de3568aa0..5133e9f397 100644
--- a/swgl/build.rs
+++ b/swgl/build.rs
@@ -2,9 +2,9 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-extern crate cc;
-extern crate glsl_to_cxx;
-extern crate webrender_build;
+use cc;
+use glsl_to_cxx;
+use webrender_build;
use std::collections::HashSet;
use std::fmt::Write;
diff --git a/swgl/src/lib.rs b/swgl/src/lib.rs
index e8fc030e0c..e19e85fd51 100644
--- a/swgl/src/lib.rs
+++ b/swgl/src/lib.rs
@@ -5,7 +5,7 @@
#![crate_name = "swgl"]
#![crate_type = "lib"]
-extern crate gleam;
+use gleam;
mod swgl_fns;
diff --git a/webrender/build.rs b/webrender/build.rs
index 36a7f17a8e..caea4dd5c2 100644
--- a/webrender/build.rs
+++ b/webrender/build.rs
@@ -2,7 +2,7 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-extern crate webrender_build;
+use webrender_build;
use std::borrow::Cow;
use std::env;
diff --git a/webrender/src/device/gl.rs b/webrender/src/device/gl.rs
index 6ad0e98eef..3eac572081 100644
--- a/webrender/src/device/gl.rs
+++ b/webrender/src/device/gl.rs
@@ -373,7 +373,7 @@ impl<T> Drop for VBO<T> {
pub struct ExternalTexture {
id: gl::GLuint,
target: gl::GLuint,
- swizzle: Swizzle,
+ _swizzle: Swizzle,
uv_rect: TexelRect,
}
@@ -387,7 +387,7 @@ impl ExternalTexture {
ExternalTexture {
id,
target: get_gl_target(target),
- swizzle,
+ _swizzle: swizzle,
uv_rect,
}
}
@@ -520,7 +520,7 @@ impl Texture {
let ext = ExternalTexture {
id: self.id,
target: self.target,
- swizzle: Swizzle::default(),
+ _swizzle: Swizzle::default(),
// TODO(gw): Support custom UV rect for external textures during captures
uv_rect: TexelRect::new(
0.0,
diff --git a/webrender/src/internal_types.rs b/webrender/src/internal_types.rs
index bae74efcfa..321afd2221 100644
--- a/webrender/src/internal_types.rs
+++ b/webrender/src/internal_types.rs
@@ -568,13 +568,13 @@ pub enum ResultMsg {
#[derive(Clone, Debug)]
pub struct ResourceCacheError {
- description: String,
+ _description: String,
}
impl ResourceCacheError {
pub fn new(description: String) -> ResourceCacheError {
ResourceCacheError {
- description,
+ _description: description,
}
}
}
diff --git a/webrender/src/lib.rs b/webrender/src/lib.rs
index 965f7dbc89..0db5feae9e 100644
--- a/webrender/src/lib.rs
+++ b/webrender/src/lib.rs
@@ -72,8 +72,7 @@ extern crate serde;
#[macro_use]
extern crate tracy_rs;
-extern crate malloc_size_of;
-extern crate svg_fmt;
+use malloc_size_of;
#[macro_use]
mod profiler;
@@ -155,49 +154,34 @@ mod platform {
}
#[cfg(target_os = "macos")]
-extern crate core_foundation;
+use core_foundation;
#[cfg(target_os = "macos")]
-extern crate core_graphics;
+use core_graphics;
#[cfg(target_os = "macos")]
-extern crate core_text;
-
-#[cfg(all(unix, not(target_os = "macos")))]
-extern crate freetype;
-#[cfg(all(unix, not(target_os = "macos")))]
-extern crate libc;
+use core_text;
#[cfg(target_os = "windows")]
-extern crate dwrote;
-
-extern crate bincode;
-extern crate byteorder;
-pub extern crate euclid;
-extern crate fxhash;
-extern crate gleam;
-extern crate num_traits;
-extern crate plane_split;
-extern crate rayon;
-#[cfg(feature = "ron")]
-extern crate ron;
+use dwrote;
+
+pub use euclid;
#[cfg(feature = "debugger")]
-extern crate serde_json;
+use serde_json;
#[macro_use]
extern crate smallvec;
-extern crate time;
#[cfg(feature = "debugger")]
-extern crate ws;
+use ws;
#[cfg(feature = "debugger")]
-extern crate image_loader;
+use image_loader;
#[cfg(feature = "debugger")]
-extern crate base64;
+use base64;
#[cfg(all(feature = "capture", feature = "png"))]
-extern crate png;
+use png;
#[cfg(test)]
-extern crate rand;
+use rand;
#[macro_use]
pub extern crate api;
-extern crate webrender_build;
+use webrender_build;
#[doc(hidden)]
pub use crate::composite::{CompositorConfig, Compositor, CompositorCapabilities};
diff --git a/webrender/src/render_target.rs b/webrender/src/render_target.rs
index 9a3c953f42..9c62297c92 100644
--- a/webrender/src/render_target.rs
+++ b/webrender/src/render_target.rs
@@ -1003,10 +1003,10 @@ fn add_svg_filter_instances(
let generic_int = match filter {
SvgFilterInfo::Blend(mode) => *mode as u16,
SvgFilterInfo::ComponentTransfer(data) =>
- ((data.r_func.to_int() << 12 |
+ (data.r_func.to_int() << 12 |
data.g_func.to_int() << 8 |
data.b_func.to_int() << 4 |
- data.a_func.to_int()) as u16),
+ data.a_func.to_int()) as u16,
SvgFilterInfo::Composite(operator) =>
operator.as_int() as u16,
SvgFilterInfo::LinearToSrgb |
diff --git a/webrender/tests/angle_shader_validation.rs b/webrender/tests/angle_shader_validation.rs
index 0a099d0b04..dda275dfda 100644
--- a/webrender/tests/angle_shader_validation.rs
+++ b/webrender/tests/angle_shader_validation.rs
@@ -2,9 +2,9 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-extern crate mozangle;
-extern crate webrender;
-extern crate webrender_build;
+use mozangle;
+use webrender;
+use webrender_build;
use mozangle::shaders::{BuiltInResources, Output, ShaderSpec, ShaderValidator};
use webrender_build::shader::{ShaderFeatureFlags, ShaderVersion, build_shader_strings, get_shader_features};
diff --git a/webrender_api/src/api.rs b/webrender_api/src/api.rs
index 3e8a99e921..94962ad712 100644
--- a/webrender_api/src/api.rs
+++ b/webrender_api/src/api.rs
@@ -4,8 +4,6 @@
#![deny(missing_docs)]
-extern crate serde_bytes;
-
use peek_poke::PeekPoke;
use std::cell::Cell;
use std::fmt;
diff --git a/webrender_api/src/image.rs b/webrender_api/src/image.rs
index deaeb92aeb..4a664bddcf 100644
--- a/webrender_api/src/image.rs
+++ b/webrender_api/src/image.rs
@@ -340,7 +340,7 @@ pub enum ImageData {
}
mod serde_image_data_raw {
- extern crate serde_bytes;
+ use serde_bytes;
use std::sync::Arc;
use serde::{Deserializer, Serializer};
diff --git a/webrender_api/src/lib.rs b/webrender_api/src/lib.rs
index 5f274753e8..848f4740c9 100644
--- a/webrender_api/src/lib.rs
+++ b/webrender_api/src/lib.rs
@@ -15,28 +15,23 @@
#![cfg_attr(feature = "cargo-clippy", allow(clippy::float_cmp, clippy::too_many_arguments))]
#![cfg_attr(feature = "cargo-clippy", allow(clippy::unreadable_literal, clippy::new_without_default))]
-extern crate app_units;
#[macro_use]
extern crate bitflags;
-extern crate byteorder;
#[cfg(feature = "nightly")]
-extern crate core;
+use core;
#[cfg(target_os = "macos")]
-extern crate core_foundation;
+use core_foundation;
#[cfg(target_os = "macos")]
-extern crate core_graphics;
+use core_graphics;
#[macro_use]
extern crate derive_more;
-pub extern crate euclid;
+pub use euclid;
#[macro_use]
extern crate malloc_size_of_derive;
-extern crate serde;
#[macro_use]
extern crate serde_derive;
-extern crate time;
-extern crate malloc_size_of;
-extern crate peek_poke;
+use malloc_size_of;
mod api;
pub mod channel;
diff --git a/wr_malloc_size_of/lib.rs b/wr_malloc_size_of/lib.rs
index 49a9666342..2a34508974 100644
--- a/wr_malloc_size_of/lib.rs
+++ b/wr_malloc_size_of/lib.rs
@@ -10,8 +10,8 @@
//! A reduced fork of Firefox's malloc_size_of crate, for bundling with WebRender.
-extern crate app_units;
-extern crate euclid;
+use app_units;
+use euclid;
use std::hash::{BuildHasher, Hash};
use std::mem::size_of;

View file

@ -0,0 +1,250 @@
diff --git a/webrender/src/hit_test.rs b/webrender/src/hit_test.rs
index 4a73e2158d..e095d8db0c 100644
--- a/webrender/src/hit_test.rs
+++ b/webrender/src/hit_test.rs
@@ -2,13 +2,14 @@
* 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 api::{BorderRadius, ClipMode, HitTestItem, HitTestResult, ItemTag, PrimitiveFlags};
+use api::{BorderRadius, ClipMode, HitTestItem, HitTestResult, ItemTag, PrimitiveFlags, HitTestFlags};
use api::{PipelineId, ApiHitTester, ClipId};
use api::units::*;
use crate::clip::{ClipItemKind, ClipStore, ClipNode, rounded_rectangle_contains_point};
use crate::clip::{polygon_contains_point};
use crate::prim_store::PolygonKey;
use crate::scene_builder_thread::Interners;
+use crate::spatial_node::SpatialNodeType;
use crate::spatial_tree::{SpatialNodeIndex, SpatialTree};
use crate::internal_types::{FastHashMap, FastHashSet, LayoutPrimitiveInfo};
use std::ops;
@@ -45,8 +46,9 @@ impl ApiHitTester for SharedHitTester {
fn hit_test(&self,
pipeline_id: Option<PipelineId>,
point: WorldPoint,
+ flags: HitTestFlags,
) -> HitTestResult {
- self.get_ref().hit_test(HitTest::new(pipeline_id, point))
+ self.get_ref().hit_test(HitTest::new(pipeline_id, point, flags))
}
}
@@ -355,6 +357,7 @@ impl HitTester {
self.spatial_nodes.clear();
self.spatial_nodes.reserve(spatial_tree.spatial_nodes.len());
+ self.pipeline_root_nodes.clear();
for (index, node) in spatial_tree.spatial_nodes.iter().enumerate() {
let index = SpatialNodeIndex::new(index);
@@ -380,6 +383,8 @@ impl HitTester {
}
pub fn hit_test(&self, test: HitTest) -> HitTestResult {
+ let point = test.get_absolute_point(self);
+
let mut result = HitTestResult::default();
let mut current_spatial_node_index = SpatialNodeIndex::INVALID;
@@ -402,7 +407,7 @@ impl HitTester {
point_in_layer = scroll_node
.world_content_transform
.inverse()
- .and_then(|inverted| inverted.transform_point2d(test.point));
+ .and_then(|inverted| inverted.transform_point2d(point));
current_spatial_node_index = item.spatial_node_index;
}
@@ -426,7 +431,7 @@ impl HitTester {
.world_content_transform;
let transformed_point = match transform
.inverse()
- .and_then(|inverted| inverted.transform_point2d(test.point))
+ .and_then(|inverted| inverted.transform_point2d(point))
{
Some(point) => point,
None => {
@@ -457,7 +462,7 @@ impl HitTester {
point_in_viewport = root_node
.world_viewport_transform
.inverse()
- .and_then(|inverted| inverted.transform_point2d(test.point))
+ .and_then(|inverted| inverted.transform_point2d(point))
.map(|pt| pt - scroll_node.external_scroll_offset);
current_root_spatial_node_index = root_spatial_node_index;
@@ -470,6 +475,10 @@ impl HitTester {
point_in_viewport,
point_relative_to_item: point_in_layer - item.rect.origin.to_vector(),
});
+
+ if !test.flags.contains(HitTestFlags::FIND_ALL) {
+ return result;
+ }
}
}
}
@@ -477,24 +486,51 @@ impl HitTester {
result.items.dedup();
result
}
+
+ fn get_pipeline_root(&self, pipeline_id: PipelineId) -> &HitTestSpatialNode {
+ &self.spatial_nodes[self.pipeline_root_nodes[&pipeline_id].0 as usize]
+ }
+
}
#[derive(MallocSizeOf)]
pub struct HitTest {
pipeline_id: Option<PipelineId>,
point: WorldPoint,
+ flags: HitTestFlags,
}
impl HitTest {
pub fn new(
pipeline_id: Option<PipelineId>,
point: WorldPoint,
+ flags: HitTestFlags,
) -> HitTest {
HitTest {
pipeline_id,
point,
+ flags
}
}
+
+ fn get_absolute_point(&self, hit_tester: &HitTester) -> WorldPoint {
+ if !self.flags.contains(HitTestFlags::POINT_RELATIVE_TO_PIPELINE_VIEWPORT) {
+ return self.point;
+ }
+
+ let point = LayoutPoint::new(self.point.x, self.point.y);
+ self.pipeline_id
+ .and_then(|id|
+ hit_tester
+ .get_pipeline_root(id)
+ .world_viewport_transform
+ .transform_point2d(point)
+ )
+ .unwrap_or_else(|| {
+ WorldPoint::new(self.point.x, self.point.y)
+ })
+ }
+
}
/// Collect clips for a given ClipId, convert and add them to the hit testing
diff --git a/webrender/src/render_api.rs b/webrender/src/render_api.rs
index b84fa2c63a..b2c8a64e88 100644
--- a/webrender/src/render_api.rs
+++ b/webrender/src/render_api.rs
@@ -10,6 +10,7 @@ use std::marker::PhantomData;
use std::path::PathBuf;
use std::sync::Arc;
use std::u32;
+use api::HitTestFlags;
use time::precise_time_ns;
//use crate::api::peek_poke::PeekPoke;
use crate::api::channel::{Sender, single_msg_channel, unbounded_channel};
@@ -812,7 +813,7 @@ pub enum FrameMsg {
///
UpdateEpoch(PipelineId, Epoch),
///
- HitTest(Option<PipelineId>, WorldPoint, Sender<HitTestResult>),
+ HitTest(Option<PipelineId>, WorldPoint, HitTestFlags, Sender<HitTestResult>),
///
RequestHitTester(Sender<Arc<dyn ApiHitTester>>),
///
@@ -1297,12 +1298,13 @@ impl RenderApi {
document_id: DocumentId,
pipeline_id: Option<PipelineId>,
point: WorldPoint,
+ flags: HitTestFlags,
) -> HitTestResult {
let (tx, rx) = single_msg_channel();
self.send_frame_msg(
document_id,
- FrameMsg::HitTest(pipeline_id, point, tx)
+ FrameMsg::HitTest(pipeline_id, point, flags, tx)
);
rx.recv().unwrap()
}
diff --git a/webrender/src/render_backend.rs b/webrender/src/render_backend.rs
index 96bc600484..825e981b5c 100644
--- a/webrender/src/render_backend.rs
+++ b/webrender/src/render_backend.rs
@@ -535,14 +535,14 @@ impl Document {
FrameMsg::UpdateEpoch(pipeline_id, epoch) => {
self.scene.pipeline_epochs.insert(pipeline_id, epoch);
}
- FrameMsg::HitTest(pipeline_id, point, tx) => {
+ FrameMsg::HitTest(pipeline_id, point, flags, tx) => {
if !self.hit_tester_is_valid {
self.rebuild_hit_tester();
}
let result = match self.hit_tester {
Some(ref hit_tester) => {
- hit_tester.hit_test(HitTest::new(pipeline_id, point))
+ hit_tester.hit_test(HitTest::new(pipeline_id, point, flags))
}
None => HitTestResult { items: Vec::new() },
};
diff --git a/webrender_api/src/lib.rs b/webrender_api/src/lib.rs
index 7dc887ade9..b0446c1d0b 100644
--- a/webrender_api/src/lib.rs
+++ b/webrender_api/src/lib.rs
@@ -278,7 +278,7 @@ pub trait ApiHitTester: Send + Sync {
/// hit results so that only items inside that pipeline are matched. The vector
/// of hit results will contain all display items that match, ordered from
/// front to back.
- fn hit_test(&self, pipeline_id: Option<PipelineId>, point: WorldPoint) -> HitTestResult;
+ fn hit_test(&self, pipeline_id: Option<PipelineId>, point: WorldPoint, flags: HitTestFlags) -> HitTestResult;
}
/// A hit tester requested to the render backend thread but not necessarily ready yet.
@@ -322,6 +322,17 @@ pub struct HitTestResult {
pub items: Vec<HitTestItem>,
}
+bitflags! {
+ #[derive(Deserialize, MallocSizeOf, Serialize)]
+ ///
+ pub struct HitTestFlags: u8 {
+ ///
+ const FIND_ALL = 0b00000001;
+ ///
+ const POINT_RELATIVE_TO_PIPELINE_VIEWPORT = 0b00000010;
+ }
+}
+
impl Drop for NotificationRequest {
fn drop(&mut self) {
if let Some(ref mut handler) = self.handler {
diff --git a/wrench/src/main.rs b/wrench/src/main.rs
index 7dc037ebb2..843512f595 100644
--- a/wrench/src/main.rs
+++ b/wrench/src/main.rs
@@ -965,6 +965,7 @@ fn render<'a>(
wrench.document_id,
None,
cursor_position,
+ HitTestFlags::empty(),
);
println!("Hit test results:");
diff --git a/wrench/src/rawtest.rs b/wrench/src/rawtest.rs
index 580f1cb015..b86b583617 100644
--- a/wrench/src/rawtest.rs
+++ b/wrench/src/rawtest.rs
@@ -1393,6 +1393,7 @@ impl<'a> RawtestHarness<'a> {
self.wrench.document_id,
None,
point,
+ HitTetFlags::empty(),
)
};

View file

@ -0,0 +1,62 @@
diff --git a/example-compositor/compositor/Cargo.toml b/example-compositor/compositor/Cargo.toml
index 4202332c41..02c6ebe0ce 100644
--- a/example-compositor/compositor/Cargo.toml
+++ b/example-compositor/compositor/Cargo.toml
@@ -7,7 +7,7 @@ license = "MPL-2.0"
[dependencies]
webrender = { path = "../../webrender" }
-gleam = "0.13.1"
+gleam = "0.15"
[target.'cfg(windows)'.dependencies]
compositor-windows = { path = "../compositor-windows" }
diff --git a/examples/Cargo.toml b/examples/Cargo.toml
index 556b67d1ed..f1a4718b04 100644
--- a/examples/Cargo.toml
+++ b/examples/Cargo.toml
@@ -57,7 +57,7 @@ debug = ["webrender/capture", "webrender/profiler"]
app_units = "0.7"
env_logger = "0.5"
euclid = "0.22"
-gleam = "0.13"
+gleam = "0.15"
glutin = "0.21"
rayon = "1"
webrender = { path = "../webrender" }
diff --git a/swgl/Cargo.toml b/swgl/Cargo.toml
index 9b7624b13e..2e84e2267c 100644
--- a/swgl/Cargo.toml
+++ b/swgl/Cargo.toml
@@ -12,4 +12,4 @@ glsl-to-cxx = { path = "../glsl-to-cxx" }
webrender_build = { path = "../webrender_build" }
[dependencies]
-gleam = "0.13.1"
+gleam = "0.15"
diff --git a/webrender/Cargo.toml b/webrender/Cargo.toml
index 40064a1573..e82ac85718 100644
--- a/webrender/Cargo.toml
+++ b/webrender/Cargo.toml
@@ -33,7 +33,7 @@ byteorder = "1.0"
cstr = "0.2"
euclid = { version = "0.22.0", features = ["serde"] }
fxhash = "0.2.1"
-gleam = "0.13.1"
+gleam = "0.15"
lazy_static = "1"
log = "0.4"
malloc_size_of_derive = "0.1"
diff --git a/wrench/Cargo.toml b/wrench/Cargo.toml
index 7d2345be43..f51e4202ff 100644
--- a/wrench/Cargo.toml
+++ b/wrench/Cargo.toml
@@ -9,7 +9,7 @@ edition = "2018"
[dependencies]
base64 = "0.12"
env_logger = { version = "0.5", optional = true }
-gleam = "0.13"
+gleam = "0.15"
glutin = "0.21"
clap = { version = "2", features = ["yaml"] }
log = "0.4"

View file

@ -0,0 +1,221 @@
diff --git a/webrender/build.rs b/webrender/build.rs
index 60b4a96c23..adc5dbf2e8 100644
--- a/webrender/build.rs
+++ b/webrender/build.rs
@@ -2,8 +2,6 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-extern crate webrender_build;
-
use std::borrow::Cow;
use std::env;
use std::fs::{canonicalize, read_dir, File};
diff --git a/webrender/src/device/gl.rs b/webrender/src/device/gl.rs
index eb272e56d6..5e0c050378 100644
--- a/webrender/src/device/gl.rs
+++ b/webrender/src/device/gl.rs
@@ -386,6 +386,7 @@ impl<T> Drop for VBO<T> {
pub struct ExternalTexture {
id: gl::GLuint,
target: gl::GLuint,
+ #[allow(dead_code)]
swizzle: Swizzle,
uv_rect: TexelRect,
}
diff --git a/webrender/src/hit_test.rs b/webrender/src/hit_test.rs
index e095d8db0c..0bd02cd426 100644
--- a/webrender/src/hit_test.rs
+++ b/webrender/src/hit_test.rs
@@ -6,10 +6,9 @@ use api::{BorderRadius, ClipMode, HitTestItem, HitTestResult, ItemTag, Primitive
use api::{PipelineId, ApiHitTester, ClipId};
use api::units::*;
use crate::clip::{ClipItemKind, ClipStore, ClipNode, rounded_rectangle_contains_point};
-use crate::clip::{polygon_contains_point};
+use crate::clip::polygon_contains_point;
use crate::prim_store::PolygonKey;
use crate::scene_builder_thread::Interners;
-use crate::spatial_node::SpatialNodeType;
use crate::spatial_tree::{SpatialNodeIndex, SpatialTree};
use crate::internal_types::{FastHashMap, FastHashSet, LayoutPrimitiveInfo};
use std::ops;
diff --git a/webrender/src/internal_types.rs b/webrender/src/internal_types.rs
index 07f937c6a0..9819850db0 100644
--- a/webrender/src/internal_types.rs
+++ b/webrender/src/internal_types.rs
@@ -536,6 +536,7 @@ pub enum ResultMsg {
#[derive(Clone, Debug)]
pub struct ResourceCacheError {
+ #[allow(dead_code)]
description: String,
}
diff --git a/webrender/src/lib.rs b/webrender/src/lib.rs
index 34bc9fb49b..cc200e30eb 100644
--- a/webrender/src/lib.rs
+++ b/webrender/src/lib.rs
@@ -71,8 +71,7 @@ extern crate serde;
extern crate tracy_rs;
#[macro_use]
extern crate derive_more;
-extern crate malloc_size_of;
-extern crate svg_fmt;
+use malloc_size_of;
#[macro_use]
mod profiler;
@@ -163,41 +162,14 @@ mod platform {
}
}
-#[cfg(target_os = "macos")]
-extern crate core_foundation;
-#[cfg(target_os = "macos")]
-extern crate core_graphics;
-#[cfg(target_os = "macos")]
-extern crate core_text;
-
-#[cfg(all(unix, not(target_os = "macos")))]
-extern crate freetype;
-#[cfg(all(unix, not(target_os = "macos")))]
-extern crate libc;
-
-#[cfg(target_os = "windows")]
-extern crate dwrote;
-
-extern crate bincode;
-extern crate byteorder;
-pub extern crate euclid;
-extern crate fxhash;
-extern crate gleam;
-extern crate num_traits;
-extern crate plane_split;
-extern crate rayon;
-#[cfg(feature = "ron")]
-extern crate ron;
+pub use euclid;
#[macro_use]
extern crate smallvec;
-extern crate time;
-#[cfg(all(feature = "capture", feature = "png"))]
-extern crate png;
#[cfg(test)]
-extern crate rand;
+use rand;
-pub extern crate api;
-extern crate webrender_build;
+pub use api;
+use webrender_build;
#[doc(hidden)]
pub use crate::composite::{CompositorConfig, Compositor, CompositorCapabilities, CompositorSurfaceTransform};
diff --git a/webrender/src/profiler.rs b/webrender/src/profiler.rs
index 40c091d617..702fa634ff 100644
--- a/webrender/src/profiler.rs
+++ b/webrender/src/profiler.rs
@@ -1362,6 +1362,7 @@ pub struct Counter {
change_indicator: u8,
/// Only used to check that the constants match the real index.
+ #[allow(dead_code)]
index: usize,
graph: Option<Graph>,
diff --git a/webrender/src/render_target.rs b/webrender/src/render_target.rs
index d31176047b..301ce4ec4d 100644
--- a/webrender/src/render_target.rs
+++ b/webrender/src/render_target.rs
@@ -10,7 +10,7 @@ use crate::batch::{ClipBatcher, BatchBuilder};
use crate::spatial_tree::{SpatialTree, ROOT_SPATIAL_NODE_INDEX};
use crate::clip::ClipStore;
use crate::composite::CompositeState;
-use crate::frame_builder::{FrameGlobalResources};
+use crate::frame_builder::FrameGlobalResources;
use crate::gpu_cache::{GpuCache, GpuCacheAddress};
use crate::gpu_types::{BorderInstance, SvgFilterInstance, BlurDirection, BlurInstance, PrimitiveHeaders, ScalingInstance};
use crate::gpu_types::{TransformPalette, ZBufferIdGenerator};
@@ -819,10 +819,10 @@ fn add_svg_filter_instances(
let generic_int = match filter {
SvgFilterInfo::Blend(mode) => *mode as u16,
SvgFilterInfo::ComponentTransfer(data) =>
- ((data.r_func.to_int() << 12 |
+ (data.r_func.to_int() << 12 |
data.g_func.to_int() << 8 |
data.b_func.to_int() << 4 |
- data.a_func.to_int()) as u16),
+ data.a_func.to_int()) as u16,
SvgFilterInfo::Composite(operator) =>
operator.as_int() as u16,
SvgFilterInfo::LinearToSrgb |
diff --git a/webrender_api/src/image.rs b/webrender_api/src/image.rs
index 238d004814..23c660b647 100644
--- a/webrender_api/src/image.rs
+++ b/webrender_api/src/image.rs
@@ -326,10 +326,9 @@ pub enum ImageData {
}
mod serde_image_data_raw {
- extern crate serde_bytes;
-
- use std::sync::Arc;
use serde::{Deserializer, Serializer};
+ use serde_bytes;
+ use std::sync::Arc;
pub fn serialize<S: Serializer>(bytes: &Arc<Vec<u8>>, serializer: S) -> Result<S::Ok, S::Error> {
serde_bytes::serialize(bytes.as_slice(), serializer)
diff --git a/webrender_api/src/lib.rs b/webrender_api/src/lib.rs
index b0446c1d0b..f5cda1fbf6 100644
--- a/webrender_api/src/lib.rs
+++ b/webrender_api/src/lib.rs
@@ -15,29 +15,20 @@
#![cfg_attr(feature = "cargo-clippy", allow(clippy::float_cmp, clippy::too_many_arguments))]
#![cfg_attr(feature = "cargo-clippy", allow(clippy::unreadable_literal, clippy::new_without_default))]
-pub extern crate crossbeam_channel;
-pub extern crate euclid;
+pub use crossbeam_channel;
+pub use euclid;
-extern crate app_units;
#[macro_use]
extern crate bitflags;
-extern crate byteorder;
#[cfg(feature = "nightly")]
extern crate core;
-#[cfg(target_os = "macos")]
-extern crate core_foundation;
-#[cfg(target_os = "macos")]
-extern crate core_graphics;
-extern crate derive_more;
#[macro_use]
extern crate malloc_size_of_derive;
-extern crate serde;
#[macro_use]
extern crate serde_derive;
-extern crate time;
-extern crate malloc_size_of;
-extern crate peek_poke;
+use malloc_size_of;
+use peek_poke;
pub mod channel;
mod color;
diff --git a/wr_malloc_size_of/lib.rs b/wr_malloc_size_of/lib.rs
index 38b049095e..abd982ffe8 100644
--- a/wr_malloc_size_of/lib.rs
+++ b/wr_malloc_size_of/lib.rs
@@ -10,8 +10,8 @@
//! A reduced fork of Firefox's malloc_size_of crate, for bundling with WebRender.
-extern crate app_units;
-extern crate euclid;
+use app_units;
+use euclid;
use std::hash::{BuildHasher, Hash};
use std::mem::size_of;

View file

@ -1 +1 @@
1175acad2d4f49fa712e105c84149ac7f394261d
e491e1ae637b2eed1e7195855d88357e5eb3ddf9

View file

@ -1,7 +1,3 @@
0001-Add-signal-handler-to-catch-segfault-in-build-script.patch
0002-Bug-1646741-Update-gleam-to-0.12.-r-kvark.patch
0003-Bug-1651889.-Update-to-gleam-0.12.1.-r-kvark.patch
0004-Bug-1654699.-Update-core-foundation-core-graphics.-r.patch
0005-Bug-1656236-Update-to-euclid-0.22.-r-kvark.patch
0006-Bump-procedural-masquerade-to-0.1.7.patch
0007-Fix-warnings.patch
001-Restore-hit-testing-api.diff
002-Upgrade-version-of-gleam.diff
003-Fix-WebRender-warnings.diff

View file

@ -43,10 +43,7 @@ fn get_discriminant_size_type(len: usize) -> TokenStream {
fn is_struct(s: &Structure) -> bool {
// a single variant with no prefix is 'struct'
match &s.variants()[..] {
[v] if v.prefix.is_none() => true,
_ => false,
}
matches!(&s.variants()[..], [v] if v.prefix.is_none())
}
fn derive_max_size(s: &Structure) -> TokenStream {
@ -223,7 +220,7 @@ fn peek_poke_derive(mut s: Structure) -> TokenStream {
};
let poke_impl = s.gen_impl(quote! {
use peek_poke;
extern crate peek_poke;
gen unsafe impl peek_poke::Poke for @Self {
#max_size_fn
@ -249,7 +246,7 @@ fn peek_poke_derive(mut s: Structure) -> TokenStream {
let peek_impl = quote! {
#[allow(non_upper_case_globals)]
const #dummy_const: () = {
use peek_poke;
extern crate peek_poke;
impl #impl_generics peek_poke::Peek for #name #ty_generics #where_clause {
#peek_from_fn

View file

@ -9,7 +9,7 @@
// except according to those terms.
use crate::{Peek, Poke};
use euclid::{Point2D, Rect, SideOffsets2D, Size2D, Transform3D, Vector2D};
use euclid::{Point2D, Rect, Box2D, SideOffsets2D, Size2D, Transform3D, Vector2D};
unsafe impl<T: Poke, U> Poke for Point2D<T, U> {
#[inline(always)]
@ -53,6 +53,27 @@ impl<T: Peek, U> Peek for Rect<T, U> {
}
}
unsafe impl<T: Poke, U> Poke for Box2D<T, U> {
#[inline(always)]
fn max_size() -> usize {
Point2D::<T, U>::max_size() * 2
}
#[inline(always)]
unsafe fn poke_into(&self, bytes: *mut u8) -> *mut u8 {
let bytes = self.min.poke_into(bytes);
let bytes = self.max.poke_into(bytes);
bytes
}
}
impl<T: Peek, U> Peek for Box2D<T, U> {
#[inline(always)]
unsafe fn peek_from(bytes: *const u8, output: *mut Self) -> *const u8 {
let bytes = Point2D::<T, U>::peek_from(bytes, &mut (*output).min);
let bytes = Point2D::<T, U>::peek_from(bytes, &mut (*output).max);
bytes
}
}
unsafe impl<T: Poke, U> Poke for SideOffsets2D<T, U> {
#[inline(always)]
fn max_size() -> usize {

View file

@ -113,6 +113,20 @@ pub fn ensure_red_zone<T: Poke>(bytes: &mut Vec<u8>) {
}
}
/// Remove the "red zone" (padding of zeroes) from the end of the vec of `bytes`.
/// This is effectively the inverse of `ensure_red_zone`, with the caveat that
/// space reserved for the red zone is not un-reserved. Callers are repsonsible
/// for making sure the vec actually has a red zone, otherwise data bytes can
/// get stripped instead.
pub fn strip_red_zone<T: Poke>(bytes: &mut Vec<u8>) {
assert!(bytes.len() >= T::max_size());
unsafe {
let end_ptr = bytes.as_end_mut_ptr();
end_ptr.write_bytes(0, T::max_size());
bytes.set_end_ptr(end_ptr.sub(T::max_size()));
}
}
#[inline]
unsafe fn read_verbatim<T>(src: *const u8, dst: *mut T) -> *const u8 {
*dst = (src as *const T).read_unaligned();

View file

@ -6,18 +6,17 @@ check-alphabetical-order = false
[ignore]
# Ignored packages with duplicated versions
packages = [
"cfg-if",
"core-foundation",
"core-foundation-sys",
"core-graphics",
"gl_generator",
"gleam",
"rand",
"rand_core",
# https://github.com/trimental/andrew/issues/5
"rusttype",
# https://bugzilla.mozilla.org/show_bug.cgi?id=1615148
"smallvec",
"winapi",
"yaml-rust",
# These are tracked in bug 1587468, see there for pending work.
"proc-macro2",

View file

@ -12,4 +12,4 @@ glsl-to-cxx = { path = "../glsl-to-cxx" }
webrender_build = { path = "../webrender_build" }
[dependencies]
gleam = "0.12.0"
gleam = "0.15"

View file

@ -1,4 +1,220 @@
swgl
========
# swgl
Software OpenGL implementation for WebRender
## Overview
This is a relatively simple single threaded software rasterizer designed
for use by WebRender. It will shade one quad at a time using a 4xf32 vector
with one vertex per lane. It rasterizes quads usings spans and shades that
span 4 pixels at a time.
## Building
clang-cl is required to build on Windows. This can be done by installing
the llvm binaries from https://releases.llvm.org/ and adding the installation
to the path with something like `set PATH=%PATH%;C:\Program Files\LLVM\bin`.
Then `set CC=clang-cl` and `set CXX=clang-cl`. That should be sufficient
for `cc-rs` to use `clang-cl` instead of `cl`.
## Extensions
SWGL contains a number of OpenGL and GLSL extensions designed to both ease
integration with WebRender and to help accelerate span rasterization.
GLSL extension intrinsics are generally prefixed with `swgl_` to distinguish
them from other items in the GLSL namespace.
Inside GLSL, the `SWGL` preprocessor token is defined so that usage of SWGL
extensions may be conditionally compiled.
```
void swgl_drawSpanRGBA8();
void swgl_drawSpanR8();
int swgl_SpanLength;
int swgl_StepSize;
mixed swgl_interpStep(mixed varying_input);
void swgl_stepInterp();
```
SWGL's default fragment processing calls a fragment shader's `main` function
on groups of fragments in units of `swgl_StepSize`. On return, the value of
gl_FragColor is read, packed to an appropriate pixel format, and sent to the
blend stage for output to the destination framebuffer. This can be inefficient
for some types of fragment shaders, such as those that must lookup from a
texture and immediately output it, unpacking the texels only to subsequently
repack them at cost. Also, various per-fragment conditions in the shader might
need to be repeatedly checked, even though they are actually constant over
the entire primitive.
To work around this inefficiency, SWGL allows fragments to optionally be
processed over entire spans. This can both side-step the packing inefficiency
as well as more efficiently deal with conditions that remain constant over an
entire span. SWGL also introduces various specialized intrinsics for more
efficiently dealing with certain types of primitive spans with optimal
fixed-function processing.
Inside a fragment shader, a `swgl_drawSpan` function may be defined to override
the normal fragment processing for that fragment shader. The function must then
call some form of `swgl_commit` intrinsic to actually output to the destination
framebuffer via the blend stage, as normal fragment processing does not take
place otherwise as would have happened in `main`. This function is used by the
rasterizer to process an entire span of fragments that have passed the depth
test (if applicable) and clipping, but have not yet been output to the blend
stage.
The amount of fragments within the span to be processed is designated by
`swgl_SpanLength` and is always aligned to units of `swgl_StepSize`.
The size of a group of fragments in terms of which `swgl_commit` intrinsics
process and output fragments is designated by `swgl_StepSize`. The
`swgl_commit` intrinsics will deduct accordingly from `swgl_SpanLength` in
units of `swgl_StepSize` to reflect the fragments actually processed, which
may be less than the entire span or up to the entire span.
Fragments should be output until `swgl_SpanLength` becomes zero to process the
entire span. If `swgl_drawSpan` returns while leaving any fragments unprocessed,
the remaining fragments will be processed as normal by the fragment shader's
`main` function. This can be used to conditionally handle certain fast-paths
in a fragment shader by otherwise defaulting to the `main` function if
`swgl_drawSpan` can't appropriately process some or all of the fragments.
The values of any varying inputs to the fragment shader will be set to their
values for the start of the span, but do not automatically update over the
the course of a span within a given call to `swgl_drawSpan`. The
`swgl_interpStep` intrinsic may be used to get the derivative per `swgl_StepSize`
group of fragments of a varying input so that the caller may update such
variables manually if desired or otherwise use that information for processing.
The `swgl_stepInterp` intrinsic forces all such varying inputs to advance by
a single step.
The RGBA8 version will be used when the destination framebuffer is RGBA8 format,
and the R8 version will be used when the destination framebuffer is R8. Various
other intrinsics described below may have restrictions on whether they can be
used only with a certain destination framebuffer format and are noted as such if
so.
```
void swgl_clipMask(sampler2D mask, vec2 offset, vec2 bb_origin, vec2 bb_size);
```
When called from the the vertex shader, this specifies a clip mask texture to
be used to mask the currently drawn primitive while blending is enabled. This
mask will only apply to the current primitive.
The mask must be an R8 texture that will be interpreted as alpha weighting
applied to the source pixel prior to the blend stage. It is sampled 1:1 with
nearest filtering without any applied transform. The given offset specifies
the positioning of the clip mask relative to the framebuffer's viewport.
The supplied bounding box constrains sampling of the clip mask to only fall
within the given rectangle, specified relative to the clip mask offset.
Anything falling outside this rectangle will be clipped entirely. If the
rectangle is empty, then the clip mask will be ignored.
```
void swgl_antiAlias(int edgeMask);
```
When called from the vertex shader, this enables anti-aliasing for the
currently drawn primitive while blending is enabled. This setting will only
apply to the current primitive. Anti-aliasing will be applied only to the
edges corresponding to bits supplied in the mask. For simple use-cases,
the edge mask can be set to all 1 bits to enable AA for the entire quad.
The order of the bits in the edge mask must match the winding order in which
the vertices are output in the vertex shader if processed as a quad, so that
the edge ends on that vertex. The easiest way to understand this ordering
is that for a rectangle (x0,y0,x1,y1) then the edge Nth edge bit corresponds
to the edge where Nth coordinate in the rectangle is constant.
SWGL tries to use an anti-aliasing method that is reasonably close to WR's
signed-distance field approximation. WR would normally try to discern the
2D local-space coordinates of a given destination pixel relative to the
2D local-space bounding rectangle of a primitive. It then uses the screen-
space derivative to try to determine the how many local-space units equate
to a distance of around one screen-space pixel. A distance approximation
of coverage is then used based on the distance in local-space from the
the current pixel's center, roughly at half-intensity at pixel center
and ranging to zero or full intensity within a radius of half a pixel
away from the center. To account for AAing going outside the normal geometry
boundaries of the primitive, WR has to extrude the primitive by a local-space
estimate to allow some AA to happen within the extruded region.
SWGL can ultimately do this approximation more simply and get around the
extrusion limitations by just ensuring spans encompass any pixel that is
partially covered when computing span boundaries. Further, since SWGL already
knows the slope of an edge and the coordinate of the span relative to the span
boundaries, finding the partial coverage of a given span becomes easy to do
without requiring any extra interpolants to track against local-space bounds.
Essentially, SWGL just performs anti-aliasing on the actual geometry bounds,
but when the pixels on a span's edge are determined to be partially covered
during span rasterization, it uses the same distance field method as WR on
those span boundary pixels to estimate the coverage based on edge slope.
```
void swgl_commitTextureLinearRGBA8(sampler, vec2 uv, vec4 uv_bounds);
void swgl_commitTextureLinearR8(sampler, vec2 uv, vec4 uv_bounds);
void swgl_commitTextureLinearR8ToRGBA8(sampler, vec2 uv, vec4 uv_bounds);
void swgl_commitTextureLinearColorRGBA8(sampler, vec2 uv, vec4 uv_bounds, vec4|float color);
void swgl_commitTextureLinearColorR8(sampler, vec2 uv, vec4 uv_bounds, vec4|float color);
void swgl_commitTextureLinearColorR8ToRGBA8(sampler, vec2 uv, vec4 uv_bounds, vec4|float color);
void swgl_commitTextureLinearRepeatRGBA8(sampler, vec2 uv, vec2 tile_repeat, vec4 uv_repeat, vec4 uv_bounds);
void swgl_commitTextureLinearRepeatColorRGBA8(sampler, vec2 uv, vec2 tile_repeat, vec4 uv_repeat, vec4 uv_bounds, vec4|float color);
void swgl_commitTextureNearestRGBA8(sampler, vec2 uv, vec4 uv_bounds);
void swgl_commitTextureNearestColorRGBA8(sampler, vec2 uv, vec4 uv_bounds, vec4|float color);
void swgl_commitTextureNearestRepeatRGBA8(sampler, vec2 uv, vec2 tile_repeat, vec4 uv_repeat, vec4 uv_bounds);
void swgl_commitTextureNearestRepeatColorRGBA8(sampler, vec2 uv, vec2 tile_repeat, vec4 uv_repeat, vec4 uv_bounds, vec4|float color);
void swgl_commitTextureRGBA8(sampler, vec2 uv, vec4 uv_bounds);
void swgl_commitTextureColorRGBA8(sampler, vec2 uv, vec4 uv_bounds, vec4|float color);
void swgl_commitTextureRepeatRGBA8(sampler, vec2 uv, vec2 tile_repeat, vec4 uv_repeat, vec4 uv_bounds);
void swgl_commitTextureRepeatColorRGBA8(sampler, vec2 uv, vec2 tile_repeat, vec4 uv_repeat, vec4 uv_bounds, vec4|float color);
void swgl_commitPartialTextureLinearR8(int len, sampler, vec2 uv, vec4 uv_bounds);
void swgl_commitPartialTextureLinearInvertR8(int len, sampler, vec2 uv, vec4 uv_bounds);
```
Samples and commits an entire span of texture starting at the given uv and
within the supplied uv bounds. The color variations also accept a supplied color
that modulates the result.
The RGBA8 versions may only be used to commit within `swgl_drawSpanRGBA8`, and
the R8 versions may only be used to commit within `swgl_drawSpanR8`. The R8ToRGBA8
versions may be used to sample from an R8 source while committing to an RGBA8
framebuffer.
The Linear variations use a linear filter that bilinearly interpolates between
the four samples near the pixel. The Nearest variations use a nearest filter
that chooses the closest aliased sample to the center of the pixel. If neither
Linear nor Nearest is specified in the `swgl_commitTexture` variation name, then
it will automatically select either the Linear or Nearest variation depending
on the sampler's specified filter.
The Repeat variations require an optional repeat rect that specifies how to
scale and offset the UVs, assuming the UVs are normalized to repeat in the
range 0 to 1. For NearestRepeat variations, it is assumed the repeat rect is
always within the bounds. The tile repeat limit, if non-zero, specifies the
maximum number of repetitions allowed.
The Partial variations allow committing only a sub-span rather the entire
remaining span. These are currently only implemented in linear R8 variants
for optimizing clip shaders in WebRender. The Invert variant of these is
useful for implementing clip-out modes by inverting the source texture value.
```
// Premultiplied alpha over blend, but with source color set to source alpha modulated with a constant color.
void swgl_blendDropShadow(vec4 color);
// Premultiplied alpha over blend, but treats the source as a subpixel mask modulated with a constant color.
void swgl_blendSubpixelText(vec4 color);
```
SWGL allows overriding the blend mode per-primitive by calling `swgl_blend`
intrinsics in the vertex shader. The existing blend mode set by the GL is
replaced with the one specified by the intrinsic for the current primitive.
The blend mode will be reset to the blend mode set by the GL for the next
primitive after the current one, even within the same draw call.

View file

@ -2,9 +2,9 @@
* 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 cc;
use glsl_to_cxx;
use webrender_build;
extern crate cc;
extern crate glsl_to_cxx;
extern crate webrender_build;
use std::collections::HashSet;
use std::fmt::Write;
@ -52,7 +52,7 @@ fn process_imports(shader_dir: &str, shader: &str, included: &mut HashSet<String
}
fn translate_shader(shader_key: &str, shader_dir: &str) {
let mut imported = String::from("#define SWGL 1\n");
let mut imported = String::from("#define SWGL 1\n#define __VERSION__ 150\n");
let _ = write!(imported, "#define WR_MAX_VERTEX_TEXTURE_WIDTH {}U\n",
webrender_build::MAX_VERTEX_TEXTURE_WIDTH);
@ -73,11 +73,21 @@ fn translate_shader(shader_key: &str, shader_dir: &str) {
std::fs::write(&imp_name, imported).unwrap();
let mut build = cc::Build::new();
if build.get_compiler().is_like_msvc() {
build.flag("/EP");
} else {
build.flag("-xc").flag("-P");
build.no_default_flags(true);
if let Ok(tool) = build.try_get_compiler() {
if tool.is_like_msvc() {
build.flag("/EP");
if tool.path().to_str().map_or(false, |p| p.contains("clang")) {
build.flag("/clang:-undef");
} else {
build.flag("/u");
}
} else {
build.flag("-xc").flag("-P").flag("-undef");
}
}
// Use SWGLPP target to avoid pulling CFLAGS/CXXFLAGS.
build.target("SWGLPP");
build.file(&imp_name);
let vs = build.clone()
.define("WR_VERTEX_SHADER", Some("1"))
@ -90,16 +100,11 @@ fn translate_shader(shader_key: &str, shader_dir: &str) {
std::fs::write(&vs_name, vs).unwrap();
std::fs::write(&fs_name, fs).unwrap();
let mut args = vec![
let args = vec![
"glsl_to_cxx".to_string(),
vs_name,
fs_name,
];
let frag_include = format!("{}/{}.frag.h", shader_dir, shader);
if std::path::Path::new(&frag_include).exists() {
println!("cargo:rerun-if-changed={}/{}.frag.h", shader_dir, shader);
args.push(frag_include);
}
let result = glsl_to_cxx::translate(&mut args.into_iter());
std::fs::write(format!("{}/{}.h", out_dir, shader), result).unwrap();
}
@ -112,7 +117,9 @@ fn main() {
let shader_flags =
ShaderFeatureFlags::GL |
ShaderFeatureFlags::DUAL_SOURCE_BLENDING;
ShaderFeatureFlags::DUAL_SOURCE_BLENDING |
ShaderFeatureFlags::ADVANCED_BLEND_EQUATION |
ShaderFeatureFlags::DEBUG;
let mut shaders: Vec<String> = Vec::new();
for (name, features) in get_shader_features(shader_flags) {
shaders.extend(features.iter().map(|f| {
@ -122,26 +129,74 @@ fn main() {
shaders.sort();
// We need to ensure that the C preprocessor does not pull compiler flags from
// the host or target environment. Set up a SWGLPP target with empty flags to
// work around this.
if let Ok(target) = std::env::var("TARGET") {
if let Ok(cc) = std::env::var(format!("CC_{}", target))
.or(std::env::var(format!("CC_{}", target.replace("-", "_")))) {
std::env::set_var("CC_SWGLPP", cc);
}
}
std::env::set_var("CFLAGS_SWGLPP", "");
for shader in &shaders {
translate_shader(shader, &shader_dir);
}
write_load_shader(&shaders);
println!("cargo:rerun-if-changed=src/blend.h");
println!("cargo:rerun-if-changed=src/composite.h");
println!("cargo:rerun-if-changed=src/gl_defs.h");
println!("cargo:rerun-if-changed=src/glsl.h");
println!("cargo:rerun-if-changed=src/program.h");
println!("cargo:rerun-if-changed=src/rasterize.h");
println!("cargo:rerun-if-changed=src/swgl_ext.h");
println!("cargo:rerun-if-changed=src/texture.h");
println!("cargo:rerun-if-changed=src/vector_type.h");
println!("cargo:rerun-if-changed=src/gl.cc");
cc::Build::new()
.cpp(true)
.file("src/gl.cc")
.flag("-std=c++14")
.flag("-UMOZILLA_CONFIG_H")
.flag("-fno-exceptions")
.flag("-fno-rtti")
.flag("-fno-math-errno")
let mut build = cc::Build::new();
build.cpp(true);
if let Ok(tool) = build.try_get_compiler() {
if tool.is_like_msvc() {
build.flag("/std:c++17")
.flag("/EHs-")
.flag("/GR-")
.flag("/UMOZILLA_CONFIG_H");
} else {
build.flag("-std=c++17")
.flag("-fno-exceptions")
.flag("-fno-rtti")
.flag("-fno-math-errno")
.flag("-UMOZILLA_CONFIG_H");
}
// SWGL relies heavily on inlining for performance so override -Oz with -O2
if tool.args().contains(&"-Oz".into()) {
build.flag("-O2");
}
// Most GLSL compilers assume something like fast-math so we turn it on.
// However, reciprocal division makes it so 1/1 = 0.999994 which can produce a lot of fuzz
// in reftests and the use of reciprocal instructions usually involves a refinement step
// which bloats our already bloated code. Further, our shader code is sufficiently parallel
// that we're more likely to be throughput bound vs latency bound. Having fewer
// instructions makes things easier on the processor and in places where it matters we can
// probably explicitly use reciprocal instructions and avoid the refinement step.
if tool.is_like_msvc() {
build.flag("/fp:fast")
.flag("-Xclang")
.flag("-mrecip=none");
} else if tool.is_like_clang() {
// gcc only supports -mrecip=none on some targets so to keep
// things simple we don't use -ffast-math with gcc at all
build.flag("-ffast-math")
.flag("-mrecip=none");
}
}
build.file("src/gl.cc")
.define("_GLIBCXX_USE_CXX11_ABI", Some("0"))
.include(shader_dir)
.include("src")

864
third_party/webrender/swgl/src/blend.h vendored Normal file
View file

@ -0,0 +1,864 @@
/* 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/. */
static ALWAYS_INLINE HalfRGBA8 packRGBA8(I32 a, I32 b) {
#if USE_SSE2
return _mm_packs_epi32(a, b);
#elif USE_NEON
return vcombine_u16(vqmovun_s32(a), vqmovun_s32(b));
#else
return CONVERT(combine(a, b), HalfRGBA8);
#endif
}
static ALWAYS_INLINE WideRGBA8 pack_pixels_RGBA8(const vec4& v,
float scale = 255.0f) {
ivec4 i = round_pixel(v, scale);
HalfRGBA8 xz = packRGBA8(i.z, i.x);
HalfRGBA8 yw = packRGBA8(i.y, i.w);
HalfRGBA8 xyzwl = zipLow(xz, yw);
HalfRGBA8 xyzwh = zipHigh(xz, yw);
HalfRGBA8 lo = zip2Low(xyzwl, xyzwh);
HalfRGBA8 hi = zip2High(xyzwl, xyzwh);
return combine(lo, hi);
}
static ALWAYS_INLINE WideRGBA8 pack_pixels_RGBA8(Float alpha,
float scale = 255.0f) {
I32 i = round_pixel(alpha, scale);
HalfRGBA8 c = packRGBA8(i, i);
c = zipLow(c, c);
return zip(c, c);
}
static ALWAYS_INLINE WideRGBA8 pack_pixels_RGBA8(float alpha,
float scale = 255.0f) {
I32 i = round_pixel(alpha, scale);
return repeat2(packRGBA8(i, i));
}
UNUSED static ALWAYS_INLINE WideRGBA8 pack_pixels_RGBA8(const vec4_scalar& v,
float scale = 255.0f) {
I32 i = round_pixel((Float){v.z, v.y, v.x, v.w}, scale);
return repeat2(packRGBA8(i, i));
}
static ALWAYS_INLINE WideRGBA8 pack_pixels_RGBA8() {
return pack_pixels_RGBA8(fragment_shader->gl_FragColor);
}
static ALWAYS_INLINE WideRGBA8 pack_pixels_RGBA8(WideRGBA32F v,
float scale = 255.0f) {
ivec4 i = round_pixel(bit_cast<vec4>(v), scale);
return combine(packRGBA8(i.x, i.y), packRGBA8(i.z, i.w));
}
static ALWAYS_INLINE WideR8 packR8(I32 a) {
#if USE_SSE2
return lowHalf(bit_cast<V8<uint16_t>>(_mm_packs_epi32(a, a)));
#elif USE_NEON
return vqmovun_s32(a);
#else
return CONVERT(a, WideR8);
#endif
}
static ALWAYS_INLINE WideR8 pack_pixels_R8(Float c, float scale = 255.0f) {
return packR8(round_pixel(c, scale));
}
static ALWAYS_INLINE WideR8 pack_pixels_R8() {
return pack_pixels_R8(fragment_shader->gl_FragColor.x);
}
// Load a partial span > 0 and < 4 pixels.
template <typename V, typename P>
static ALWAYS_INLINE V partial_load_span(const P* src, int span) {
return bit_cast<V>(
(span >= 2
? combine(unaligned_load<V2<P>>(src),
V2<P>{span > 2 ? unaligned_load<P>(src + 2) : P(0), 0})
: V4<P>{unaligned_load<P>(src), 0, 0, 0}));
}
// Store a partial span > 0 and < 4 pixels.
template <typename V, typename P>
static ALWAYS_INLINE void partial_store_span(P* dst, V src, int span) {
auto pixels = bit_cast<V4<P>>(src);
if (span >= 2) {
unaligned_store(dst, lowHalf(pixels));
if (span > 2) {
unaligned_store(dst + 2, pixels.z);
}
} else {
unaligned_store(dst, pixels.x);
}
}
// Dispatcher that chooses when to load a full or partial span
template <typename V, typename P>
static ALWAYS_INLINE V load_span(const P* src, int span) {
if (span >= 4) {
return unaligned_load<V, P>(src);
} else {
return partial_load_span<V, P>(src, span);
}
}
// Dispatcher that chooses when to store a full or partial span
template <typename V, typename P>
static ALWAYS_INLINE void store_span(P* dst, V src, int span) {
if (span >= 4) {
unaligned_store<V, P>(dst, src);
} else {
partial_store_span<V, P>(dst, src, span);
}
}
template <typename T>
static ALWAYS_INLINE T muldiv256(T x, T y) {
return (x * y) >> 8;
}
// (x*y + x) >> 8, cheap approximation of (x*y) / 255
template <typename T>
static ALWAYS_INLINE T muldiv255(T x, T y) {
return (x * y + x) >> 8;
}
template <typename V>
static ALWAYS_INLINE WideRGBA8 pack_span(uint32_t*, const V& v,
float scale = 255.0f) {
return pack_pixels_RGBA8(v, scale);
}
template <typename C>
static ALWAYS_INLINE WideR8 pack_span(uint8_t*, C c, float scale = 255.0f) {
return pack_pixels_R8(c, scale);
}
// Helper functions to apply a color modulus when available.
struct NoColor {};
template <typename P>
static ALWAYS_INLINE P applyColor(P src, NoColor) {
return src;
}
struct InvertColor {};
template <typename P>
static ALWAYS_INLINE P applyColor(P src, InvertColor) {
return 255 - src;
}
template <typename P>
static ALWAYS_INLINE P applyColor(P src, P color) {
return muldiv255(color, src);
}
static ALWAYS_INLINE WideRGBA8 applyColor(PackedRGBA8 src, WideRGBA8 color) {
return applyColor(unpack(src), color);
}
template <typename P, typename C>
static ALWAYS_INLINE auto packColor(P* buf, C color) {
return pack_span(buf, color, 255.0f);
}
template <typename P>
static ALWAYS_INLINE NoColor packColor(UNUSED P* buf, NoColor noColor) {
return noColor;
}
template <typename P>
static ALWAYS_INLINE InvertColor packColor(UNUSED P* buf,
InvertColor invertColor) {
return invertColor;
}
// Single argument variation that takes an explicit destination buffer type.
template <typename P, typename C>
static ALWAYS_INLINE auto packColor(C color) {
// Just pass in a typed null pointer, as the pack routines never use the
// pointer's value, just its type.
return packColor((P*)0, color);
}
// Byte-wise addition for when x or y is a signed 8-bit value stored in the
// low byte of a larger type T only with zeroed-out high bits, where T is
// greater than 8 bits, i.e. uint16_t. This can result when muldiv255 is used
// upon signed operands, using up all the precision in a 16 bit integer, and
// potentially losing the sign bit in the last >> 8 shift. Due to the
// properties of two's complement arithmetic, even though we've discarded the
// sign bit, we can still represent a negative number under addition (without
// requiring any extra sign bits), just that any negative number will behave
// like a large unsigned number under addition, generating a single carry bit
// on overflow that we need to discard. Thus, just doing a byte-wise add will
// overflow without the troublesome carry, giving us only the remaining 8 low
// bits we actually need while keeping the high bits at zero.
template <typename T>
static ALWAYS_INLINE T addlow(T x, T y) {
typedef VectorType<uint8_t, sizeof(T)> bytes;
return bit_cast<T>(bit_cast<bytes>(x) + bit_cast<bytes>(y));
}
// Replace color components of each pixel with the pixel's alpha values.
template <typename T>
static ALWAYS_INLINE T alphas(T c) {
return SHUFFLE(c, c, 3, 3, 3, 3, 7, 7, 7, 7, 11, 11, 11, 11, 15, 15, 15, 15);
}
// Replace the alpha values of the first vector with alpha values from the
// second, while leaving the color components unmodified.
template <typename T>
static ALWAYS_INLINE T set_alphas(T c, T a) {
return SHUFFLE(c, a, 0, 1, 2, 19, 4, 5, 6, 23, 8, 9, 10, 27, 12, 13, 14, 31);
}
// Miscellaneous helper functions for working with packed RGBA8 data.
static ALWAYS_INLINE HalfRGBA8 if_then_else(V8<int16_t> c, HalfRGBA8 t,
HalfRGBA8 e) {
return bit_cast<HalfRGBA8>((c & t) | (~c & e));
}
template <typename T, typename C, int N>
static ALWAYS_INLINE VectorType<T, N> if_then_else(VectorType<C, N> c,
VectorType<T, N> t,
VectorType<T, N> e) {
return combine(if_then_else(lowHalf(c), lowHalf(t), lowHalf(e)),
if_then_else(highHalf(c), highHalf(t), highHalf(e)));
}
static ALWAYS_INLINE HalfRGBA8 min(HalfRGBA8 x, HalfRGBA8 y) {
#if USE_SSE2
return bit_cast<HalfRGBA8>(
_mm_min_epi16(bit_cast<V8<int16_t>>(x), bit_cast<V8<int16_t>>(y)));
#elif USE_NEON
return vminq_u16(x, y);
#else
return if_then_else(x < y, x, y);
#endif
}
template <typename T, int N>
static ALWAYS_INLINE VectorType<T, N> min(VectorType<T, N> x,
VectorType<T, N> y) {
return combine(min(lowHalf(x), lowHalf(y)), min(highHalf(x), highHalf(y)));
}
static ALWAYS_INLINE HalfRGBA8 max(HalfRGBA8 x, HalfRGBA8 y) {
#if USE_SSE2
return bit_cast<HalfRGBA8>(
_mm_max_epi16(bit_cast<V8<int16_t>>(x), bit_cast<V8<int16_t>>(y)));
#elif USE_NEON
return vmaxq_u16(x, y);
#else
return if_then_else(x > y, x, y);
#endif
}
template <typename T, int N>
static ALWAYS_INLINE VectorType<T, N> max(VectorType<T, N> x,
VectorType<T, N> y) {
return combine(max(lowHalf(x), lowHalf(y)), max(highHalf(x), highHalf(y)));
}
template <typename T, int N>
static ALWAYS_INLINE VectorType<T, N> recip(VectorType<T, N> v) {
return combine(recip(lowHalf(v)), recip(highHalf(v)));
}
// Helper to get the reciprocal if the value is non-zero, or otherwise default
// to the supplied fallback value.
template <typename V>
static ALWAYS_INLINE V recip_or(V v, float f) {
return if_then_else(v != V(0.0f), recip(v), V(f));
}
template <typename T, int N>
static ALWAYS_INLINE VectorType<T, N> inversesqrt(VectorType<T, N> v) {
return combine(inversesqrt(lowHalf(v)), inversesqrt(highHalf(v)));
}
// Extract the alpha components so that we can cheaply calculate the reciprocal
// on a single SIMD register. Then multiply the duplicated alpha reciprocal with
// the pixel data. 0 alpha is treated as transparent black.
static ALWAYS_INLINE WideRGBA32F unpremultiply(WideRGBA32F v) {
Float a = recip_or((Float){v[3], v[7], v[11], v[15]}, 0.0f);
return v * a.xxxxyyyyzzzzwwww;
}
// Packed RGBA32F data is AoS in BGRA order. Transpose it to SoA and swizzle to
// RGBA to unpack.
static ALWAYS_INLINE vec4 unpack(PackedRGBA32F c) {
return bit_cast<vec4>(
SHUFFLE(c, c, 2, 6, 10, 14, 1, 5, 9, 13, 0, 4, 8, 12, 3, 7, 11, 15));
}
// The following lum/sat functions mostly follow the KHR_blend_equation_advanced
// specification but are rearranged to work on premultiplied data.
static ALWAYS_INLINE Float lumv3(vec3 v) {
return v.x * 0.30f + v.y * 0.59f + v.z * 0.11f;
}
static ALWAYS_INLINE Float minv3(vec3 v) { return min(min(v.x, v.y), v.z); }
static ALWAYS_INLINE Float maxv3(vec3 v) { return max(max(v.x, v.y), v.z); }
static inline vec3 clip_color(vec3 v, Float lum, Float alpha) {
Float mincol = max(-minv3(v), lum);
Float maxcol = max(maxv3(v), alpha - lum);
return lum + v * (lum * (alpha - lum) * recip_or(mincol * maxcol, 0.0f));
}
static inline vec3 set_lum(vec3 base, vec3 ref, Float alpha) {
return clip_color(base - lumv3(base), lumv3(ref), alpha);
}
static inline vec3 set_lum_sat(vec3 base, vec3 sref, vec3 lref, Float alpha) {
vec3 diff = base - minv3(base);
Float sbase = maxv3(diff);
Float ssat = maxv3(sref) - minv3(sref);
// The sbase range is rescaled to ssat. If sbase has 0 extent, then rescale
// to black, as per specification.
return set_lum(diff * ssat * recip_or(sbase, 0.0f), lref, alpha);
}
// Flags the reflect the current blend-stage clipping to be applied.
enum SWGLClipFlag {
SWGL_CLIP_FLAG_MASK = 1 << 0,
SWGL_CLIP_FLAG_AA = 1 << 1,
SWGL_CLIP_FLAG_BLEND_OVERRIDE = 1 << 2,
};
static int swgl_ClipFlags = 0;
static BlendKey swgl_BlendOverride = BLEND_KEY_NONE;
static WideRGBA8 swgl_BlendColorRGBA8 = {0};
static WideRGBA8 swgl_BlendAlphaRGBA8 = {0};
// A pointer into the color buffer for the start of the span.
static void* swgl_SpanBuf = nullptr;
// A pointer into the clip mask for the start of the span.
static uint8_t* swgl_ClipMaskBuf = nullptr;
static ALWAYS_INLINE WideR8 expand_mask(UNUSED uint8_t* buf, WideR8 mask) {
return mask;
}
static ALWAYS_INLINE WideRGBA8 expand_mask(UNUSED uint32_t* buf, WideR8 mask) {
WideRG8 maskRG = zip(mask, mask);
return zip(maskRG, maskRG);
}
// Loads a chunk of clip masks. The current pointer into the color buffer is
// used to reconstruct the relative position within the span. From there, the
// pointer into the clip mask can be generated from the start of the clip mask
// span.
template <typename P>
static ALWAYS_INLINE uint8_t* get_clip_mask(P* buf) {
return &swgl_ClipMaskBuf[buf - (P*)swgl_SpanBuf];
}
template <typename P>
static ALWAYS_INLINE auto load_clip_mask(P* buf, int span)
-> decltype(expand_mask(buf, 0)) {
return expand_mask(buf,
unpack(load_span<PackedR8>(get_clip_mask(buf), span)));
}
// Temporarily removes masking from the blend stage, assuming the caller will
// handle it.
static ALWAYS_INLINE void override_clip_mask() {
blend_key = BlendKey(blend_key - MASK_BLEND_KEY_NONE);
}
// Restores masking to the blend stage, assuming it was previously overridden.
static ALWAYS_INLINE void restore_clip_mask() {
blend_key = BlendKey(MASK_BLEND_KEY_NONE + blend_key);
}
// A pointer to the start of the opaque destination region of the span for AA.
static const uint8_t* swgl_OpaqueStart = nullptr;
// The size, in bytes, of the opaque region.
static uint32_t swgl_OpaqueSize = 0;
// AA coverage distance offsets for the left and right edges.
static Float swgl_LeftAADist = 0.0f;
static Float swgl_RightAADist = 0.0f;
// AA coverage slope values used for accumulating coverage for each step.
static Float swgl_AASlope = 0.0f;
// Get the amount of pixels we need to process before the start of the opaque
// region.
template <typename P>
static ALWAYS_INLINE int get_aa_opaque_start(P* buf) {
return max(int((P*)swgl_OpaqueStart - buf), 0);
}
// Assuming we are already in the opaque part of the span, return the remaining
// size of the opaque part.
template <typename P>
static ALWAYS_INLINE int get_aa_opaque_size(P* buf) {
return max(int((P*)&swgl_OpaqueStart[swgl_OpaqueSize] - buf), 0);
}
// Temporarily removes anti-aliasing from the blend stage, assuming the caller
// will handle it.
static ALWAYS_INLINE void override_aa() {
blend_key = BlendKey(blend_key - AA_BLEND_KEY_NONE);
}
// Restores anti-aliasing to the blend stage, assuming it was previously
// overridden.
static ALWAYS_INLINE void restore_aa() {
blend_key = BlendKey(AA_BLEND_KEY_NONE + blend_key);
}
static PREFER_INLINE WideRGBA8 blend_pixels(uint32_t* buf, PackedRGBA8 pdst,
WideRGBA8 src, int span = 4) {
WideRGBA8 dst = unpack(pdst);
const WideRGBA8 RGB_MASK = {0xFFFF, 0xFFFF, 0xFFFF, 0, 0xFFFF, 0xFFFF,
0xFFFF, 0, 0xFFFF, 0xFFFF, 0xFFFF, 0,
0xFFFF, 0xFFFF, 0xFFFF, 0};
const WideRGBA8 ALPHA_MASK = {0, 0, 0, 0xFFFF, 0, 0, 0, 0xFFFF,
0, 0, 0, 0xFFFF, 0, 0, 0, 0xFFFF};
const WideRGBA8 ALPHA_OPAQUE = {0, 0, 0, 255, 0, 0, 0, 255,
0, 0, 0, 255, 0, 0, 0, 255};
// clang-format off
// Computes AA for the given pixel based on the offset of the pixel within
// destination row. Given the initial coverage offsets for the left and right
// edges, the offset is scaled by the slope and accumulated to find the
// minimum coverage value for the pixel. A final weight is generated that
// can be used to scale the source pixel.
#define DO_AA(format, body) \
do { \
int offset = int((const uint8_t*)buf - swgl_OpaqueStart); \
if (uint32_t(offset) >= swgl_OpaqueSize) { \
Float delta = swgl_AASlope * float(offset); \
Float dist = clamp(min(swgl_LeftAADist + delta.x, \
swgl_RightAADist + delta.y), \
0.0f, 256.0f); \
auto aa = pack_pixels_##format(dist, 1.0f); \
body; \
} \
} while (0)
// Each blend case is preceded by the MASK_ variant. The MASK_ case first
// loads the mask values and multiplies the source value by them. After, it
// falls through to the normal blending case using the masked source. The
// AA_ variations may further precede the blend cases, in which case the
// source value is further modified before use.
#define BLEND_CASE_KEY(key) \
case AA_##key: \
DO_AA(RGBA8, src = muldiv256(src, aa)); \
goto key; \
case AA_MASK_##key: \
DO_AA(RGBA8, src = muldiv256(src, aa)); \
FALLTHROUGH; \
case MASK_##key: \
src = muldiv255(src, load_clip_mask(buf, span)); \
FALLTHROUGH; \
case key: key
#define BLEND_CASE(...) BLEND_CASE_KEY(BLEND_KEY(__VA_ARGS__))
switch (blend_key) {
BLEND_CASE(GL_ONE, GL_ZERO):
return src;
BLEND_CASE(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE,
GL_ONE_MINUS_SRC_ALPHA):
// dst + src.a*(src.rgb1 - dst)
// use addlow for signed overflow
return addlow(dst, muldiv255(alphas(src), (src | ALPHA_OPAQUE) - dst));
BLEND_CASE(GL_ONE, GL_ONE_MINUS_SRC_ALPHA):
return src + dst - muldiv255(dst, alphas(src));
BLEND_CASE(GL_ZERO, GL_ONE_MINUS_SRC_COLOR):
return dst - muldiv255(dst, src);
BLEND_CASE(GL_ZERO, GL_ONE_MINUS_SRC_COLOR, GL_ZERO, GL_ONE):
return dst - (muldiv255(dst, src) & RGB_MASK);
BLEND_CASE(GL_ZERO, GL_ONE_MINUS_SRC_ALPHA):
return dst - muldiv255(dst, alphas(src));
BLEND_CASE(GL_ZERO, GL_SRC_COLOR):
return muldiv255(src, dst);
BLEND_CASE(GL_ONE, GL_ONE):
return src + dst;
BLEND_CASE(GL_ONE, GL_ONE, GL_ONE, GL_ONE_MINUS_SRC_ALPHA):
return src + dst - (muldiv255(dst, src) & ALPHA_MASK);
BLEND_CASE(GL_ONE_MINUS_DST_ALPHA, GL_ONE, GL_ZERO, GL_ONE):
// src*(1-dst.a) + dst*1 = src - src*dst.a + dst
return dst + ((src - muldiv255(src, alphas(dst))) & RGB_MASK);
BLEND_CASE(GL_CONSTANT_COLOR, GL_ONE_MINUS_SRC_COLOR):
// src*k + (1-src)*dst = src*k + dst -
// src*dst = dst + src*(k - dst) use addlow
// for signed overflow
return addlow(
dst, muldiv255(src, repeat2(ctx->blendcolor) - dst));
// We must explicitly handle the masked/anti-aliased secondary blend case.
// The secondary color as well as the source must be multiplied by the
// weights.
case BLEND_KEY(GL_ONE, GL_ONE_MINUS_SRC1_COLOR): {
WideRGBA8 secondary =
applyColor(dst,
packColor<uint32_t>(fragment_shader->gl_SecondaryFragColor));
return src + dst - secondary;
}
case MASK_BLEND_KEY(GL_ONE, GL_ONE_MINUS_SRC1_COLOR): {
WideRGBA8 secondary =
applyColor(dst,
packColor<uint32_t>(fragment_shader->gl_SecondaryFragColor));
WideRGBA8 mask = load_clip_mask(buf, span);
return muldiv255(src, mask) + dst - muldiv255(secondary, mask);
}
case AA_BLEND_KEY(GL_ONE, GL_ONE_MINUS_SRC1_COLOR): {
WideRGBA8 secondary =
applyColor(dst,
packColor<uint32_t>(fragment_shader->gl_SecondaryFragColor));
DO_AA(RGBA8, {
src = muldiv256(src, aa);
secondary = muldiv256(secondary, aa);
});
return src + dst - secondary;
}
case AA_MASK_BLEND_KEY(GL_ONE, GL_ONE_MINUS_SRC1_COLOR): {
WideRGBA8 secondary =
applyColor(dst,
packColor<uint32_t>(fragment_shader->gl_SecondaryFragColor));
WideRGBA8 mask = load_clip_mask(buf, span);
DO_AA(RGBA8, mask = muldiv256(mask, aa));
return muldiv255(src, mask) + dst - muldiv255(secondary, mask);
}
BLEND_CASE(GL_MIN):
return min(src, dst);
BLEND_CASE(GL_MAX):
return max(src, dst);
// The KHR_blend_equation_advanced spec describes the blend equations such
// that the unpremultiplied values Cs, Cd, As, Ad and function f combine to
// the result:
// Cr = f(Cs,Cd)*As*Ad + Cs*As*(1-Ad) + Cd*AD*(1-As)
// Ar = As*Ad + As*(1-Ad) + Ad*(1-As)
// However, working with unpremultiplied values requires expensive math to
// unpremultiply and premultiply again during blending. We can use the fact
// that premultiplied value P = C*A and simplify the equations such that no
// unpremultiplied colors are necessary, allowing us to stay with integer
// math that avoids floating-point conversions in the common case. Some of
// the blend modes require division or sqrt, in which case we do convert
// to (possibly transposed/unpacked) floating-point to implement the mode.
// However, most common modes can still use cheaper premultiplied integer
// math. As an example, the multiply mode f(Cs,Cd) = Cs*Cd is simplified
// to:
// Cr = Cs*Cd*As*Ad + Cs*As*(1-Ad) + Cd*Ad*(1-As)
// .. Pr = Ps*Pd + Ps - Ps*Ad + Pd - Pd*As
// Ar = As*Ad + As - As*Ad + Ad - Ad*As
// .. Ar = As + Ad - As*Ad
// Note that the alpha equation is the same for all blend equations, such
// that so long as the implementation results in As + Ad - As*Ad, we can
// avoid using separate instructions to compute the alpha result, which is
// dependent on the math used to implement each blend mode. The exact
// reductions used to get the final math for every blend mode are too
// involved to show here in comments, but mostly follows from replacing
// Cs*As and Cd*Ad with Ps and Ps while factoring out as many common terms
// as possible.
BLEND_CASE(GL_MULTIPLY_KHR): {
WideRGBA8 diff = muldiv255(alphas(src) - (src & RGB_MASK),
alphas(dst) - (dst & RGB_MASK));
return src + dst + (diff & RGB_MASK) - alphas(diff);
}
BLEND_CASE(GL_SCREEN_KHR):
return src + dst - muldiv255(src, dst);
BLEND_CASE(GL_OVERLAY_KHR): {
WideRGBA8 srcA = alphas(src);
WideRGBA8 dstA = alphas(dst);
WideRGBA8 diff = muldiv255(src, dst) + muldiv255(srcA - src, dstA - dst);
return src + dst +
if_then_else(dst * 2 <= dstA, (diff & RGB_MASK) - alphas(diff),
-diff);
}
BLEND_CASE(GL_DARKEN_KHR):
return src + dst -
max(muldiv255(src, alphas(dst)), muldiv255(dst, alphas(src)));
BLEND_CASE(GL_LIGHTEN_KHR):
return src + dst -
min(muldiv255(src, alphas(dst)), muldiv255(dst, alphas(src)));
BLEND_CASE(GL_COLORDODGE_KHR): {
// Color-dodge and color-burn require division, so we convert to FP math
// here, but avoid transposing to a vec4.
WideRGBA32F srcF = CONVERT(src, WideRGBA32F);
WideRGBA32F srcA = alphas(srcF);
WideRGBA32F dstF = CONVERT(dst, WideRGBA32F);
WideRGBA32F dstA = alphas(dstF);
return pack_pixels_RGBA8(
srcA * set_alphas(
min(dstA, dstF * srcA * recip_or(srcA - srcF, 255.0f)),
dstF) +
srcF * (255.0f - dstA) + dstF * (255.0f - srcA),
1.0f / 255.0f);
}
BLEND_CASE(GL_COLORBURN_KHR): {
WideRGBA32F srcF = CONVERT(src, WideRGBA32F);
WideRGBA32F srcA = alphas(srcF);
WideRGBA32F dstF = CONVERT(dst, WideRGBA32F);
WideRGBA32F dstA = alphas(dstF);
return pack_pixels_RGBA8(
srcA * set_alphas((dstA - min(dstA, (dstA - dstF) * srcA *
recip_or(srcF, 255.0f))),
dstF) +
srcF * (255.0f - dstA) + dstF * (255.0f - srcA),
1.0f / 255.0f);
}
BLEND_CASE(GL_HARDLIGHT_KHR): {
WideRGBA8 srcA = alphas(src);
WideRGBA8 dstA = alphas(dst);
WideRGBA8 diff = muldiv255(src, dst) + muldiv255(srcA - src, dstA - dst);
return src + dst +
if_then_else(src * 2 <= srcA, (diff & RGB_MASK) - alphas(diff),
-diff);
}
BLEND_CASE(GL_SOFTLIGHT_KHR): {
// Soft-light requires an unpremultiply that can't be factored out as
// well as a sqrt, so we convert to FP math here, but avoid transposing
// to a vec4.
WideRGBA32F srcF = CONVERT(src, WideRGBA32F);
WideRGBA32F srcA = alphas(srcF);
WideRGBA32F dstF = CONVERT(dst, WideRGBA32F);
WideRGBA32F dstA = alphas(dstF);
WideRGBA32F dstU = unpremultiply(dstF);
WideRGBA32F scale = srcF + srcF - srcA;
return pack_pixels_RGBA8(
dstF * (255.0f +
set_alphas(
scale *
if_then_else(scale < 0.0f, 1.0f - dstU,
min((16.0f * dstU - 12.0f) * dstU + 3.0f,
inversesqrt(dstU) - 1.0f)),
WideRGBA32F(0.0f))) +
srcF * (255.0f - dstA),
1.0f / 255.0f);
}
BLEND_CASE(GL_DIFFERENCE_KHR): {
WideRGBA8 diff =
min(muldiv255(dst, alphas(src)), muldiv255(src, alphas(dst)));
return src + dst - diff - (diff & RGB_MASK);
}
BLEND_CASE(GL_EXCLUSION_KHR): {
WideRGBA8 diff = muldiv255(src, dst);
return src + dst - diff - (diff & RGB_MASK);
}
// The HSL blend modes are non-separable and require complicated use of
// division. It is advantageous to convert to FP and transpose to vec4
// math to more easily manipulate the individual color components.
#define DO_HSL(rgb) \
do { \
vec4 srcV = unpack(CONVERT(src, PackedRGBA32F)); \
vec4 dstV = unpack(CONVERT(dst, PackedRGBA32F)); \
Float srcA = srcV.w * (1.0f / 255.0f); \
Float dstA = dstV.w * (1.0f / 255.0f); \
Float srcDstA = srcV.w * dstA; \
vec3 srcC = vec3(srcV) * dstA; \
vec3 dstC = vec3(dstV) * srcA; \
return pack_pixels_RGBA8(vec4(rgb + vec3(srcV) - srcC + vec3(dstV) - dstC, \
srcV.w + dstV.w - srcDstA), \
1.0f); \
} while (0)
BLEND_CASE(GL_HSL_HUE_KHR):
DO_HSL(set_lum_sat(srcC, dstC, dstC, srcDstA));
BLEND_CASE(GL_HSL_SATURATION_KHR):
DO_HSL(set_lum_sat(dstC, srcC, dstC, srcDstA));
BLEND_CASE(GL_HSL_COLOR_KHR):
DO_HSL(set_lum(srcC, dstC, srcDstA));
BLEND_CASE(GL_HSL_LUMINOSITY_KHR):
DO_HSL(set_lum(dstC, srcC, srcDstA));
// SWGL-specific extended blend modes.
BLEND_CASE(SWGL_BLEND_DROP_SHADOW): {
// Premultiplied alpha over blend, but with source color set to source alpha
// modulated with a constant color.
WideRGBA8 color = applyColor(alphas(src), swgl_BlendColorRGBA8);
return color + dst - muldiv255(dst, alphas(color));
}
BLEND_CASE(SWGL_BLEND_SUBPIXEL_TEXT):
// Premultiplied alpha over blend, but treats the source as a subpixel mask
// modulated with a constant color.
return applyColor(src, swgl_BlendColorRGBA8) + dst -
muldiv255(dst, applyColor(src, swgl_BlendAlphaRGBA8));
default:
UNREACHABLE;
// return src;
}
#undef BLEND_CASE
#undef BLEND_CASE_KEY
// clang-format on
}
static PREFER_INLINE WideR8 blend_pixels(uint8_t* buf, WideR8 dst, WideR8 src,
int span = 4) {
// clang-format off
#define BLEND_CASE_KEY(key) \
case AA_##key: \
DO_AA(R8, src = muldiv256(src, aa)); \
goto key; \
case AA_MASK_##key: \
DO_AA(R8, src = muldiv256(src, aa)); \
FALLTHROUGH; \
case MASK_##key: \
src = muldiv255(src, load_clip_mask(buf, span)); \
FALLTHROUGH; \
case key: key
#define BLEND_CASE(...) BLEND_CASE_KEY(BLEND_KEY(__VA_ARGS__))
switch (blend_key) {
BLEND_CASE(GL_ONE, GL_ZERO):
return src;
BLEND_CASE(GL_ZERO, GL_SRC_COLOR):
return muldiv255(src, dst);
BLEND_CASE(GL_ONE, GL_ONE):
return src + dst;
default:
UNREACHABLE;
// return src;
}
#undef BLEND_CASE
#undef BLEND_CASE_KEY
// clang-format on
}
static ALWAYS_INLINE void commit_span(uint32_t* buf, WideRGBA8 r) {
unaligned_store(buf, pack(r));
}
static ALWAYS_INLINE void commit_span(uint32_t* buf, WideRGBA8 r, int len) {
partial_store_span(buf, pack(r), len);
}
static ALWAYS_INLINE WideRGBA8 blend_span(uint32_t* buf, WideRGBA8 r) {
return blend_pixels(buf, unaligned_load<PackedRGBA8>(buf), r);
}
static ALWAYS_INLINE WideRGBA8 blend_span(uint32_t* buf, WideRGBA8 r, int len) {
return blend_pixels(buf, partial_load_span<PackedRGBA8>(buf, len), r, len);
}
static ALWAYS_INLINE void commit_span(uint32_t* buf, PackedRGBA8 r) {
unaligned_store(buf, r);
}
static ALWAYS_INLINE void commit_span(uint32_t* buf, PackedRGBA8 r, int len) {
partial_store_span(buf, r, len);
}
static ALWAYS_INLINE PackedRGBA8 blend_span(uint32_t* buf, PackedRGBA8 r) {
return pack(blend_span(buf, unpack(r)));
}
static ALWAYS_INLINE PackedRGBA8 blend_span(uint32_t* buf, PackedRGBA8 r,
int len) {
return pack(blend_span(buf, unpack(r), len));
}
static ALWAYS_INLINE void commit_span(uint8_t* buf, WideR8 r) {
unaligned_store(buf, pack(r));
}
static ALWAYS_INLINE void commit_span(uint8_t* buf, WideR8 r, int len) {
partial_store_span(buf, pack(r), len);
}
static ALWAYS_INLINE WideR8 blend_span(uint8_t* buf, WideR8 r) {
return blend_pixels(buf, unpack(unaligned_load<PackedR8>(buf)), r);
}
static ALWAYS_INLINE WideR8 blend_span(uint8_t* buf, WideR8 r, int len) {
return blend_pixels(buf, unpack(partial_load_span<PackedR8>(buf, len)), r,
len);
}
static ALWAYS_INLINE void commit_span(uint8_t* buf, PackedR8 r) {
unaligned_store(buf, r);
}
static ALWAYS_INLINE void commit_span(uint8_t* buf, PackedR8 r, int len) {
partial_store_span(buf, r, len);
}
static ALWAYS_INLINE PackedR8 blend_span(uint8_t* buf, PackedR8 r) {
return pack(blend_span(buf, unpack(r)));
}
static ALWAYS_INLINE PackedR8 blend_span(uint8_t* buf, PackedR8 r, int len) {
return pack(blend_span(buf, unpack(r), len));
}
template <bool BLEND, typename P, typename R>
static ALWAYS_INLINE void commit_blend_span(P* buf, R r) {
if (BLEND) {
commit_span(buf, blend_span(buf, r));
} else {
commit_span(buf, r);
}
}
template <bool BLEND, typename P, typename R>
static ALWAYS_INLINE void commit_blend_span(P* buf, R r, int len) {
if (BLEND) {
commit_span(buf, blend_span(buf, r, len), len);
} else {
commit_span(buf, r, len);
}
}
template <typename P, typename R>
static ALWAYS_INLINE void commit_blend_solid_span(P* buf, R r, int len) {
for (P* end = &buf[len & ~3]; buf < end; buf += 4) {
commit_span(buf, blend_span(buf, r));
}
len &= 3;
if (len > 0) {
partial_store_span(buf, pack(blend_span(buf, r, len)), len);
}
}
template <bool BLEND>
static void commit_solid_span(uint32_t* buf, WideRGBA8 r, int len) {
commit_blend_solid_span(buf, r, len);
}
template <>
ALWAYS_INLINE void commit_solid_span<false>(uint32_t* buf, WideRGBA8 r,
int len) {
fill_n(buf, len, bit_cast<U32>(pack(r)).x);
}
template <bool BLEND>
static void commit_solid_span(uint8_t* buf, WideR8 r, int len) {
commit_blend_solid_span(buf, r, len);
}
template <>
ALWAYS_INLINE void commit_solid_span<false>(uint8_t* buf, WideR8 r, int len) {
PackedR8 p = pack(r);
if (uintptr_t(buf) & 3) {
int align = 4 - (uintptr_t(buf) & 3);
align = min(align, len);
partial_store_span(buf, p, align);
buf += align;
len -= align;
}
fill_n((uint32_t*)buf, len / 4, bit_cast<uint32_t>(p));
buf += len & ~3;
len &= 3;
if (len > 0) {
partial_store_span(buf, p, len);
}
}

1069
third_party/webrender/swgl/src/composite.h vendored Normal file

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -15,20 +15,27 @@ typedef float GLfloat;
typedef double GLdouble;
typedef uint32_t GLenum;
typedef int32_t GLboolean;
typedef uint8_t GLboolean;
typedef uint32_t GLbitfield;
typedef int32_t GLsizei;
typedef size_t GLsizeiptr;
typedef intptr_t GLintptr;
#define GL_FALSE 0
#define GL_TRUE 1
#define GL_NONE 0
#define GL_NO_ERROR 0
#define GL_RGBA32F 0x8814
#define GL_RGBA8 0x8058
#define GL_R8 0x8229
#define GL_R16 0x822A
#define GL_RGBA32I 0x8D82
#define GL_BGRA8 0x93A1
#define GL_RG8 0x822B
#define GL_BYTE 0x1400
#define GL_UNSIGNED_BYTE 0x1401
@ -37,6 +44,7 @@ typedef intptr_t GLintptr;
#define GL_INT 0x1404
#define GL_UNSIGNED_INT 0x1405
#define GL_FLOAT 0x1406
#define GL_DOUBLE 0x1408
#define GL_RED 0x1903
#define GL_GREEN 0x1904
@ -46,6 +54,7 @@ typedef intptr_t GLintptr;
#define GL_RGBA 0x1908
#define GL_RGBA_INTEGER 0x8D99
#define GL_BGRA 0x80E1
#define GL_RG 0x8227
#define GL_DEPTH_COMPONENT 0x1902
#define GL_DEPTH_COMPONENT16 0x81A5
@ -146,6 +155,8 @@ typedef intptr_t GLintptr;
#define GL_ONE_MINUS_SRC1_ALPHA 0x88FB
#define GL_FUNC_ADD 0x8006
#define GL_MIN 0x8007
#define GL_MAX 0x8008
#define GL_NEVER 0x0200
#define GL_LESS 0x0201
@ -165,6 +176,9 @@ typedef intptr_t GLintptr;
#define GL_VERSION 0x1F02
#define GL_EXTENSIONS 0x1F03
#define GL_NUM_EXTENSIONS 0x821D
#define GL_MINOR_VERSION 0x821C
#define GL_MAJOR_VERSION 0x821B
#define GL_SHADING_LANGUAGE_VERSION 0x8B8C
#define GL_POINTS 0x0000
#define GL_LINES 0x0001
@ -174,3 +188,29 @@ typedef intptr_t GLintptr;
#define GL_TRIANGLE_STRIP 0x0005
#define GL_TRIANGLE_FAN 0x0006
#define GL_QUADS 0x0007
#define GL_UNSIGNED_INT_8_8_8_8_REV 0x8367
#define GL_RGB_422_APPLE 0x8A1F
#define GL_UNSIGNED_SHORT_8_8_APPLE 0x85BA
#define GL_UNSIGNED_SHORT_8_8_REV_APPLE 0x85BB
#define GL_RGB_RAW_422_APPLE 0x8A51
#define GL_MULTIPLY_KHR 0x9294
#define GL_SCREEN_KHR 0x9295
#define GL_OVERLAY_KHR 0x9296
#define GL_DARKEN_KHR 0x9297
#define GL_LIGHTEN_KHR 0x9298
#define GL_COLORDODGE_KHR 0x9299
#define GL_COLORBURN_KHR 0x929A
#define GL_HARDLIGHT_KHR 0x929B
#define GL_SOFTLIGHT_KHR 0x929C
#define GL_DIFFERENCE_KHR 0x929E
#define GL_EXCLUSION_KHR 0x92A0
#define GL_HSL_HUE_KHR 0x92AD
#define GL_HSL_SATURATION_KHR 0x92AE
#define GL_HSL_COLOR_KHR 0x92AF
#define GL_HSL_LUMINOSITY_KHR 0x92B0
#define SWGL_BLEND_DROP_SHADOW 0xB001
#define SWGL_BLEND_SUBPIXEL_TEXT 0xB002

File diff suppressed because it is too large Load diff

View file

@ -5,7 +5,7 @@
#![crate_name = "swgl"]
#![crate_type = "lib"]
use gleam;
extern crate gleam;
mod swgl_fns;

View file

@ -12,6 +12,12 @@ namespace glsl {
// to operate in Float-sized chunks.
typedef vec3 Interpolants;
// Clip distances, if enabled, are always stored in the first SIMD chunk of the
// interpolants.
static ALWAYS_INLINE Float get_clip_distances(const Interpolants& interp) {
return interp.x;
}
struct VertexShaderImpl;
struct FragmentShaderImpl;
@ -23,10 +29,14 @@ struct ProgramImpl {
virtual size_t interpolants_size() const = 0;
virtual VertexShaderImpl* get_vertex_shader() = 0;
virtual FragmentShaderImpl* get_fragment_shader() = 0;
virtual const char* get_name() const = 0;
};
typedef ProgramImpl* (*ProgramLoader)();
// The maximum size of the gl_ClipDistance array.
constexpr int32_t gl_MaxClipDistances = 4;
struct VertexShaderImpl {
typedef void (*SetUniform1iFunc)(VertexShaderImpl*, int index, int value);
typedef void (*SetUniform4fvFunc)(VertexShaderImpl*, int index,
@ -46,7 +56,17 @@ struct VertexShaderImpl {
LoadAttribsFunc load_attribs_func = nullptr;
RunPrimitiveFunc run_primitive_func = nullptr;
enum FLAGS {
CLIP_DISTANCE = 1 << 0,
};
int flags = 0;
void enable_clip_distance() { flags |= CLIP_DISTANCE; }
ALWAYS_INLINE bool use_clip_distance() const {
return (flags & CLIP_DISTANCE) != 0;
}
vec4 gl_Position;
Float gl_ClipDistance[gl_MaxClipDistances];
void set_uniform_1i(int index, int value) {
(*set_uniform_1i_func)(this, index, value);
@ -72,18 +92,20 @@ struct VertexShaderImpl {
}
};
// The number of pixels in a step.
constexpr int32_t swgl_StepSize = 4;
struct FragmentShaderImpl {
typedef void (*InitSpanFunc)(FragmentShaderImpl*, const void* interps,
const void* step, float step_width);
const void* step);
typedef void (*RunFunc)(FragmentShaderImpl*);
typedef void (*SkipFunc)(FragmentShaderImpl*, int chunks);
typedef void (*SkipFunc)(FragmentShaderImpl*, int steps);
typedef void (*InitSpanWFunc)(FragmentShaderImpl*, const void* interps,
const void* step, float step_width);
const void* step);
typedef void (*RunWFunc)(FragmentShaderImpl*);
typedef void (*SkipWFunc)(FragmentShaderImpl*, int chunks);
typedef void (*DrawSpanRGBA8Func)(FragmentShaderImpl*, uint32_t* buf,
int len);
typedef void (*DrawSpanR8Func)(FragmentShaderImpl*, uint8_t* buf, int len);
typedef void (*SkipWFunc)(FragmentShaderImpl*, int steps);
typedef int (*DrawSpanRGBA8Func)(FragmentShaderImpl*);
typedef int (*DrawSpanR8Func)(FragmentShaderImpl*);
InitSpanFunc init_span_func = nullptr;
RunFunc run_func = nullptr;
@ -107,31 +129,27 @@ struct FragmentShaderImpl {
}
vec4 gl_FragCoord;
vec2_scalar stepZW;
Bool isPixelDiscarded = false;
vec4 gl_FragColor;
vec4 gl_SecondaryFragColor;
ALWAYS_INLINE void step_fragcoord() { gl_FragCoord.x += 4; }
vec2_scalar swgl_StepZW;
Bool swgl_IsPixelDiscarded = false;
// The current buffer position for committing span output.
uint32_t* swgl_OutRGBA8 = nullptr;
uint8_t* swgl_OutR8 = nullptr;
// The remaining number of pixels in the span.
int32_t swgl_SpanLength = 0;
ALWAYS_INLINE void step_fragcoord(int chunks) {
gl_FragCoord.x += 4 * chunks;
}
ALWAYS_INLINE void step_fragcoord(int steps = 4) { gl_FragCoord.x += steps; }
ALWAYS_INLINE void step_perspective() {
gl_FragCoord.z += stepZW.x;
gl_FragCoord.w += stepZW.y;
}
ALWAYS_INLINE void step_perspective(int chunks) {
gl_FragCoord.z += stepZW.x * chunks;
gl_FragCoord.w += stepZW.y * chunks;
ALWAYS_INLINE void step_perspective(int steps = 4) {
gl_FragCoord.z += swgl_StepZW.x * steps;
gl_FragCoord.w += swgl_StepZW.y * steps;
}
template <bool W = false>
ALWAYS_INLINE void init_span(const void* interps, const void* step,
float step_width) {
(*(W ? init_span_w_func : init_span_func))(this, interps, step, step_width);
ALWAYS_INLINE void init_span(const void* interps, const void* step) {
(*(W ? init_span_w_func : init_span_func))(this, interps, step);
}
template <bool W = false>
@ -140,20 +158,24 @@ struct FragmentShaderImpl {
}
template <bool W = false>
ALWAYS_INLINE void skip(int chunks = 1) {
(*(W ? skip_w_func : skip_func))(this, chunks);
ALWAYS_INLINE void skip(int steps = 4) {
(*(W ? skip_w_func : skip_func))(this, steps);
}
ALWAYS_INLINE void draw_span(uint32_t* buf, int len) {
(*draw_span_RGBA8_func)(this, buf, len);
ALWAYS_INLINE int draw_span(uint32_t* buf, int len) {
swgl_OutRGBA8 = buf;
swgl_SpanLength = len;
return (*draw_span_RGBA8_func)(this);
}
ALWAYS_INLINE bool has_draw_span(uint32_t*) {
return draw_span_RGBA8_func != nullptr;
}
ALWAYS_INLINE void draw_span(uint8_t* buf, int len) {
(*draw_span_R8_func)(this, buf, len);
ALWAYS_INLINE int draw_span(uint8_t* buf, int len) {
swgl_OutR8 = buf;
swgl_SpanLength = len;
return (*draw_span_R8_func)(this);
}
ALWAYS_INLINE bool has_draw_span(uint8_t*) {

1670
third_party/webrender/swgl/src/rasterize.h vendored Normal file

File diff suppressed because it is too large Load diff

1826
third_party/webrender/swgl/src/swgl_ext.h vendored Normal file

File diff suppressed because it is too large Load diff

View file

@ -14,8 +14,12 @@ macro_rules! debug {
($($x:tt)*) => {};
}
extern "C" {}
#[repr(C)]
struct LockedTexture {
_private: [u8; 0],
}
#[allow(dead_code)]
extern "C" {
fn ActiveTexture(texture: GLenum);
fn BindTexture(target: GLenum, texture: GLuint);
@ -61,19 +65,7 @@ extern "C" {
level: GLint,
);
fn CheckFramebufferStatus(target: GLenum) -> GLenum;
fn InvalidateFramebuffer(
target: GLenum,
num_attachments: GLsizei,
attachments: *const GLenum,
);
fn TexStorage3D(
target: GLenum,
levels: GLint,
internal_format: GLenum,
width: GLsizei,
height: GLsizei,
depth: GLsizei,
);
fn InvalidateFramebuffer(target: GLenum, num_attachments: GLsizei, attachments: *const GLenum);
fn TexImage2D(
target: GLenum,
level: GLint,
@ -85,18 +77,6 @@ extern "C" {
ty: GLenum,
data: *const c_void,
);
fn TexImage3D(
target: GLenum,
level: GLint,
internal_format: GLint,
width: GLsizei,
height: GLsizei,
depth: GLsizei,
border: GLint,
format: GLenum,
ty: GLenum,
data: *const c_void,
);
fn TexSubImage2D(
target: GLenum,
level: GLint,
@ -108,19 +88,6 @@ extern "C" {
ty: GLenum,
data: *const c_void,
);
fn TexSubImage3D(
target: GLenum,
level: GLint,
xoffset: GLint,
yoffset: GLint,
zoffset: GLint,
width: GLsizei,
height: GLsizei,
depth: GLsizei,
format: GLenum,
ty: GLenum,
data: *const c_void,
);
fn GenerateMipmap(target: GLenum);
fn GetUniformLocation(program: GLuint, name: *const GLchar) -> GLint;
fn BindAttribLocation(program: GLuint, index: GLuint, name: *const GLchar);
@ -152,26 +119,19 @@ extern "C" {
transpose: GLboolean,
value: *const GLfloat,
);
fn DrawElementsInstanced(
mode: GLenum,
count: GLsizei,
type_: GLenum,
indices: *const c_void,
indices: GLintptr,
instancecount: GLsizei,
);
fn EnableVertexAttribArray(index: GLuint);
fn VertexAttribDivisor(index: GLuint, divisor: GLuint);
fn LinkProgram(program: GLuint);
fn GetLinkStatus(program: GLuint) -> GLint;
fn UseProgram(program: GLuint);
fn SetViewport(x: GLint, y: GLint, width: GLsizei, height: GLsizei);
fn FramebufferTextureLayer(
target: GLenum,
attachment: GLenum,
texture: GLuint,
level: GLint,
layer: GLint,
);
fn FramebufferRenderbuffer(
target: GLenum,
attachment: GLenum,
@ -185,6 +145,31 @@ extern "C" {
fn ClearColor(r: GLfloat, g: GLfloat, b: GLfloat, a: GLfloat);
fn ClearDepth(depth: GLdouble);
fn Clear(mask: GLbitfield);
fn ClearTexSubImage(
target: GLenum,
level: GLint,
xoffset: GLint,
yoffset: GLint,
zoffset: GLint,
width: GLsizei,
height: GLsizei,
depth: GLsizei,
format: GLenum,
ty: GLenum,
data: *const c_void,
);
fn ClearTexImage(target: GLenum, level: GLint, format: GLenum, ty: GLenum, data: *const c_void);
fn ClearColorRect(
fbo: GLuint,
xoffset: GLint,
yoffset: GLint,
width: GLsizei,
height: GLsizei,
r: GLfloat,
g: GLfloat,
b: GLfloat,
a: GLfloat,
);
fn PixelStorei(name: GLenum, param: GLint);
fn ReadPixels(
x: GLint,
@ -225,17 +210,6 @@ extern "C" {
width: GLsizei,
height: GLsizei,
);
fn CopyTexSubImage3D(
target: GLenum,
level: GLint,
xoffset: GLint,
yoffset: GLint,
zoffset: GLint,
x: GLint,
y: GLint,
width: GLsizei,
height: GLsizei,
);
fn BlitFramebuffer(
src_x0: GLint,
src_y0: GLint,
@ -253,22 +227,33 @@ extern "C" {
fn GetString(name: GLenum) -> *const c_char;
fn GetStringi(name: GLenum, index: GLuint) -> *const c_char;
fn GetError() -> GLenum;
fn InitDefaultFramebuffer(width: i32, height: i32);
fn InitDefaultFramebuffer(
x: i32,
y: i32,
width: i32,
height: i32,
stride: i32,
buf: *mut c_void,
);
fn GetColorBuffer(
fbo: GLuint,
flush: GLboolean,
width: *mut i32,
height: *mut i32,
stride: *mut i32,
) -> *mut c_void;
fn ResolveFramebuffer(fbo: GLuint);
fn SetTextureBuffer(
tex: GLuint,
internal_format: GLenum,
width: GLsizei,
height: GLsizei,
stride: GLsizei,
buf: *mut c_void,
min_width: GLsizei,
min_height: GLsizei,
);
fn SetTextureParameter(tex: GLuint, pname: GLenum, param: GLint);
fn DeleteTexture(n: GLuint);
fn DeleteRenderbuffer(n: GLuint);
fn DeleteFramebuffer(n: GLuint);
@ -277,23 +262,64 @@ extern "C" {
fn DeleteQuery(n: GLuint);
fn DeleteShader(shader: GLuint);
fn DeleteProgram(program: GLuint);
fn LockFramebuffer(fbo: GLuint) -> *mut LockedTexture;
fn LockTexture(tex: GLuint) -> *mut LockedTexture;
fn LockResource(resource: *mut LockedTexture);
fn UnlockResource(resource: *mut LockedTexture);
fn GetResourceBuffer(
resource: *mut LockedTexture,
width: *mut i32,
height: *mut i32,
stride: *mut i32,
) -> *mut c_void;
fn Composite(
src_id: GLuint,
locked_dst: *mut LockedTexture,
locked_src: *mut LockedTexture,
src_x: GLint,
src_y: GLint,
src_width: GLsizei,
src_height: GLsizei,
dst_x: GLint,
dst_y: GLint,
dst_width: GLsizei,
dst_height: GLsizei,
opaque: GLboolean,
flip: GLboolean,
filter: GLenum,
clip_x: GLint,
clip_y: GLint,
clip_width: GLsizei,
clip_height: GLsizei,
);
fn CompositeYUV(
locked_dst: *mut LockedTexture,
locked_y: *mut LockedTexture,
locked_u: *mut LockedTexture,
locked_v: *mut LockedTexture,
color_space: YUVColorSpace,
color_depth: GLuint,
src_x: GLint,
src_y: GLint,
src_width: GLsizei,
src_height: GLsizei,
dst_x: GLint,
dst_y: GLint,
dst_width: GLsizei,
dst_height: GLsizei,
flip: GLboolean,
clip_x: GLint,
clip_y: GLint,
clip_width: GLsizei,
clip_height: GLsizei,
);
fn CreateContext() -> *mut c_void;
fn ReferenceContext(ctx: *mut c_void);
fn DestroyContext(ctx: *mut c_void);
fn MakeCurrent(ctx: *mut c_void);
fn ReportMemory(size_of_op: unsafe extern "C" fn(ptr: *const c_void) -> usize) -> usize;
}
#[derive(Clone)]
#[derive(Clone, Copy)]
pub struct Context(*mut c_void);
impl Context {
@ -301,6 +327,12 @@ impl Context {
Context(unsafe { CreateContext() })
}
pub fn reference(&self) {
unsafe {
ReferenceContext(self.0);
}
}
pub fn destroy(&self) {
unsafe {
DestroyContext(self.0);
@ -313,18 +345,56 @@ impl Context {
}
}
pub fn init_default_framebuffer(&self, width: i32, height: i32) {
pub fn init_default_framebuffer(
&self,
x: i32,
y: i32,
width: i32,
height: i32,
stride: i32,
buf: *mut c_void,
) {
unsafe {
InitDefaultFramebuffer(width, height);
InitDefaultFramebuffer(x, y, width, height, stride, buf);
}
}
pub fn get_color_buffer(&self, fbo: GLuint, flush: bool) -> (*mut c_void, i32, i32) {
pub fn get_color_buffer(&self, fbo: GLuint, flush: bool) -> (*mut c_void, i32, i32, i32) {
unsafe {
let mut width: i32 = 0;
let mut height: i32 = 0;
let data_ptr = GetColorBuffer(fbo, flush as GLboolean, &mut width, &mut height);
(data_ptr, width, height)
let mut stride: i32 = 0;
let data_ptr = GetColorBuffer(
fbo,
flush as GLboolean,
&mut width,
&mut height,
&mut stride,
);
(data_ptr, width, height, stride)
}
}
pub fn resolve_framebuffer(&self, fbo: GLuint) {
unsafe {
ResolveFramebuffer(fbo);
}
}
pub fn clear_color_rect(
&self,
fbo: GLuint,
xoffset: GLint,
yoffset: GLint,
width: GLsizei,
height: GLsizei,
r: f32,
g: f32,
b: f32,
a: f32,
) {
unsafe {
ClearColorRect(fbo, xoffset, yoffset, width, height, r, g, b, a);
}
}
@ -334,6 +404,7 @@ impl Context {
internal_format: GLenum,
width: GLsizei,
height: GLsizei,
stride: GLsizei,
buf: *mut c_void,
min_width: GLsizei,
min_height: GLsizei,
@ -344,6 +415,7 @@ impl Context {
internal_format,
width,
height,
stride,
buf,
min_width,
min_height,
@ -351,32 +423,37 @@ impl Context {
}
}
pub fn composite(
&self,
src_id: GLuint,
src_x: GLint,
src_y: GLint,
src_width: GLsizei,
src_height: GLint,
dst_x: GLint,
dst_y: GLint,
opaque: bool,
flip: bool,
) {
pub fn set_texture_parameter(&self, tex: GLuint, pname: GLenum, param: GLint) {
unsafe {
Composite(
src_id,
src_x,
src_y,
src_width,
src_height,
dst_x,
dst_y,
opaque as GLboolean,
flip as GLboolean,
);
SetTextureParameter(tex, pname, param);
}
}
pub fn lock_framebuffer(&self, fbo: GLuint) -> Option<LockedResource> {
unsafe {
let resource = LockFramebuffer(fbo);
if resource != ptr::null_mut() {
Some(LockedResource(resource))
} else {
None
}
}
}
pub fn lock_texture(&self, tex: GLuint) -> Option<LockedResource> {
unsafe {
let resource = LockTexture(tex);
if resource != ptr::null_mut() {
Some(LockedResource(resource))
} else {
None
}
}
}
pub fn report_memory(size_of_op: unsafe extern "C" fn(ptr: *const c_void) -> usize) -> usize {
unsafe { ReportMemory(size_of_op) }
}
}
impl From<*mut c_void> for Context {
@ -411,6 +488,7 @@ fn calculate_length(width: GLsizei, height: GLsizei, format: GLenum, pixel_type:
UNSIGNED_SHORT => 2,
SHORT => 2,
FLOAT => 4,
UNSIGNED_INT_8_8_8_8_REV => 1,
_ => panic!("unsupported pixel_type for read_pixels: {:?}", pixel_type),
};
@ -485,8 +563,8 @@ impl Gl for Context {
let u = str::from_utf8(s).unwrap();
const PREFIX: &'static str = "// shader: ";
if let Some(start) = u.find(PREFIX) {
if let Some(end) = u[start ..].find('\n') {
let name = u[start + PREFIX.len() .. start + end].trim();
if let Some(end) = u[start..].find('\n') {
let name = u[start + PREFIX.len()..start + end].trim();
debug!("shader name: {}", name);
unsafe {
let c_string = CString::new(name).unwrap();
@ -955,7 +1033,6 @@ impl Gl for Context {
panic!();
}
// FIXME: Does not verify buffer size -- unsafe!
fn tex_image_3d(
&self,
target: GLenum,
@ -969,24 +1046,7 @@ impl Gl for Context {
ty: GLenum,
opt_data: Option<&[u8]>,
) {
unsafe {
let pdata = match opt_data {
Some(data) => data.as_ptr() as *const GLvoid,
None => ptr::null(),
};
TexImage3D(
target,
level,
internal_format,
width,
height,
depth,
border,
format,
ty,
pdata,
);
}
panic!();
}
fn copy_tex_image_2d(
@ -1031,11 +1091,7 @@ impl Gl for Context {
width: GLsizei,
height: GLsizei,
) {
unsafe {
CopyTexSubImage3D(
target, level, xoffset, yoffset, zoffset, x, y, width, height,
);
}
panic!();
}
fn tex_sub_image_2d(
@ -1117,22 +1173,7 @@ impl Gl for Context {
data: &[u8],
) {
debug!("tex_sub_image_3d");
//panic!();
unsafe {
TexSubImage3D(
target,
level,
xoffset,
yoffset,
zoffset,
width,
height,
depth,
format,
ty,
data.as_ptr() as *const c_void,
);
}
panic!();
}
fn tex_sub_image_3d_pbo(
@ -1149,21 +1190,7 @@ impl Gl for Context {
ty: GLenum,
offset: usize,
) {
unsafe {
TexSubImage3D(
target,
level,
xoffset,
yoffset,
zoffset,
width,
height,
depth,
format,
ty,
offset as *const c_void,
);
}
panic!();
}
fn tex_storage_2d(
@ -1189,10 +1216,7 @@ impl Gl for Context {
height: GLsizei,
depth: GLsizei,
) {
//panic!();
unsafe {
TexStorage3D(target, levels, internal_format, width, height, depth);
}
panic!();
}
fn get_tex_image_into_buffer(
@ -1352,10 +1376,7 @@ impl Gl for Context {
"framebuffer_texture_layer {} {} {} {} {}",
target, attachment, texture, level, layer
);
//panic!();
unsafe {
FramebufferTextureLayer(target, attachment, texture, level, layer);
}
panic!();
}
fn blit_framebuffer(
@ -1477,7 +1498,9 @@ impl Gl for Context {
}
fn draw_arrays(&self, mode: GLenum, first: GLint, count: GLsizei) {
panic!();
unsafe {
DrawElementsInstanced(mode, count, NONE, first as GLintptr, 1);
}
}
fn draw_arrays_instanced(
@ -1487,7 +1510,9 @@ impl Gl for Context {
count: GLsizei,
primcount: GLsizei,
) {
panic!();
unsafe {
DrawElementsInstanced(mode, count, NONE, first as GLintptr, primcount);
}
}
fn draw_elements(
@ -1503,13 +1528,7 @@ impl Gl for Context {
);
//panic!();
unsafe {
DrawElementsInstanced(
mode,
count,
element_type,
indices_offset as *const c_void,
1,
);
DrawElementsInstanced(mode, count, element_type, indices_offset as GLintptr, 1);
}
}
@ -1531,7 +1550,7 @@ impl Gl for Context {
mode,
count,
element_type,
indices_offset as *const c_void,
indices_offset as GLintptr,
primcount,
);
}
@ -1824,8 +1843,8 @@ impl Gl for Context {
}
fn get_program_info_log(&self, program: GLuint) -> String {
panic!();
//String::new()
debug!("get_program_info_log {}", program);
String::new()
}
#[inline]
@ -1835,7 +1854,7 @@ impl Gl for Context {
assert!(!result.is_empty());
//#define GL_LINK_STATUS 0x8B82
if pname == 0x8b82 {
result[0] = 1;
result[0] = GetLinkStatus(program);
}
}
@ -2099,7 +2118,7 @@ impl Gl for Context {
//ptr::null()
}
fn client_wait_sync(&self, sync: GLsync, flags: GLbitfield, timeout: GLuint64) {
fn client_wait_sync(&self, sync: GLsync, flags: GLbitfield, timeout: GLuint64) -> GLenum {
panic!();
}
@ -2172,7 +2191,7 @@ impl Gl for Context {
// GL_KHR_blend_equation_advanced
fn blend_barrier_khr(&self) {
panic!();
// No barrier required, so nothing to do
}
// GL_CHROMIUM_copy_texture
@ -2250,4 +2269,158 @@ impl Gl for Context {
) {
unimplemented!("Not supported by SWGL");
}
fn buffer_storage(
&self,
target: GLenum,
size: GLsizeiptr,
data: *const GLvoid,
flags: GLbitfield,
) {
unimplemented!("Not supported by SWGL");
}
fn flush_mapped_buffer_range(&self, target: GLenum, offset: GLintptr, length: GLsizeiptr) {
unimplemented!("Not supported by SWGL");
}
}
/// A resource that is intended for sharing between threads.
/// Locked resources such as textures or framebuffers will
/// not allow any further modifications while it remains
/// locked. The resource will be unlocked when LockedResource
/// is dropped.
pub struct LockedResource(*mut LockedTexture);
unsafe impl Send for LockedResource {}
unsafe impl Sync for LockedResource {}
#[repr(C)]
pub enum YUVColorSpace {
Rec601 = 0,
Rec709,
Rec2020,
Identity,
}
impl LockedResource {
/// Composites from a locked resource to another locked resource. The band
/// offset and height are relative to the destination rectangle and specify
/// how to clip the composition into appropriate range for this band.
pub fn composite(
&self,
locked_src: &LockedResource,
src_x: GLint,
src_y: GLint,
src_width: GLsizei,
src_height: GLsizei,
dst_x: GLint,
dst_y: GLint,
dst_width: GLsizei,
dst_height: GLsizei,
opaque: bool,
flip: bool,
filter: GLenum,
clip_x: GLint,
clip_y: GLint,
clip_width: GLsizei,
clip_height: GLsizei,
) {
unsafe {
Composite(
self.0,
locked_src.0,
src_x,
src_y,
src_width,
src_height,
dst_x,
dst_y,
dst_width,
dst_height,
opaque as GLboolean,
flip as GLboolean,
filter,
clip_x,
clip_y,
clip_width,
clip_height,
);
}
}
/// Composites from locked resources representing YUV planes
pub fn composite_yuv(
&self,
locked_y: &LockedResource,
locked_u: &LockedResource,
locked_v: &LockedResource,
color_space: YUVColorSpace,
color_depth: GLuint,
src_x: GLint,
src_y: GLint,
src_width: GLsizei,
src_height: GLsizei,
dst_x: GLint,
dst_y: GLint,
dst_width: GLsizei,
dst_height: GLsizei,
flip: bool,
clip_x: GLint,
clip_y: GLint,
clip_width: GLsizei,
clip_height: GLsizei,
) {
unsafe {
CompositeYUV(
self.0,
locked_y.0,
locked_u.0,
locked_v.0,
color_space,
color_depth,
src_x,
src_y,
src_width,
src_height,
dst_x,
dst_y,
dst_width,
dst_height,
flip as GLboolean,
clip_x,
clip_y,
clip_width,
clip_height,
);
}
}
/// Get the underlying buffer for a locked resource
pub fn get_buffer(&self) -> (*mut c_void, i32, i32, i32) {
unsafe {
let mut width: i32 = 0;
let mut height: i32 = 0;
let mut stride: i32 = 0;
let data_ptr = GetResourceBuffer(self.0, &mut width, &mut height, &mut stride);
(data_ptr, width, height, stride)
}
}
}
impl Clone for LockedResource {
fn clone(&self) -> Self {
unsafe {
LockResource(self.0);
}
LockedResource(self.0)
}
}
impl Drop for LockedResource {
fn drop(&mut self) {
unsafe {
UnlockResource(self.0);
}
}
}

File diff suppressed because it is too large Load diff

View file

@ -38,6 +38,16 @@ SI VectorType<T, 16> combine(VectorType<T, 8> a, VectorType<T, 8> b) {
13, 14, 15);
}
template <typename T>
SI VectorType<T, 2> lowHalf(VectorType<T, 4> a) {
return __builtin_shufflevector(a, a, 0, 1);
}
template <typename T>
SI VectorType<T, 2> highHalf(VectorType<T, 4> a) {
return __builtin_shufflevector(a, a, 2, 3);
}
template <typename T>
SI VectorType<T, 4> lowHalf(VectorType<T, 8> a) {
return __builtin_shufflevector(a, a, 0, 1, 2, 3);
@ -104,7 +114,7 @@ struct VectorType {
};
};
VectorType() : data{0} { }
VectorType() : data{0} {}
constexpr VectorType(const VectorType& rhs) : data(rhs.data) {}
// GCC vector extensions only support broadcasting scalars on arithmetic ops,
@ -305,10 +315,27 @@ struct VectorType {
return VectorType<T, N * 2>::wrap(data, high.data);
}
# define xxxx swizzle(0, 0, 0, 0)
# define yyyy swizzle(1, 1, 1, 1)
# define zzzz swizzle(2, 2, 2, 2)
# define wwww swizzle(3, 3, 3, 3)
# define xxyy swizzle(0, 0, 1, 1)
# define xxzz swizzle(0, 0, 2, 2)
# define yyww swizzle(1, 1, 3, 3)
# define zzww swizzle(2, 2, 3, 3)
# define xyxy swizzle(0, 1, 0, 1)
# define xzxz swizzle(0, 2, 0, 2)
# define ywyw swizzle(1, 3, 1, 3)
# define zwzw swizzle(2, 3, 2, 3)
# define zwxy swizzle(2, 3, 0, 1)
# define zyxw swizzle(2, 1, 0, 3)
# define xxyz swizzle(0, 0, 1, 2)
# define xyyz swizzle(0, 1, 1, 2)
# define xyzz swizzle(0, 1, 2, 2)
# define xzyw swizzle(0, 2, 1, 3)
# define yzwx swizzle(1, 2, 3, 0)
# define wxyz swizzle(3, 0, 1, 2)
# define wzyx swizzle(3, 2, 1, 0)
# define xxxxyyyy XXXXYYYY()
VectorType<T, 8> XXXXYYYY() const {
return swizzle(0, 0, 0, 0).combine(swizzle(1, 1, 1, 1));
@ -331,6 +358,10 @@ struct VectorType {
VectorType<T, 8> XXYYZZWW() const {
return swizzle(0, 0, 1, 1).combine(swizzle(2, 2, 3, 3));
}
# define xxxxyyyyzzzzwwww XXXXYYYYZZZZWWWW()
VectorType<T, 16> XXXXYYYYZZZZWWWW() {
return XXXXYYYY().combine(ZZZZWWWW());
}
};
template <typename T>
@ -343,6 +374,17 @@ struct VectorType<T, 2> {
};
T elements[2];
};
SI VectorType wrap(const data_type& data) {
VectorType v;
v.data = data;
return v;
}
VectorType operator&(VectorType x) const { return wrap(data & x.data); }
VectorType operator&(T x) const { return wrap(data & x); }
VectorType operator|(VectorType x) const { return wrap(data | x.data); }
VectorType operator|(T x) const { return wrap(data | x); }
};
# define CONVERT(vector, type) ((type)(vector))
@ -369,6 +411,32 @@ SI VectorType<T, N * 2> expand(VectorType<T, N> a) {
}
#endif
template <typename T, int N>
SI VectorType<T, N * 4> combine(VectorType<T, N> a, VectorType<T, N> b,
VectorType<T, N> c, VectorType<T, N> d) {
return combine(combine(a, b), combine(c, d));
}
template <typename T, int N>
SI VectorType<T, N> combineLow(VectorType<T, N> a, VectorType<T, N> b) {
return combine(lowHalf(a), lowHalf(b));
}
template <typename T, int N>
SI VectorType<T, N> combineHigh(VectorType<T, N> a, VectorType<T, N> b) {
return combine(highHalf(a), highHalf(b));
}
template <typename T, int N>
SI VectorType<T, N * 2> repeat2(VectorType<T, N> a) {
return combine(a, a);
}
template <typename T, int N>
SI VectorType<T, N * 4> repeat4(VectorType<T, N> a) {
return combine(a, a, a, a);
}
template <typename T>
SI VectorType<T, 4> zipLow(VectorType<T, 4> a, VectorType<T, 4> b) {
return SHUFFLE(a, b, 0, 4, 1, 5);
@ -410,6 +478,23 @@ SI VectorType<T, 8> zip2High(VectorType<T, 8> a, VectorType<T, 8> b) {
return SHUFFLE(a, b, 4, 5, 12, 13, 6, 7, 14, 15);
}
#ifdef __clang__
template <typename T>
SI VectorType<T, 8> zip(VectorType<T, 4> a, VectorType<T, 4> b) {
return SHUFFLE(a, b, 0, 4, 1, 5, 2, 6, 3, 7);
}
template <typename T>
SI VectorType<T, 16> zip(VectorType<T, 8> a, VectorType<T, 8> b) {
return SHUFFLE(a, b, 0, 8, 1, 9, 2, 10, 3, 11, 4, 12, 5, 13, 6, 14, 7, 15);
}
#else
template <typename T, int N>
SI VectorType<T, N * 2> zip(VectorType<T, N> a, VectorType<T, N> b) {
return combine(zipLow(a, b), zipHigh(a, b));
}
#endif
template <typename T>
struct Unaligned {
template <typename P>

View file

@ -8,8 +8,8 @@ edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
ron = "0.5"
ron = "0.6.2"
serde = {version = "1.0.88", features = ["derive"] }
webrender = {path = "../webrender", features=["capture","replay","debugger","png","profiler","no_static_freetype", "leak_checks"]}
webrender = {path = "../webrender", features=["capture","replay","png","profiler","no_static_freetype", "leak_checks"]}
webrender_api = {path = "../webrender_api", features=["serialize","deserialize"]}
euclid = { version = "0.22.0", features = ["serde"] }

View file

@ -36,7 +36,8 @@ use std::io::prelude::*;
use std::path::Path;
use std::ffi::OsString;
use std::collections::HashMap;
use webrender::api::{enumerate_interners, ColorF};
use webrender::enumerate_interners;
use webrender::api::ColorF;
use euclid::{Rect, Transform3D};
use webrender_api::units::{PicturePoint, PictureSize, PicturePixel, WorldPixel};
@ -59,6 +60,7 @@ static CSS_PRIM_COUNT: &str = "fill:#40f0f0;fill-opacity:0.1;";
static CSS_CONTENT: &str = "fill:#f04040;fill-opacity:0.1;";
static CSS_COMPOSITOR_KIND_CHANGED: &str = "fill:#f0c070;fill-opacity:0.1;";
static CSS_VALID_RECT_CHANGED: &str = "fill:#ff00ff;fill-opacity:0.1;";
static CSS_SCALE_CHANGED: &str = "fill:#ff80ff;fill-opacity:0.1;";
// parameters to tweak the SVG generation
struct SvgSettings {
@ -111,6 +113,7 @@ fn tile_to_svg(key: TileOffset,
Some(InvalidationReason::CompositorKindChanged) => CSS_COMPOSITOR_KIND_CHANGED.to_string(),
Some(InvalidationReason::Content { .. } ) => CSS_CONTENT.to_string(),
Some(InvalidationReason::ValidRectChanged) => CSS_VALID_RECT_CHANGED.to_string(),
Some(InvalidationReason::ScaleChanged) => CSS_SCALE_CHANGED.to_string(),
None => {
let mut background = tile.background_color;
if background.is_none() {

View file

@ -12,30 +12,28 @@ edition = "2018"
default = ["freetype-lib"]
freetype-lib = ["freetype/freetype-sys"]
profiler = ["tracy-rs/enable_profiler"]
debugger = ["ws", "serde_json", "serde", "image_loader", "base64"]
capture = ["api/serialize", "ron", "serde", "smallvec/serde"]
replay = ["api/deserialize", "ron", "serde", "smallvec/serde"]
capture = ["api/serialize", "ron", "serde", "smallvec/serde", "etagere/serialization"]
replay = ["api/deserialize", "ron", "serde", "smallvec/serde", "etagere/serialization"]
display_list_stats = ["api/display_list_stats"]
serialize_program = ["serde", "webrender_build/serialize_program"]
no_static_freetype = []
leak_checks = []
gecko = []
sw_compositor = ["swgl"]
[build-dependencies]
build-parallel = "0.1.1"
glslopt = "0.1.2"
build-parallel = "0.1.2"
glslopt = "0.1.9"
webrender_build = { version = "0.0.1", path = "../webrender_build" }
[dependencies]
base64 = { optional = true, version = "0.10" }
bincode = "1.0"
bitflags = "1.2"
byteorder = "1.0"
cfg-if = "0.1.2"
cstr = "0.1.2"
cstr = "0.2"
euclid = { version = "0.22.0", features = ["serde"] }
fxhash = "0.2.1"
gleam = "0.12.1"
image_loader = { optional = true, version = "0.23", package = "image", default-features = false, features = ["png"] }
gleam = "0.15"
lazy_static = "1"
log = "0.4"
malloc_size_of_derive = "0.1"
@ -43,27 +41,23 @@ num-traits = "0.2"
plane-split = "0.17"
png = { optional = true, version = "0.16" }
rayon = "1"
ron = { optional = true, version = "0.5" }
ron = { optional = true, version = "0.6.2" }
serde = { optional = true, version = "1.0", features = ["serde_derive"] }
serde_json = { optional = true, version = "1.0" }
smallvec = "1"
time = "0.1"
api = { version = "0.61.0", path = "../webrender_api", package = "webrender_api" }
webrender_build = { version = "0.0.1", path = "../webrender_build" }
malloc_size_of = { version = "0.0.1", path = "../wr_malloc_size_of", package = "wr_malloc_size_of" }
ws = { optional = true, version = "0.9" }
svg_fmt = "0.4"
tracy-rs = { version = "0.1" }
tracy-rs = "0.1.2"
derive_more = "0.99"
etagere = "0.2.4"
swgl = { path = "../swgl", optional = true }
[dev-dependencies]
mozangle = "0.3.1"
mozangle = "0.3.3"
rand = "0.4"
[target.'cfg(any(target_os = "macos", target_os = "linux"))'.build-dependencies]
backtrace = "0.3"
sig = "1.0"
libc = "0.2"
[target.'cfg(any(target_os = "android", all(unix, not(target_os = "macos"))))'.dependencies]
freetype = { version = "0.7", default-features = false }
libc = "0.2"
@ -75,3 +69,4 @@ dwrote = "0.11"
core-foundation = "0.9"
core-graphics = "0.22"
core-text = { version = "19", default-features = false }
objc = "0.2"

View file

@ -1,103 +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 https://mozilla.org/MPL/2.0/. */
//! Similar to `println!("{:?}", Backtrace::new())`, but doesnt allocate.
//!
//! Seems to fix some deadlocks: https://github.com/servo/servo/issues/24881
//!
//! FIXME: if/when a future version of the `backtrace` crate has
//! https://github.com/rust-lang/backtrace-rs/pull/265, use that instead.
use std::fmt::{self, Write};
use backtrace::{BytesOrWideString, PrintFmt};
#[inline(never)]
pub(crate) fn print(w: &mut dyn std::io::Write) -> Result<(), std::io::Error> {
write!(w, "{:?}", Print {
print_fn_address: print as usize,
})
}
struct Print {
print_fn_address: usize,
}
impl fmt::Debug for Print {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
// Safety: were in a signal handler that is about to call `libc::_exit`.
// Potential data races from using `*_unsynchronized` functions are perhaps
// less bad than potential deadlocks?
unsafe {
let mut print_fn_frame = 0;
let mut frame_count = 0;
backtrace::trace_unsynchronized(|frame| {
let found = frame.symbol_address() as usize == self.print_fn_address;
if found {
print_fn_frame = frame_count;
}
frame_count += 1;
!found
});
let mode = PrintFmt::Short;
let mut p = print_path;
let mut f = backtrace::BacktraceFmt::new(fmt, mode, &mut p);
f.add_context()?;
let mut result = Ok(());
let mut frame_count = 0;
backtrace::trace_unsynchronized(|frame| {
let skip = frame_count < print_fn_frame;
frame_count += 1;
if skip {
return true
}
let mut frame_fmt = f.frame();
let mut any_symbol = false;
backtrace::resolve_frame_unsynchronized(frame, |symbol| {
any_symbol = true;
if let Err(e) = frame_fmt.symbol(frame, symbol) {
result = Err(e)
}
});
if !any_symbol {
if let Err(e) = frame_fmt.print_raw(frame.ip(), None, None, None) {
result = Err(e)
}
}
result.is_ok()
});
result?;
f.finish()
}
}
}
fn print_path(fmt: &mut fmt::Formatter, path: BytesOrWideString) -> fmt::Result {
match path {
BytesOrWideString::Bytes(mut bytes) => {
loop {
match std::str::from_utf8(bytes) {
Ok(s) => {
fmt.write_str(s)?;
break;
}
Err(err) => {
fmt.write_char(std::char::REPLACEMENT_CHARACTER)?;
match err.error_len() {
Some(len) => bytes = &bytes[err.valid_up_to() + len..],
None => break,
}
}
}
}
}
BytesOrWideString::Wide(wide) => {
for c in std::char::decode_utf16(wide.iter().cloned()) {
fmt.write_char(c.unwrap_or(std::char::REPLACEMENT_CHARACTER))?
}
}
}
Ok(())
}

View file

@ -2,8 +2,6 @@
* 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 webrender_build;
use std::borrow::Cow;
use std::env;
use std::fs::{canonicalize, read_dir, File};
@ -14,6 +12,12 @@ use std::hash::Hasher;
use webrender_build::shader::*;
use webrender_build::shader_features::{ShaderFeatureFlags, get_shader_features};
// glsopt is known to leak, but we don't particularly care.
#[no_mangle]
pub extern "C" fn __lsan_default_options() -> *const u8 {
b"detect_leaks=0\0".as_ptr()
}
/// Compute the shader path for insertion into the include_str!() macro.
/// This makes for more compact generated code than inserting the literal
/// shader source into the generated file.
@ -94,6 +98,16 @@ struct ShaderOptimizationError {
message: String,
}
fn print_shader_source(shader_src: &str) {
// For some reason the glsl-opt errors are offset by 1 compared
// to the provided shader source string.
println!("0\t|");
for (n, line) in shader_src.split('\n').enumerate() {
let line_number = n + 1;
println!("{}\t|{}", line_number, line);
}
}
fn write_optimized_shaders(shader_dir: &Path, shader_file: &mut File, out_dir: &str) -> Result<(), std::io::Error> {
writeln!(
shader_file,
@ -119,8 +133,10 @@ fn write_optimized_shaders(shader_dir: &Path, shader_file: &mut File, out_dir: &
flags.remove(ShaderFeatureFlags::GLES);
flags.remove(ShaderFeatureFlags::TEXTURE_EXTERNAL);
}
if !matches!(env::var("CARGO_CFG_TARGET_OS").as_ref().map(|s| &**s), Ok("android")) {
flags.remove(ShaderFeatureFlags::TEXTURE_EXTERNAL_ESSL1);
}
flags.remove(ShaderFeatureFlags::DITHERING);
flags.remove(ShaderFeatureFlags::PIXEL_LOCAL_STORAGE);
for (shader_name, configs) in get_shader_features(flags) {
for config in configs {
@ -156,15 +172,17 @@ fn write_optimized_shaders(shader_dir: &Path, shader_file: &mut File, out_dir: &
format!("{}_{}", shader.shader_name, shader.config.replace(",", "_"))
};
let vert = glslopt_ctx.optimize(glslopt::ShaderType::Vertex, vert_src);
let vert = glslopt_ctx.optimize(glslopt::ShaderType::Vertex, vert_src.clone());
if !vert.get_status() {
print_shader_source(&vert_src);
return Err(ShaderOptimizationError {
shader: shader.clone(),
message: vert.get_log().to_string(),
});
}
let frag = glslopt_ctx.optimize(glslopt::ShaderType::Fragment, frag_src);
let frag = glslopt_ctx.optimize(glslopt::ShaderType::Fragment, frag_src.clone());
if !frag.get_status() {
print_shader_source(&frag_src);
return Err(ShaderOptimizationError {
shader: shader.clone(),
message: frag.get_log().to_string(),
@ -178,17 +196,15 @@ fn write_optimized_shaders(shader_dir: &Path, shader_file: &mut File, out_dir: &
// as a literal alongside the source string so that we don't need
// to hash large strings at runtime.
let mut hasher = DefaultHasher::new();
hasher.write(vert_source.as_bytes());
hasher.write(frag_source.as_bytes());
let digest: ProgramSourceDigest = hasher.into();
let vert_file_path = Path::new(out_dir)
.join(format!("{}_{:?}.vert", full_shader_name, shader.gl_version));
let mut vert_file = File::create(&vert_file_path).unwrap();
vert_file.write_all(vert_source.as_bytes()).unwrap();
write_optimized_shader_file(&vert_file_path, vert_source, &shader.shader_name, &features, &mut hasher);
let frag_file_path = vert_file_path.with_extension("frag");
let mut frag_file = File::create(&frag_file_path).unwrap();
frag_file.write_all(frag_source.as_bytes()).unwrap();
write_optimized_shader_file(&frag_file_path, frag_source, &shader.shader_name, &features, &mut hasher);
let digest: ProgramSourceDigest = hasher.into();
println!("Finished optimizing shader {:?}", shader);
@ -244,37 +260,35 @@ fn write_optimized_shaders(shader_dir: &Path, shader_file: &mut File, out_dir: &
Ok(())
}
#[cfg(any(target_os = "macos", target_os = "linux"))]
mod backtrace;
#[cfg(any(target_os = "macos", target_os = "linux"))]
extern "C" fn handler(sig: i32) {
use std::sync::atomic;
static BEEN_HERE_BEFORE: atomic::AtomicBool = atomic::AtomicBool::new(false);
if !BEEN_HERE_BEFORE.swap(true, atomic::Ordering::SeqCst) {
let stdout = std::io::stdout();
let mut stdout = stdout.lock();
let _ = write!(&mut stdout, "Stack trace");
if let Some(name) = std::thread::current().name() {
let _ = write!(&mut stdout, " for thread \"{}\"", name);
fn write_optimized_shader_file(
path: &Path,
source: &str,
shader_name: &str,
features: &[&str],
hasher: &mut DefaultHasher,
) {
let mut file = File::create(&path).unwrap();
for (line_number, line) in source.lines().enumerate() {
// We embed the shader name and features as a comment in the
// source to make debugging easier.
// The #version directive must be on the first line so we insert
// the extra information on the next line.
if line_number == 1 {
let prelude = format!(
"// {}\n// features: {:?}\n\n",
shader_name, features
);
file.write_all(prelude.as_bytes()).unwrap();
hasher.write(prelude.as_bytes());
}
let _ = write!(&mut stdout, "\n");
let _ = backtrace::print(&mut stdout);
}
unsafe {
libc::_exit(sig);
file.write_all(line.as_bytes()).unwrap();
file.write_all("\n".as_bytes()).unwrap();
hasher.write(line.as_bytes());
hasher.write("\n".as_bytes());
}
}
fn main() -> Result<(), std::io::Error> {
#[cfg(any(target_os = "macos", target_os = "linux"))]
{
sig::signal!(sig::ffi::Sig::SEGV, handler); // handle segfaults
sig::signal!(sig::ffi::Sig::ILL, handler); // handle stack overflow and unsupported CPUs
sig::signal!(sig::ffi::Sig::IOT, handler); // handle double panics
sig::signal!(sig::ffi::Sig::BUS, handler); // handle invalid memory access
}
let out_dir = env::var("OUT_DIR").unwrap_or("out".to_owned());
let shaders_file_path = Path::new(&out_dir).join("shaders.rs");

View file

@ -4,12 +4,6 @@
#if defined(GL_ES)
#if GL_ES == 1
#ifdef GL_FRAGMENT_PRECISION_HIGH
precision highp sampler2DArray;
#else
precision mediump sampler2DArray;
#endif
// Sampler default precision is lowp on mobile GPUs.
// This causes RGBA32F texture data to be clamped to 16 bit floats on some GPUs (e.g. Mali-T880).
// Define highp precision macro to allow lossless FLOAT texture sampling.
@ -32,7 +26,20 @@
#else
#define HIGHP_SAMPLER_FLOAT
#define HIGHP_FS_ADDRESS
#define TEXEL_FETCH(sampler, position, lod, offset) texelFetchOffset(sampler, position, lod, offset)
#if defined(PLATFORM_MACOS) && !defined(SWGL)
// texelFetchOffset introduces a variety of shader compilation bugs on macOS Intel so avoid it.
#define TEXEL_FETCH(sampler, position, lod, offset) texelFetch(sampler, position + offset, lod)
#else
#define TEXEL_FETCH(sampler, position, lod, offset) texelFetchOffset(sampler, position, lod, offset)
#endif
#endif
#ifdef SWGL
#define SWGL_DRAW_SPAN
#define SWGL_CLIP_MASK
#define SWGL_ANTIALIAS
#define SWGL_BLEND
#define SWGL_CLIP_DIST
#endif
#ifdef WR_VERTEX_SHADER
@ -44,10 +51,20 @@
#define PER_INSTANCE
#endif
#define varying out
#if __VERSION__ != 100
#define varying out
#define attribute in
#endif
#endif
#ifdef WR_FRAGMENT_SHADER
precision highp float;
#define varying in
#if __VERSION__ != 100
#define varying in
#endif
#endif
// Flat interpolation is not supported on ESSL 1
#if __VERSION__ == 100
#define flat
#endif

View file

@ -0,0 +1,233 @@
/* 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 COMPONENT_TRANSFER_IDENTITY 0
#define COMPONENT_TRANSFER_TABLE 1
#define COMPONENT_TRANSFER_DISCRETE 2
#define COMPONENT_TRANSFER_LINEAR 3
#define COMPONENT_TRANSFER_GAMMA 4
// Must be kept in sync with `Filter::as_int` in internal_types.rs
// Not all filters are defined here because some filter use different shaders.
#define FILTER_CONTRAST 0
#define FILTER_GRAYSCALE 1
#define FILTER_HUE_ROTATE 2
#define FILTER_INVERT 3
#define FILTER_SATURATE 4
#define FILTER_SEPIA 5
#define FILTER_BRIGHTNESS 6
#define FILTER_COLOR_MATRIX 7
#define FILTER_SRGB_TO_LINEAR 8
#define FILTER_LINEAR_TO_SRGB 9
#define FILTER_FLOOD 10
#define FILTER_COMPONENT_TRANSFER 11
#ifdef WR_VERTEX_SHADER
void SetupFilterParams(
int op,
float amount,
int gpu_data_address,
out vec4 color_offset,
out mat4 color_mat,
out int table_address
) {
float lumR = 0.2126;
float lumG = 0.7152;
float lumB = 0.0722;
float oneMinusLumR = 1.0 - lumR;
float oneMinusLumG = 1.0 - lumG;
float oneMinusLumB = 1.0 - lumB;
float invAmount = 1.0 - amount;
if (op == FILTER_GRAYSCALE) {
color_mat = mat4(
vec4(lumR + oneMinusLumR * invAmount, lumR - lumR * invAmount, lumR - lumR * invAmount, 0.0),
vec4(lumG - lumG * invAmount, lumG + oneMinusLumG * invAmount, lumG - lumG * invAmount, 0.0),
vec4(lumB - lumB * invAmount, lumB - lumB * invAmount, lumB + oneMinusLumB * invAmount, 0.0),
vec4(0.0, 0.0, 0.0, 1.0)
);
color_offset = vec4(0.0);
} else if (op == FILTER_HUE_ROTATE) {
float c = cos(amount);
float s = sin(amount);
color_mat = mat4(
vec4(lumR + oneMinusLumR * c - lumR * s, lumR - lumR * c + 0.143 * s, lumR - lumR * c - oneMinusLumR * s, 0.0),
vec4(lumG - lumG * c - lumG * s, lumG + oneMinusLumG * c + 0.140 * s, lumG - lumG * c + lumG * s, 0.0),
vec4(lumB - lumB * c + oneMinusLumB * s, lumB - lumB * c - 0.283 * s, lumB + oneMinusLumB * c + lumB * s, 0.0),
vec4(0.0, 0.0, 0.0, 1.0)
);
color_offset = vec4(0.0);
} else if (op == FILTER_SATURATE) {
color_mat = mat4(
vec4(invAmount * lumR + amount, invAmount * lumR, invAmount * lumR, 0.0),
vec4(invAmount * lumG, invAmount * lumG + amount, invAmount * lumG, 0.0),
vec4(invAmount * lumB, invAmount * lumB, invAmount * lumB + amount, 0.0),
vec4(0.0, 0.0, 0.0, 1.0)
);
color_offset = vec4(0.0);
} else if (op == FILTER_SEPIA) {
color_mat = mat4(
vec4(0.393 + 0.607 * invAmount, 0.349 - 0.349 * invAmount, 0.272 - 0.272 * invAmount, 0.0),
vec4(0.769 - 0.769 * invAmount, 0.686 + 0.314 * invAmount, 0.534 - 0.534 * invAmount, 0.0),
vec4(0.189 - 0.189 * invAmount, 0.168 - 0.168 * invAmount, 0.131 + 0.869 * invAmount, 0.0),
vec4(0.0, 0.0, 0.0, 1.0)
);
color_offset = vec4(0.0);
} else if (op == FILTER_COLOR_MATRIX) {
vec4 mat_data[4] = fetch_from_gpu_cache_4(gpu_data_address);
vec4 offset_data = fetch_from_gpu_cache_1(gpu_data_address + 4);
color_mat = mat4(mat_data[0], mat_data[1], mat_data[2], mat_data[3]);
color_offset = offset_data;
} else if (op == FILTER_COMPONENT_TRANSFER) {
table_address = gpu_data_address;
} else if (op == FILTER_FLOOD) {
color_offset = fetch_from_gpu_cache_1(gpu_data_address);
}
}
#endif
#ifdef WR_FRAGMENT_SHADER
vec3 Contrast(vec3 Cs, float amount) {
return clamp(Cs.rgb * amount - 0.5 * amount + 0.5, 0.0, 1.0);
}
vec3 Invert(vec3 Cs, float amount) {
return mix(Cs.rgb, vec3(1.0) - Cs.rgb, amount);
}
vec3 Brightness(vec3 Cs, float amount) {
// Apply the brightness factor.
// Resulting color needs to be clamped to output range
// since we are pre-multiplying alpha in the shader.
return clamp(Cs.rgb * amount, vec3(0.0), vec3(1.0));
}
// Based on the Gecko's implementation in
// https://hg.mozilla.org/mozilla-central/file/91b4c3687d75/gfx/src/FilterSupport.cpp#l24
// These could be made faster by sampling a lookup table stored in a float texture
// with linear interpolation.
vec3 SrgbToLinear(vec3 color) {
vec3 c1 = color / 12.92;
vec3 c2 = pow(color / 1.055 + vec3(0.055 / 1.055), vec3(2.4));
return if_then_else(lessThanEqual(color, vec3(0.04045)), c1, c2);
}
vec3 LinearToSrgb(vec3 color) {
vec3 c1 = color * 12.92;
vec3 c2 = vec3(1.055) * pow(color, vec3(1.0 / 2.4)) - vec3(0.055);
return if_then_else(lessThanEqual(color, vec3(0.0031308)), c1, c2);
}
// This function has to be factored out due to the following issue:
// https://github.com/servo/webrender/wiki/Driver-issues#bug-1532245---switch-statement-inside-control-flow-inside-switch-statement-fails-to-compile-on-some-android-phones
// (and now the words "default: default:" so angle_shader_validation.rs passes)
vec4 ComponentTransfer(vec4 colora, ivec4 vfuncs, int table_address) {
// We push a different amount of data to the gpu cache depending on the
// function type.
// Identity => 0 blocks
// Table/Discrete => 64 blocks (256 values)
// Linear => 1 block (2 values)
// Gamma => 1 block (3 values)
// We loop through the color components and increment the offset (for the
// next color component) into the gpu cache based on how many blocks that
// function type put into the gpu cache.
// Table/Discrete use a 256 entry look up table.
// Linear/Gamma are a simple calculation.
int offset = 0;
vec4 texel;
int k;
// Dynamically indexing a vector is buggy on some platforms, so use a temporary array
int[4] funcs = int[4](vfuncs.r, vfuncs.g, vfuncs.b, vfuncs.a);
for (int i = 0; i < 4; i++) {
switch (funcs[i]) {
case COMPONENT_TRANSFER_IDENTITY:
break;
case COMPONENT_TRANSFER_TABLE:
case COMPONENT_TRANSFER_DISCRETE: {
// fetch value from lookup table
k = int(floor(colora[i]*255.0));
texel = fetch_from_gpu_cache_1(table_address + offset + k/4);
colora[i] = clamp(texel[k % 4], 0.0, 1.0);
// offset plus 256/4 blocks
offset = offset + 64;
break;
}
case COMPONENT_TRANSFER_LINEAR: {
// fetch the two values for use in the linear equation
texel = fetch_from_gpu_cache_1(table_address + offset);
colora[i] = clamp(texel[0] * colora[i] + texel[1], 0.0, 1.0);
// offset plus 1 block
offset = offset + 1;
break;
}
case COMPONENT_TRANSFER_GAMMA: {
// fetch the three values for use in the gamma equation
texel = fetch_from_gpu_cache_1(table_address + offset);
colora[i] = clamp(texel[0] * pow(colora[i], texel[1]) + texel[2], 0.0, 1.0);
// offset plus 1 block
offset = offset + 1;
break;
}
default:
// shouldn't happen
break;
}
}
return colora;
}
void CalculateFilter(
vec4 Cs,
int op,
float amount,
int table_address,
vec4 color_offset,
mat4 color_mat,
ivec4 v_funcs,
out vec3 color,
out float alpha
) {
// Un-premultiply the input.
alpha = Cs.a;
color = alpha != 0.0 ? Cs.rgb / alpha : Cs.rgb;
switch (op) {
case FILTER_CONTRAST:
color = Contrast(color, amount);
break;
case FILTER_INVERT:
color = Invert(color, amount);
break;
case FILTER_BRIGHTNESS:
color = Brightness(color, amount);
break;
case FILTER_SRGB_TO_LINEAR:
color = SrgbToLinear(color);
break;
case FILTER_LINEAR_TO_SRGB:
color = LinearToSrgb(color);
break;
case FILTER_COMPONENT_TRANSFER: {
// Get the unpremultiplied color with alpha.
vec4 colora = vec4(color, alpha);
colora = ComponentTransfer(colora, v_funcs, table_address);
color = colora.rgb;
alpha = colora.a;
break;
}
case FILTER_FLOOD:
color = color_offset.rgb;
alpha = color_offset.a;
break;
default:
// Color matrix type filters (sepia, hue-rotate, etc...)
vec4 result = color_mat * vec4(color, alpha) + color_offset;
result = clamp(result, vec4(0.0), vec4(1.0));
color = result.rgb;
alpha = result.a;
}
}
#endif

Some files were not shown because too many files have changed in this diff Show more