From 5c5fe00b276e6d18e1752f2d7f56c6190daa9355 Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Mon, 17 Jun 2019 13:16:03 -0700 Subject: [PATCH 1/5] Fix build problem --- demo/common/src/device.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/demo/common/src/device.rs b/demo/common/src/device.rs index 29b27540..a34f7f83 100644 --- a/demo/common/src/device.rs +++ b/demo/common/src/device.rs @@ -63,7 +63,7 @@ where ) -> GroundVertexArray { let vertex_array = device.create_vertex_array(); - let position_attr = device.get_vertex_attr(&ground_program.program, "Position"); + let position_attr = device.get_vertex_attr(&ground_program.program, "Position").unwrap(); device.bind_vertex_array(&vertex_array); device.use_program(&ground_program.program); From 487577a11b85145f85fc9bcfcac0ec8b4f34486a Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Wed, 5 Jun 2019 14:35:46 -0700 Subject: [PATCH 2/5] Add Metal support. This commit substantially reworks the `pathfinder_gpu` API to better support modern APIs like Metal. It should open the door to `gfx-rs`, `wgpu`, Vulkan, and D3D12 backends relatively straightforwardly. A new example, `canvas_metal_minimal`, has been added. Note that the new Metal shaders require a patched version of `spirv-cross` to build properly. An upstream patch is forthcoming. --- .gitignore | 1 + Cargo.lock | 89 + Cargo.toml | 2 + c/include/pathfinder/pathfinder.h | 32 +- c/src/lib.rs | 81 +- demo/common/Cargo.toml | 9 + demo/common/src/device.rs | 15 +- demo/common/src/lib.rs | 48 +- demo/common/src/renderer.rs | 140 +- demo/common/src/ui.rs | 16 +- demo/common/src/window.rs | 32 +- demo/magicleap/src/lib.rs | 1 + demo/native/Cargo.toml | 8 + demo/native/src/main.rs | 107 +- examples/c_canvas_minimal/c_canvas_minimal.c | 10 +- examples/canvas_glutin_minimal/src/main.rs | 16 +- examples/canvas_metal_minimal/Cargo.toml | 31 + examples/canvas_metal_minimal/src/main.rs | 87 + examples/canvas_minimal/src/main.rs | 14 +- examples/canvas_moire/src/main.rs | 16 +- examples/canvas_text/src/main.rs | 14 +- geometry/src/color.rs | 22 +- gl/src/lib.rs | 456 +++-- gpu/src/lib.rs | 124 +- metal/Cargo.toml | 24 + metal/src/lib.rs | 1484 +++++++++++++++++ renderer/Cargo.toml | 1 + renderer/src/builder.rs | 8 +- renderer/src/concurrent/scene_proxy.rs | 16 +- renderer/src/gpu/mod.rs | 1 + renderer/src/gpu/options.rs | 60 + renderer/src/gpu/renderer.rs | 803 +++++---- renderer/src/gpu_data.rs | 1 + renderer/src/lib.rs | 2 + renderer/src/options.rs | 15 +- renderer/src/scene.rs | 10 +- renderer/src/z_buffer.rs | 1 + resources/shaders/gl3/debug_solid.fs.glsl | 2 + resources/shaders/gl3/debug_solid.vs.glsl | 6 +- resources/shaders/gl3/debug_texture.fs.glsl | 2 + resources/shaders/gl3/debug_texture.vs.glsl | 10 +- resources/shaders/gl3/demo_ground.fs.glsl | 2 + resources/shaders/gl3/demo_ground.vs.glsl | 8 +- resources/shaders/gl3/fill.fs.glsl | 2 + resources/shaders/gl3/fill.vs.glsl | 16 +- resources/shaders/gl3/post.fs.glsl | 2 + resources/shaders/gl3/post.vs.glsl | 8 +- resources/shaders/gl3/reproject.fs.glsl | 2 + resources/shaders/gl3/reproject.vs.glsl | 13 +- resources/shaders/gl3/stencil.fs.glsl | 2 + resources/shaders/gl3/stencil.vs.glsl | 2 + resources/shaders/gl3/tile_alpha.fs.glsl | 2 + .../shaders/gl3/tile_alpha_monochrome.vs.glsl | 10 +- .../shaders/gl3/tile_alpha_multicolor.vs.glsl | 10 +- resources/shaders/gl3/tile_solid.fs.glsl | 2 + .../shaders/gl3/tile_solid_monochrome.vs.glsl | 9 +- .../shaders/gl3/tile_solid_multicolor.vs.glsl | 9 +- resources/shaders/metal/debug_solid.fs.metal | 10 +- resources/shaders/metal/debug_solid.vs.metal | 12 +- .../shaders/metal/debug_texture.fs.metal | 14 +- .../shaders/metal/debug_texture.vs.metal | 17 +- resources/shaders/metal/demo_ground.fs.metal | 11 +- resources/shaders/metal/demo_ground.vs.metal | 15 +- resources/shaders/metal/fill.fs.metal | 11 +- resources/shaders/metal/fill.vs.metal | 29 +- resources/shaders/metal/post.fs.metal | 38 +- resources/shaders/metal/post.vs.metal | 9 +- resources/shaders/metal/reproject.fs.metal | 14 +- resources/shaders/metal/reproject.vs.metal | 16 +- resources/shaders/metal/stencil.fs.metal | 1 + resources/shaders/metal/stencil.vs.metal | 3 +- resources/shaders/metal/tile_alpha.fs.metal | 11 +- .../metal/tile_alpha_monochrome.vs.metal | 26 +- .../metal/tile_alpha_multicolor.vs.metal | 27 +- resources/shaders/metal/tile_solid.fs.metal | 1 + .../metal/tile_solid_monochrome.vs.metal | 21 +- .../metal/tile_solid_multicolor.vs.metal | 22 +- resources/shaders/spirv/debug_solid.fs.spv | Bin 644 -> 0 bytes resources/shaders/spirv/debug_solid.vs.spv | Bin 1252 -> 0 bytes resources/shaders/spirv/debug_texture.fs.spv | Bin 1064 -> 0 bytes resources/shaders/spirv/debug_texture.vs.spv | Bin 1516 -> 0 bytes resources/shaders/spirv/demo_ground.fs.spv | Bin 908 -> 0 bytes resources/shaders/spirv/demo_ground.vs.spv | Bin 1328 -> 0 bytes resources/shaders/spirv/fill.fs.spv | Bin 2688 -> 0 bytes resources/shaders/spirv/fill.vs.spv | Bin 3908 -> 0 bytes resources/shaders/spirv/post.fs.spv | Bin 6864 -> 0 bytes resources/shaders/spirv/post.vs.spv | Bin 1080 -> 0 bytes resources/shaders/spirv/reproject.fs.spv | Bin 1212 -> 0 bytes resources/shaders/spirv/reproject.vs.spv | Bin 1144 -> 0 bytes resources/shaders/spirv/stencil.fs.spv | Bin 352 -> 0 bytes resources/shaders/spirv/stencil.vs.spv | Bin 908 -> 0 bytes resources/shaders/spirv/tile_alpha.fs.spv | Bin 1140 -> 0 bytes .../spirv/tile_alpha_monochrome.vs.spv | Bin 3876 -> 0 bytes .../spirv/tile_alpha_multicolor.vs.spv | Bin 4128 -> 0 bytes resources/shaders/spirv/tile_solid.fs.spv | Bin 376 -> 0 bytes .../spirv/tile_solid_monochrome.vs.spv | Bin 2016 -> 0 bytes .../spirv/tile_solid_multicolor.vs.spv | Bin 2268 -> 0 bytes shaders/Makefile | 26 +- shaders/debug_solid.vs.glsl | 4 +- shaders/debug_texture.vs.glsl | 8 +- shaders/demo_ground.vs.glsl | 6 +- shaders/fill.vs.glsl | 16 +- shaders/post.vs.glsl | 6 +- shaders/reproject.vs.glsl | 12 +- shaders/tile_alpha_vertex.inc.glsl | 8 +- shaders/tile_solid_vertex.inc.glsl | 7 +- ui/src/lib.rs | 117 +- 107 files changed, 3344 insertions(+), 1090 deletions(-) create mode 100644 examples/canvas_metal_minimal/Cargo.toml create mode 100644 examples/canvas_metal_minimal/src/main.rs create mode 100644 metal/Cargo.toml create mode 100644 metal/src/lib.rs create mode 100644 renderer/src/gpu/options.rs delete mode 100644 resources/shaders/spirv/debug_solid.fs.spv delete mode 100644 resources/shaders/spirv/debug_solid.vs.spv delete mode 100644 resources/shaders/spirv/debug_texture.fs.spv delete mode 100644 resources/shaders/spirv/debug_texture.vs.spv delete mode 100644 resources/shaders/spirv/demo_ground.fs.spv delete mode 100644 resources/shaders/spirv/demo_ground.vs.spv delete mode 100644 resources/shaders/spirv/fill.fs.spv delete mode 100644 resources/shaders/spirv/fill.vs.spv delete mode 100644 resources/shaders/spirv/post.fs.spv delete mode 100644 resources/shaders/spirv/post.vs.spv delete mode 100644 resources/shaders/spirv/reproject.fs.spv delete mode 100644 resources/shaders/spirv/reproject.vs.spv delete mode 100644 resources/shaders/spirv/stencil.fs.spv delete mode 100644 resources/shaders/spirv/stencil.vs.spv delete mode 100644 resources/shaders/spirv/tile_alpha.fs.spv delete mode 100644 resources/shaders/spirv/tile_alpha_monochrome.vs.spv delete mode 100644 resources/shaders/spirv/tile_alpha_multicolor.vs.spv delete mode 100644 resources/shaders/spirv/tile_solid.fs.spv delete mode 100644 resources/shaders/spirv/tile_solid_monochrome.vs.spv delete mode 100644 resources/shaders/spirv/tile_solid_multicolor.vs.spv diff --git a/.gitignore b/.gitignore index 82600a0a..4150bad5 100644 --- a/.gitignore +++ b/.gitignore @@ -6,6 +6,7 @@ target /site/dist node_modules /examples/c_canvas_minimal/build +/shaders/build # Editors *.swp diff --git a/Cargo.lock b/Cargo.lock index 18ff3a79..c35ee108 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -161,6 +161,24 @@ dependencies = [ "pathfinder_renderer 0.1.0", ] +[[package]] +name = "canvas_metal_minimal" +version = "0.1.0" +dependencies = [ + "foreign-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "gl 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", + "metal 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)", + "objc 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", + "pathfinder_canvas 0.1.0", + "pathfinder_geometry 0.3.0", + "pathfinder_gl 0.1.0", + "pathfinder_gpu 0.1.0", + "pathfinder_metal 0.1.0", + "pathfinder_renderer 0.1.0", + "sdl2 0.32.2 (registry+https://github.com/rust-lang/crates.io-index)", + "sdl2-sys 0.32.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "canvas_minimal" version = "0.1.0" @@ -419,13 +437,16 @@ name = "demo" version = "0.1.0" dependencies = [ "color-backtrace 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "foreign-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "gl 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "jemallocator 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", + "metal 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)", "nfd 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)", "pathfinder_demo 0.1.0", "pathfinder_geometry 0.3.0", "pathfinder_gl 0.1.0", "pathfinder_gpu 0.1.0", + "pathfinder_metal 0.1.0", "pathfinder_simd 0.3.0", "pretty_env_logger 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "sdl2 0.32.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1083,6 +1104,23 @@ name = "memoffset" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "metal" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "block 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "cocoa 0.18.4 (registry+https://github.com/rust-lang/crates.io-index)", + "core-graphics 0.17.3 (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.54 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "objc 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", + "objc-foundation 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "objc_id 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "nfd" version = "0.0.4" @@ -1187,6 +1225,33 @@ version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "malloc_buf 0.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "objc_exception 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "objc-foundation" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "block 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "objc 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", + "objc_id 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "objc_exception" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "gcc 0.3.55 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "objc_id" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "objc 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1280,9 +1345,11 @@ dependencies = [ "gl 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "image 0.21.1 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "metal 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)", "pathfinder_geometry 0.3.0", "pathfinder_gl 0.1.0", "pathfinder_gpu 0.1.0", + "pathfinder_metal 0.1.0", "pathfinder_renderer 0.1.0", "pathfinder_simd 0.3.0", "pathfinder_svg 0.1.0", @@ -1356,10 +1423,28 @@ dependencies = [ "usvg 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "pathfinder_metal" +version = "0.1.0" +dependencies = [ + "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "block 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "cocoa 0.18.4 (registry+https://github.com/rust-lang/crates.io-index)", + "core-foundation 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)", + "foreign-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "metal 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)", + "objc 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", + "pathfinder_geometry 0.3.0", + "pathfinder_gpu 0.1.0", + "pathfinder_simd 0.3.0", +] + [[package]] name = "pathfinder_renderer" version = "0.1.0" dependencies = [ + "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "fixedbitset 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", "hashbrown 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2374,6 +2459,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum memmap 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e2ffa2c986de11a9df78620c01eeaaf27d94d3ff02bf81bfcca953102dd0c6ff" "checksum memmap 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6585fd95e7bb50d6cc31e20d4cf9afb4e2ba16c5846fc76793f11218da9c475b" "checksum memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0f9dc261e2b62d7a622bf416ea3c5245cdd5d9a7fcc428c0d06804dfce1775b3" +"checksum metal 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cd3f21d259068945192293b7a98b1c6844af9eb7602e393c405198b229efc157" "checksum nfd 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8e752e3c216bc8a491c5b59fa46da10f1379ae450b19ac688e07f4bb55042e98" "checksum nix 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)" = "46f0f3210768d796e8fa79ec70ee6af172dacbe7147f5e69be5240a47778302b" "checksum nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9667ddcc6cc8a43afc9b7917599d7216aa09c463919ea32c59ed6cac8bc945" @@ -2387,6 +2473,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum num_cpus 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1a23f0ed30a54abaa0c7e83b1d2d87ada7c3c23078d1d87815af3e3b6385fbba" "checksum numtoa 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b8f8bdf33df195859076e54ab11ee78a1b208382d3a26ec40d142ffc1ecc49ef" "checksum objc 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "31d20fd2b37e07cf5125be68357b588672e8cefe9a96f8c17a9d46053b3e590d" +"checksum objc-foundation 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1add1b659e36c9607c7aab864a76c7a4c2760cd0cd2e120f3fb8b952c7e22bf9" +"checksum objc_exception 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "098cd29a2fa3c230d3463ae069cecccc3fdfd64c0d2496ab5b96f82dab6a00dc" +"checksum objc_id 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c92d4ddb4bd7b50d730c215ff871754d0da6b2178849f8a2a2ab69712d0c073b" "checksum ordered-float 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "18869315e81473c951eb56ad5558bbc56978562d3ecfb87abb7a1e944cea4518" "checksum osmesa-sys 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "88cfece6e95d2e717e0872a7f53a8684712ad13822a7979bc760b9c77ec0013b" "checksum owning_ref 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "49a4b8ea2179e6a2e27411d3bca09ca6dd630821cf6894c6c7c8467a8ee7ef13" diff --git a/Cargo.toml b/Cargo.toml index 34e73625..83f67f54 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,6 +7,7 @@ members = [ "demo/magicleap", "demo/native", "examples/canvas_glutin_minimal", + "examples/canvas_metal_minimal", "examples/canvas_minimal", "examples/canvas_moire", "examples/canvas_text", @@ -15,6 +16,7 @@ members = [ "gl", "gpu", "lottie", + "metal", "renderer", "simd", "svg", diff --git a/c/include/pathfinder/pathfinder.h b/c/include/pathfinder/pathfinder.h index 8962e782..d924ce7b 100644 --- a/c/include/pathfinder/pathfinder.h +++ b/c/include/pathfinder/pathfinder.h @@ -30,12 +30,9 @@ extern "C" { #define PF_GL_VERSION_GL3 0 #define PF_GL_VERSION_GLES3 1 -// `gpu` +// `renderer` -#define PF_CLEAR_FLAGS_HAS_COLOR 0x1 -#define PF_CLEAR_FLAGS_HAS_DEPTH 0x2 -#define PF_CLEAR_FLAGS_HAS_STENCIL 0x4 -#define PF_CLEAR_FLAGS_HAS_RECT 0x8 +#define PF_RENDERER_OPTIONS_FLAGS_HAS_BACKGROUND_COLOR 0x1 // Types @@ -85,24 +82,21 @@ typedef uint32_t PFGLVersion; // `gpu` -typedef uint8_t PFClearFlags; -struct PFClearParams { - PFColorF color; - float depth; - uint8_t stencil; - PFRectI rect; - PFClearFlags flags; -}; -typedef struct PFClearParams PFClearParams; struct PFResourceLoader; typedef struct PFResourceLoader *PFResourceLoaderRef; // `renderer` -struct PFRenderOptions { +typedef uint8_t PFRendererOptionsFlags; +struct PFRendererOptions { + PFColorF background_color; + PFRendererOptionsFlags flags; +}; +struct PFBuildOptions { uint32_t placeholder; }; -typedef struct PFRenderOptions PFRenderOptions; +typedef struct PFRendererOptions PFRendererOptions; +typedef struct PFBuildOptions PFBuildOptions; struct PFScene; typedef struct PFScene *PFSceneRef; struct PFSceneProxy; @@ -142,17 +136,17 @@ PFGLDestFramebufferRef PFGLDestFramebufferCreateFullWindow(const PFVector2I *win void PFGLDestFramebufferDestroy(PFGLDestFramebufferRef dest_framebuffer); PFGLDeviceRef PFGLDeviceCreate(PFGLVersion version, uint32_t default_framebuffer); void PFGLDeviceDestroy(PFGLDeviceRef device); -void PFGLDeviceClear(PFGLDeviceRef device, const PFClearParams *params); void PFGLLoadWith(PFGLFunctionLoader loader, void *userdata); PFGLRendererRef PFGLRendererCreate(PFGLDeviceRef device, PFResourceLoaderRef resources, - PFGLDestFramebufferRef dest_framebuffer); + PFGLDestFramebufferRef dest_framebuffer, + const PFRendererOptions *options); void PFGLRendererDestroy(PFGLRendererRef renderer); /// Returns a borrowed reference to the device. PFGLDeviceRef PFGLRendererGetDevice(PFGLRendererRef renderer); void PFSceneProxyBuildAndRenderGL(PFSceneProxyRef scene_proxy, PFGLRendererRef renderer, - const PFRenderOptions *options); + const PFBuildOptions *build_options); // `gpu` diff --git a/c/src/lib.rs b/c/src/lib.rs index f3ec9c71..7454e90c 100644 --- a/c/src/lib.rs +++ b/c/src/lib.rs @@ -18,11 +18,11 @@ use pathfinder_geometry::color::ColorF; use pathfinder_geometry::stroke::LineCap; use pathfinder_gl::{GLDevice, GLVersion}; use pathfinder_gpu::resources::{FilesystemResourceLoader, ResourceLoader}; -use pathfinder_gpu::{ClearParams, Device}; use pathfinder_renderer::concurrent::rayon::RayonExecutor; use pathfinder_renderer::concurrent::scene_proxy::SceneProxy; -use pathfinder_renderer::gpu::renderer::{DestFramebuffer, Renderer}; -use pathfinder_renderer::options::RenderOptions; +use pathfinder_renderer::gpu::options::{DestFramebuffer, RendererOptions}; +use pathfinder_renderer::gpu::renderer::Renderer; +use pathfinder_renderer::options::BuildOptions; use pathfinder_renderer::scene::Scene; use pathfinder_simd::default::F32x4; use std::ffi::CString; @@ -30,14 +30,13 @@ use std::os::raw::{c_char, c_void}; // Constants +// `canvas` pub const PF_LINE_CAP_BUTT: u8 = 0; pub const PF_LINE_CAP_SQUARE: u8 = 1; pub const PF_LINE_CAP_ROUND: u8 = 2; -pub const PF_CLEAR_FLAGS_HAS_COLOR: u8 = 0x1; -pub const PF_CLEAR_FLAGS_HAS_DEPTH: u8 = 0x2; -pub const PF_CLEAR_FLAGS_HAS_STENCIL: u8 = 0x4; -pub const PF_CLEAR_FLAGS_HAS_RECT: u8 = 0x8; +// `renderer` +pub const PF_RENDERER_OPTIONS_FLAGS_HAS_BACKGROUND_COLOR: u8 = 0x1; // Types @@ -87,22 +86,19 @@ pub type PFGLRendererRef = *mut Renderer; // FIXME(pcwalton): Double-boxing is unfortunate. Remove this when `std::raw::TraitObject` is // stable? pub type PFResourceLoaderRef = *mut Box; -#[repr(C)] -pub struct PFClearParams { - pub color: PFColorF, - pub depth: f32, - pub stencil: u8, - pub rect: PFRectI, - pub flags: PFClearFlags, -} -pub type PFClearFlags = u8; // `renderer` pub type PFSceneRef = *mut Scene; pub type PFSceneProxyRef = *mut SceneProxy; +#[repr(C)] +pub struct PFRendererOptions { + pub background_color: PFColorF, + pub flags: PFRendererOptionsFlags, +} +pub type PFRendererOptionsFlags = u8; // TODO(pcwalton) #[repr(C)] -pub struct PFRenderOptions { +pub struct PFBuildOptions { pub placeholder: u32, } @@ -252,11 +248,6 @@ pub unsafe extern "C" fn PFGLDeviceDestroy(device: PFGLDeviceRef) { drop(Box::from_raw(device)) } -#[no_mangle] -pub unsafe extern "C" fn PFGLDeviceClear(device: PFGLDeviceRef, params: *const PFClearParams) { - (*device).clear(&(*params).to_rust()) -} - #[no_mangle] pub unsafe extern "C" fn PFResourceLoaderDestroy(loader: PFResourceLoaderRef) { drop(Box::from_raw(loader)) @@ -279,11 +270,13 @@ pub unsafe extern "C" fn PFGLDestFramebufferDestroy(dest_framebuffer: PFGLDestFr #[no_mangle] pub unsafe extern "C" fn PFGLRendererCreate(device: PFGLDeviceRef, resources: PFResourceLoaderRef, - dest_framebuffer: PFGLDestFramebufferRef) + dest_framebuffer: PFGLDestFramebufferRef, + options: *const PFRendererOptions) -> PFGLRendererRef { Box::into_raw(Box::new(Renderer::new(*Box::from_raw(device), &**resources, - *Box::from_raw(dest_framebuffer)))) + *Box::from_raw(dest_framebuffer), + (*options).to_rust()))) } #[no_mangle] @@ -299,8 +292,8 @@ pub unsafe extern "C" fn PFGLRendererGetDevice(renderer: PFGLRendererRef) -> PFG #[no_mangle] pub unsafe extern "C" fn PFSceneProxyBuildAndRenderGL(scene_proxy: PFSceneProxyRef, renderer: PFGLRendererRef, - options: *const PFRenderOptions) { - (*scene_proxy).build_and_render(&mut *renderer, (*options).to_rust()) + build_options: *const PFBuildOptions) { + (*scene_proxy).build_and_render(&mut *renderer, (*build_options).to_rust()) } // `renderer` @@ -358,28 +351,14 @@ impl PFVector2I { } } -// Helpers for `gpu` +// Helpers for `renderer` -impl PFClearParams { - pub fn to_rust(&self) -> ClearParams { - ClearParams { - color: if (self.flags & PF_CLEAR_FLAGS_HAS_COLOR) != 0 { - Some(self.color.to_rust()) - } else { - None - }, - rect: if (self.flags & PF_CLEAR_FLAGS_HAS_RECT) != 0 { - Some(self.rect.to_rust()) - } else { - None - }, - depth: if (self.flags & PF_CLEAR_FLAGS_HAS_DEPTH) != 0 { - Some(self.depth) - } else { - None - }, - stencil: if (self.flags & PF_CLEAR_FLAGS_HAS_STENCIL) != 0 { - Some(self.stencil) +impl PFRendererOptions { + pub fn to_rust(&self) -> RendererOptions { + let has_background_color = self.flags & PF_RENDERER_OPTIONS_FLAGS_HAS_BACKGROUND_COLOR; + RendererOptions { + background_color: if has_background_color != 0 { + Some(self.background_color.to_rust()) } else { None }, @@ -387,10 +366,8 @@ impl PFClearParams { } } -// Helpers for `renderer` - -impl PFRenderOptions { - pub fn to_rust(&self) -> RenderOptions { - RenderOptions::default() +impl PFBuildOptions { + pub fn to_rust(&self) -> BuildOptions { + BuildOptions::default() } } diff --git a/demo/common/Cargo.toml b/demo/common/Cargo.toml index 95cb3976..3d2a88cb 100644 --- a/demo/common/Cargo.toml +++ b/demo/common/Cargo.toml @@ -4,6 +4,9 @@ version = "0.1.0" edition = "2018" authors = ["Patrick Walton "] +[features] +pf-gl = [] + [dependencies] clap = "2.32" gl = "0.6" @@ -28,6 +31,9 @@ path = "../../gl" [dependencies.pathfinder_gpu] path = "../../gpu" +[dependencies.pathfinder_metal] +path = "../../metal" + [dependencies.pathfinder_renderer] path = "../../renderer" @@ -39,3 +45,6 @@ path = "../../svg" [dependencies.pathfinder_ui] path = "../../ui" + +[target.'cfg(target_os = "macos")'.dependencies] +metal = "0.14" diff --git a/demo/common/src/device.rs b/demo/common/src/device.rs index a34f7f83..1417bb0b 100644 --- a/demo/common/src/device.rs +++ b/demo/common/src/device.rs @@ -65,18 +65,17 @@ where let position_attr = device.get_vertex_attr(&ground_program.program, "Position").unwrap(); - device.bind_vertex_array(&vertex_array); - device.use_program(&ground_program.program); - device.bind_buffer(quad_vertex_positions_buffer, BufferTarget::Vertex); - device.configure_vertex_attr(&position_attr, &VertexAttrDescriptor { + device.bind_buffer(&vertex_array, quad_vertex_positions_buffer, BufferTarget::Vertex); + device.configure_vertex_attr(&vertex_array, &position_attr, &VertexAttrDescriptor { size: 2, - class: VertexAttrClass::Float, - attr_type: VertexAttrType::U8, - stride: 0, + class: VertexAttrClass::Int, + attr_type: VertexAttrType::I16, + stride: 4, offset: 0, divisor: 0, + buffer_index: 0, }); - device.bind_buffer(quad_vertex_indices_buffer, BufferTarget::Index); + device.bind_buffer(&vertex_array, quad_vertex_indices_buffer, BufferTarget::Index); GroundVertexArray { vertex_array } } diff --git a/demo/common/src/lib.rs b/demo/common/src/lib.rs index 2121a93d..76c5a964 100644 --- a/demo/common/src/lib.rs +++ b/demo/common/src/lib.rs @@ -27,12 +27,12 @@ use pathfinder_geometry::basic::rect::RectF; use pathfinder_geometry::basic::transform2d::Transform2DF; use pathfinder_geometry::basic::transform3d::Transform3DF; use pathfinder_geometry::color::ColorU; -use pathfinder_gl::GLDevice; -use pathfinder_gpu::Device; use pathfinder_gpu::resources::ResourceLoader; +use pathfinder_gpu::Device; use pathfinder_renderer::concurrent::scene_proxy::{RenderCommandStream, SceneProxy}; -use pathfinder_renderer::gpu::renderer::{DestFramebuffer, RenderStats, RenderTime, Renderer}; -use pathfinder_renderer::options::{RenderOptions, RenderTransform}; +use pathfinder_renderer::gpu::options::{DestFramebuffer, RendererOptions}; +use pathfinder_renderer::gpu::renderer::{RenderStats, RenderTime, Renderer}; +use pathfinder_renderer::options::{BuildOptions, RenderTransform}; use pathfinder_renderer::post::STEM_DARKENING_FACTORS; use pathfinder_renderer::scene::Scene; use pathfinder_svg::BuiltSVG; @@ -44,6 +44,11 @@ use std::thread; use std::time::Duration; use usvg::{Options as UsvgOptions, Tree}; +#[cfg(any(not(target_os = "macos"), feature = "pf-gl"))] +use pathfinder_gl::GLDevice as DeviceImpl; +#[cfg(all(target_os = "macos", not(feature = "pf-gl")))] +use pathfinder_metal::MetalDevice as DeviceImpl; + static DEFAULT_SVG_VIRTUAL_PATH: &'static str = "svg/Ghostscript_Tiger.svg"; const MOUSELOOK_ROTATION_SPEED: f32 = 0.007; @@ -112,22 +117,31 @@ pub struct DemoApp where W: Window { build_time: Option, ui_model: DemoUIModel, - ui_presenter: DemoUIPresenter, + ui_presenter: DemoUIPresenter, scene_proxy: SceneProxy, - renderer: Renderer, + renderer: Renderer, - scene_framebuffer: Option<::Framebuffer>, + scene_framebuffer: Option<::Framebuffer>, - ground_program: GroundProgram, - ground_vertex_array: GroundVertexArray, + ground_program: GroundProgram, + ground_vertex_array: GroundVertexArray, } impl DemoApp where W: Window { pub fn new(window: W, window_size: WindowSize, mut options: Options) -> DemoApp { let expire_message_event_id = window.create_user_event_id(); - let device = GLDevice::new(window.gl_version(), window.gl_default_framebuffer()); + let device; + #[cfg(all(target_os = "macos", not(feature = "pf-gl")))] + { + device = DeviceImpl::new(window.metal_layer()); + } + #[cfg(any(not(target_os = "macos"), feature = "pf-gl"))] + { + device = DeviceImpl::new(window.gl_version(), window.gl_default_framebuffer()); + } + let resources = window.resource_loader(); // Read command line options. @@ -144,8 +158,12 @@ impl DemoApp where W: Window { viewport, window_size: window_size.device_size(), }; + // FIXME(pcwalton) + let render_options = RendererOptions { + background_color: None, + }; - let renderer = Renderer::new(device, resources, dest_framebuffer); + let renderer = Renderer::new(device, resources, dest_framebuffer, render_options); let scene_metadata = SceneMetadata::new_clipping_view_box(&mut built_svg.scene, viewport.size()); let camera = Camera::new(options.mode, scene_metadata.view_box, viewport.size()); @@ -246,7 +264,7 @@ impl DemoApp where W: Window { Camera::TwoD(transform) => Some(RenderTransform::Transform2D(transform)), }; - let render_options = RenderOptions { + let build_options = BuildOptions { transform: self.render_transform.clone().unwrap(), dilation: if self.ui_model.stem_darkening_effect_enabled { let font_size = APPROX_FONT_SIZE * self.window_size.backing_scale_factor; @@ -258,7 +276,7 @@ impl DemoApp where W: Window { subpixel_aa_enabled: self.ui_model.subpixel_aa_effect_enabled, }; - self.render_command_stream = Some(self.scene_proxy.build_with_stream(render_options)); + self.render_command_stream = Some(self.scene_proxy.build_with_stream(build_options)); } fn handle_events(&mut self, events: Vec) -> Vec { @@ -488,7 +506,9 @@ impl DemoApp where W: Window { self.handle_ui_events(frame, &mut ui_action); - self.window.present(); + self.renderer.device.end_commands(); + + self.window.present(&mut self.renderer.device); self.frame_counter += 1; } diff --git a/demo/common/src/renderer.rs b/demo/common/src/renderer.rs index 742186c1..fb42869d 100644 --- a/demo/common/src/renderer.rs +++ b/demo/common/src/renderer.rs @@ -15,10 +15,13 @@ use crate::window::{View, Window}; use crate::{BackgroundColor, DemoApp, UIVisibility}; use image::ColorType; use pathfinder_geometry::color::{ColorF, ColorU}; -use pathfinder_gpu::{ClearParams, DepthFunc, DepthState, Device, Primitive, RenderState}; -use pathfinder_gpu::{TextureFormat, UniformData}; +use pathfinder_gpu::{ClearOps, DepthFunc, DepthState, Device, Primitive, RenderOptions}; +use pathfinder_gpu::{RenderState, RenderTarget, TextureData, TextureFormat, UniformData}; +use pathfinder_geometry::basic::rect::RectI; use pathfinder_geometry::basic::transform3d::Transform3DF; -use pathfinder_renderer::gpu::renderer::{DestFramebuffer, RenderMode}; +use pathfinder_geometry::basic::vector::Vector2I; +use pathfinder_renderer::gpu::options::{DestFramebuffer, RendererOptions}; +use pathfinder_renderer::gpu::renderer::RenderMode; use pathfinder_renderer::gpu_data::RenderCommand; use pathfinder_renderer::options::RenderTransform; use pathfinder_renderer::post::DEFRINGING_KERNEL_CORE_GRAPHICS; @@ -42,13 +45,14 @@ const GRIDLINE_COUNT: i32 = 10; impl DemoApp where W: Window { pub fn prepare_frame_rendering(&mut self) -> u32 { - // Make the GL context current. + // Make the context current. let view = self.ui_model.mode.view(0); self.window.make_current(view); // Set up framebuffers. let window_size = self.window_size.device_size(); - let scene_count = match self.camera.mode() { + let mode = self.camera.mode(); + let scene_count = match mode { Mode::VR => { let viewport = self.window.viewport(View::Stereo(0)); if self.scene_framebuffer.is_none() @@ -82,49 +86,47 @@ impl DemoApp where W: Window { } }; - // Begin drawing the scene. - self.renderer.bind_dest_framebuffer(); - // Clear to the appropriate color. - let clear_color = if scene_count == 2 { - ColorF::transparent_black() - } else { - self.background_color().to_f32() + let clear_color = match mode { + Mode::TwoD => Some(self.background_color().to_f32()), + Mode::ThreeD => None, + Mode::VR => Some(ColorF::transparent_black()), }; - self.renderer.device.clear(&ClearParams { - color: Some(clear_color), - depth: Some(1.0), - stencil: Some(0), - ..ClearParams::default() - }); + self.renderer.set_options(RendererOptions { background_color: clear_color }); scene_count } pub fn draw_scene(&mut self) { + self.renderer.device.begin_commands(); + let view = self.ui_model.mode.view(0); self.window.make_current(view); if self.camera.mode() != Mode::VR { - self.draw_environment(); + self.draw_environment(0); } + self.renderer.device.end_commands(); + self.render_vector_scene(); // Reattach default framebuffer. - if self.camera.mode() != Mode::VR { - return; + if self.camera.mode() == Mode::VR { + if let DestFramebuffer::Other(scene_framebuffer) = + self.renderer + .replace_dest_framebuffer(DestFramebuffer::Default { + viewport: self.window.viewport(View::Mono), + window_size: self.window_size.device_size(), + }) + { + self.scene_framebuffer = Some(scene_framebuffer); + } } + } - if let DestFramebuffer::Other(scene_framebuffer) = - self.renderer - .replace_dest_framebuffer(DestFramebuffer::Default { - viewport: self.window.viewport(View::Mono), - window_size: self.window_size.device_size(), - }) - { - self.scene_framebuffer = Some(scene_framebuffer); - } + pub fn begin_compositing(&mut self) { + self.renderer.device.begin_commands(); } pub fn composite_scene(&mut self, render_scene_index: u32) { @@ -151,21 +153,12 @@ impl DemoApp where W: Window { let viewport = self.window.viewport(View::Stereo(render_scene_index)); self.window.make_current(View::Stereo(render_scene_index)); - self.renderer - .replace_dest_framebuffer(DestFramebuffer::Default { - viewport, - window_size: self.window_size.device_size(), - }); - - self.renderer.bind_draw_framebuffer(); - self.renderer.device.clear(&ClearParams { - color: Some(self.background_color().to_f32()), - depth: Some(1.0), - stencil: Some(0), - rect: Some(viewport), + self.renderer.replace_dest_framebuffer(DestFramebuffer::Default { + viewport, + window_size: self.window_size.device_size(), }); - self.draw_environment(); + self.draw_environment(render_scene_index); let scene_framebuffer = self.scene_framebuffer.as_ref().unwrap(); let scene_texture = self.renderer.device.framebuffer_texture(scene_framebuffer); @@ -207,7 +200,7 @@ impl DemoApp where W: Window { } // Draws the ground, if applicable. - fn draw_environment(&self) { + fn draw_environment(&self, render_scene_index: u32) { let frame = &self.current_frame.as_ref().unwrap(); let perspective = match frame.transform { @@ -233,31 +226,35 @@ impl DemoApp where W: Window { transform = transform.post_mul(&Transform3DF::from_scale(ground_scale, 1.0, ground_scale)); - let device = &self.renderer.device; - device.bind_vertex_array(&self.ground_vertex_array.vertex_array); - device.use_program(&self.ground_program.program); - device.set_uniform( - &self.ground_program.transform_uniform, - UniformData::from_transform_3d(&transform), - ); - device.set_uniform( - &self.ground_program.ground_color_uniform, - UniformData::Vec4(GROUND_SOLID_COLOR.to_f32().0), - ); - device.set_uniform( - &self.ground_program.gridline_color_uniform, - UniformData::Vec4(GROUND_LINE_COLOR.to_f32().0), - ); - device.set_uniform(&self.ground_program.gridline_count_uniform, - UniformData::Int(GRIDLINE_COUNT)); - device.draw_elements( - Primitive::Triangles, - 6, - &RenderState { + // Don't clear the first scene after drawing it. + let clear_color = if render_scene_index == 0 { + Some(self.background_color().to_f32()) + } else { + None + }; + + self.renderer.device.draw_elements(6, &RenderState { + target: &self.renderer.draw_render_target(), + program: &self.ground_program.program, + vertex_array: &self.ground_vertex_array.vertex_array, + primitive: Primitive::Triangles, + textures: &[], + uniforms: &[ + (&self.ground_program.transform_uniform, + UniformData::from_transform_3d(&transform)), + (&self.ground_program.ground_color_uniform, + UniformData::Vec4(GROUND_SOLID_COLOR.to_f32().0)), + (&self.ground_program.gridline_color_uniform, + UniformData::Vec4(GROUND_LINE_COLOR.to_f32().0)), + (&self.ground_program.gridline_count_uniform, UniformData::Int(GRIDLINE_COUNT)), + ], + viewport: self.renderer.draw_viewport(), + options: RenderOptions { depth: Some(DepthState { func: DepthFunc::Less, write: true }), - ..RenderState::default() + clear_ops: ClearOps { color: clear_color, depth: Some(1.0), stencil: Some(0) }, + ..RenderOptions::default() }, - ); + }); } fn render_vector_scene(&mut self) { @@ -305,10 +302,11 @@ impl DemoApp where W: Window { pub fn take_raster_screenshot(&mut self, path: PathBuf) { let drawable_size = self.window_size.device_size(); - let pixels = self - .renderer - .device - .read_pixels_from_default_framebuffer(drawable_size); + let viewport = RectI::new(Vector2I::default(), drawable_size); + let pixels = match self.renderer.device.read_pixels(&RenderTarget::Default, viewport) { + TextureData::U8(pixels) => pixels, + TextureData::U16(_) => panic!("Unexpected pixel format for default framebuffer!"), + }; image::save_buffer( path, &pixels, diff --git a/demo/common/src/ui.rs b/demo/common/src/ui.rs index 0a13c3bc..270893c5 100644 --- a/demo/common/src/ui.rs +++ b/demo/common/src/ui.rs @@ -500,9 +500,7 @@ where Vector2I::new(widget_x, slider_track_y), Vector2I::new(SLIDER_WIDTH, SLIDER_TRACK_HEIGHT), ); - debug_ui_presenter - .ui_presenter - .draw_rect_outline(device, slider_track_rect, TEXT_COLOR); + debug_ui_presenter.ui_presenter.draw_rect_outline(device, slider_track_rect, TEXT_COLOR); let slider_knob_x = widget_x + model.rotation - SLIDER_KNOB_WIDTH / 2; let slider_knob_rect = RectI::new( @@ -528,7 +526,11 @@ where let widget_origin = panel_position + Vector2I::new(0, widget_size.y() * index); let widget_rect = RectI::new(widget_origin, widget_size); - if self.draw_menu_item(device, debug_ui_presenter, &text, widget_rect, false) { + if self.draw_menu_item(device, + debug_ui_presenter, + &text, + widget_rect, + false) { // FIXME(pcwalton): This is not sufficient for Android, where we will need to take in // the contents of the file. if let Ok(path) = window.run_save_dialog(screenshot_type.extension()) { @@ -554,7 +556,11 @@ where let widget_rect = RectI::new(widget_origin, widget_size); let selected = color == model.background_color; - if self.draw_menu_item(device, debug_ui_presenter, text, widget_rect, selected) { + if self.draw_menu_item(device, + debug_ui_presenter, + text, + widget_rect, + selected) { model.background_color = color; *action = UIAction::ModelChanged; } diff --git a/demo/common/src/window.rs b/demo/common/src/window.rs index 6ca9852c..d8fc0019 100644 --- a/demo/common/src/window.rs +++ b/demo/common/src/window.rs @@ -10,24 +10,38 @@ //! A minimal cross-platform windowing layer. -use gl::types::GLuint; use pathfinder_geometry::basic::vector::Vector2I; use pathfinder_geometry::basic::rect::RectI; use pathfinder_geometry::basic::transform3d::{Perspective, Transform3DF}; -use pathfinder_gl::GLVersion; use pathfinder_gpu::resources::ResourceLoader; use rayon::ThreadPoolBuilder; use std::path::PathBuf; -pub trait Window { - fn gl_version(&self) -> GLVersion; - fn gl_default_framebuffer(&self) -> GLuint { - 0 - } +#[cfg(all(target_os = "macos", not(feature = "pf-gl")))] +use metal::CoreAnimationLayerRef; +#[cfg(all(target_os = "macos", not(feature = "pf-gl")))] +use pathfinder_metal::MetalDevice; + +#[cfg(any(not(target_os = "macos"), feature = "pf-gl"))] +use gl::types::GLuint; +#[cfg(any(not(target_os = "macos"), feature = "pf-gl"))] +use pathfinder_gl::{GLDevice, GLVersion}; + +pub trait Window { + #[cfg(any(not(target_os = "macos"), feature = "pf-gl"))] + fn gl_version(&self) -> GLVersion; + #[cfg(any(not(target_os = "macos"), feature = "pf-gl"))] + fn gl_default_framebuffer(&self) -> GLuint { 0 } + #[cfg(any(not(target_os = "macos"), feature = "pf-gl"))] + fn present(&mut self, device: &mut GLDevice); + + #[cfg(all(target_os = "macos", not(feature = "pf-gl")))] + fn metal_layer(&self) -> &CoreAnimationLayerRef; + #[cfg(all(target_os = "macos", not(feature = "pf-gl")))] + fn present(&mut self, device: &mut MetalDevice); - fn viewport(&self, view: View) -> RectI; fn make_current(&mut self, view: View); - fn present(&mut self); + fn viewport(&self, view: View) -> RectI; fn resource_loader(&self) -> &dyn ResourceLoader; fn create_user_event_id(&self) -> u32; fn push_user_event(message_type: u32, message_data: u32); diff --git a/demo/magicleap/src/lib.rs b/demo/magicleap/src/lib.rs index 8238b068..632023c0 100644 --- a/demo/magicleap/src/lib.rs +++ b/demo/magicleap/src/lib.rs @@ -113,6 +113,7 @@ pub unsafe extern "C" fn magicleap_pathfinder_demo_run(app: *mut c_void) { } let scene_count = app.demo.prepare_frame(events); app.demo.draw_scene(); + app.demo.begin_compositing(); for scene_index in 0..scene_count { app.demo.composite_scene(scene_index); } diff --git a/demo/native/Cargo.toml b/demo/native/Cargo.toml index 5e4468de..12515c04 100644 --- a/demo/native/Cargo.toml +++ b/demo/native/Cargo.toml @@ -5,6 +5,7 @@ edition = "2018" authors = ["Patrick Walton "] [features] +pf-gl = ["pathfinder_demo/pf-gl"] pf-no-simd = ["pathfinder_simd/pf-no-simd"] [dependencies] @@ -27,8 +28,15 @@ path = "../../gl" [dependencies.pathfinder_gpu] path = "../../gpu" +[dependencies.pathfinder_metal] +path = "../../metal" + [dependencies.pathfinder_simd] path = "../../simd" +[target.'cfg(target_os = "macos")'.dependencies] +foreign-types = "0.3" +metal = "0.14" + [target.'cfg(not(windows))'.dependencies] jemallocator = "0.1" diff --git a/demo/native/src/main.rs b/demo/native/src/main.rs index ad166dae..78636e4c 100644 --- a/demo/native/src/main.rs +++ b/demo/native/src/main.rs @@ -15,16 +15,33 @@ use pathfinder_demo::window::{Event, Keycode, SVGPath, View, Window, WindowSize} use pathfinder_demo::{DemoApp, Options}; use pathfinder_geometry::basic::vector::Vector2I; use pathfinder_geometry::basic::rect::RectI; -use pathfinder_gl::GLVersion; use pathfinder_gpu::resources::{FilesystemResourceLoader, ResourceLoader}; use sdl2::event::{Event as SDLEvent, WindowEvent}; use sdl2::keyboard::Keycode as SDLKeycode; -use sdl2::video::{GLContext, GLProfile, Window as SDLWindow}; +use sdl2::video::Window as SDLWindow; use sdl2::{EventPump, EventSubsystem, Sdl, VideoSubsystem}; use sdl2_sys::{SDL_Event, SDL_UserEvent}; use std::path::PathBuf; use std::ptr; +#[cfg(all(target_os = "macos", not(feature = "pf-gl")))] +use foreign_types::ForeignTypeRef; +#[cfg(all(target_os = "macos", not(feature = "pf-gl")))] +use metal::{CAMetalLayer, CoreAnimationLayerRef}; +#[cfg(all(target_os = "macos", not(feature = "pf-gl")))] +use pathfinder_metal::MetalDevice; +#[cfg(all(target_os = "macos", not(feature = "pf-gl")))] +use sdl2::hint; +#[cfg(all(target_os = "macos", not(feature = "pf-gl")))] +use sdl2::render::Canvas; +#[cfg(all(target_os = "macos", not(feature = "pf-gl")))] +use sdl2_sys::SDL_RenderGetMetalLayer; + +#[cfg(any(not(target_os = "macos"), feature = "pf-gl"))] +use pathfinder_gl::{GLDevice, GLVersion}; +#[cfg(any(not(target_os = "macos"), feature = "pf-gl"))] +use sdl2::video::{GLContext, GLProfile}; + #[cfg(not(windows))] use jemallocator; @@ -55,6 +72,7 @@ fn main() { let scene_count = app.prepare_frame(events); app.draw_scene(); + app.begin_compositing(); for scene_index in 0..scene_count { app.composite_scene(scene_index); } @@ -69,22 +87,36 @@ thread_local! { } struct WindowImpl { + #[cfg(any(not(target_os = "macos"), feature = "pf-gl"))] window: SDLWindow, + #[cfg(any(not(target_os = "macos"), feature = "pf-gl"))] + gl_context: GLContext, + + #[cfg(all(target_os = "macos", not(feature = "pf-gl")))] + canvas: Canvas, + #[cfg(all(target_os = "macos", not(feature = "pf-gl")))] + metal_layer: *mut CAMetalLayer, + event_pump: EventPump, #[allow(dead_code)] - gl_context: GLContext, resource_loader: FilesystemResourceLoader, selected_file: Option, open_svg_message_type: u32, } impl Window for WindowImpl { + #[cfg(any(not(target_os = "macos"), feature = "pf-gl"))] fn gl_version(&self) -> GLVersion { GLVersion::GL3 } + #[cfg(all(target_os = "macos", not(feature = "pf-gl")))] + fn metal_layer(&self) -> &CoreAnimationLayerRef { + unsafe { CoreAnimationLayerRef::from_ptr(self.metal_layer) } + } + fn viewport(&self, view: View) -> RectI { - let (width, height) = self.window.drawable_size(); + let (width, height) = self.window().drawable_size(); let mut width = width as i32; let height = height as i32; let mut x_offset = 0; @@ -95,12 +127,22 @@ impl Window for WindowImpl { RectI::new(Vector2I::new(x_offset, 0), Vector2I::new(width, height)) } + #[cfg(any(not(target_os = "macos"), feature = "pf-gl"))] fn make_current(&mut self, _view: View) { - self.window.gl_make_current(&self.gl_context).unwrap(); + self.window().gl_make_current(&self.gl_context).unwrap(); } - fn present(&mut self) { - self.window.gl_swap_window(); + #[cfg(all(target_os = "macos", not(feature = "pf-gl")))] + fn make_current(&mut self, _: View) {} + + #[cfg(any(not(target_os = "macos"), feature = "pf-gl"))] + fn present(&mut self, _: &mut GLDevice) { + self.window().gl_swap_window(); + } + + #[cfg(all(target_os = "macos", not(feature = "pf-gl")))] + fn present(&mut self, device: &mut MetalDevice) { + device.present_drawable(); } fn resource_loader(&self) -> &dyn ResourceLoader { @@ -141,6 +183,7 @@ impl Window for WindowImpl { } impl WindowImpl { + #[cfg(any(not(target_os = "macos"), feature = "pf-gl"))] fn new() -> WindowImpl { SDL_VIDEO.with(|sdl_video| { SDL_EVENT.with(|sdl_event| { @@ -185,9 +228,55 @@ impl WindowImpl { }) } + #[cfg(all(target_os = "macos", not(feature = "pf-gl")))] + fn new() -> WindowImpl { + assert!(hint::set("SDL_RENDER_DRIVER", "metal")); + + SDL_VIDEO.with(|sdl_video| { + SDL_EVENT.with(|sdl_event| { + let window = sdl_video + .window( + "Pathfinder Demo", + DEFAULT_WINDOW_WIDTH, + DEFAULT_WINDOW_HEIGHT, + ) + .opengl() + .resizable() + .allow_highdpi() + .build() + .unwrap(); + + let canvas = window.into_canvas().present_vsync().build().unwrap(); + let metal_layer = unsafe { + SDL_RenderGetMetalLayer(canvas.raw()) as *mut CAMetalLayer + }; + + let event_pump = SDL_CONTEXT.with(|sdl_context| sdl_context.event_pump().unwrap()); + + let resource_loader = FilesystemResourceLoader::locate(); + + let open_svg_message_type = unsafe { sdl_event.register_event().unwrap() }; + + WindowImpl { + event_pump, + canvas, + metal_layer, + resource_loader, + open_svg_message_type, + selected_file: None, + } + }) + }) + } + + #[cfg(any(not(target_os = "macos"), feature = "pf-gl"))] + fn window(&self) -> &SDLWindow { &self.window } + #[cfg(all(target_os = "macos", not(feature = "pf-gl")))] + fn window(&self) -> &SDLWindow { self.canvas.window() } + fn size(&self) -> WindowSize { - let (logical_width, logical_height) = self.window.size(); - let (drawable_width, _) = self.window.drawable_size(); + let (logical_width, logical_height) = self.window().size(); + let (drawable_width, _) = self.window().drawable_size(); WindowSize { logical_size: Vector2I::new(logical_width as i32, logical_height as i32), backing_scale_factor: drawable_width as f32 / logical_width as f32, diff --git a/examples/c_canvas_minimal/c_canvas_minimal.c b/examples/c_canvas_minimal/c_canvas_minimal.c index 9e773b02..9721ee3f 100644 --- a/examples/c_canvas_minimal/c_canvas_minimal.c +++ b/examples/c_canvas_minimal/c_canvas_minimal.c @@ -58,11 +58,9 @@ int main(int argc, const char **argv) { PFGLDestFramebufferCreateFullWindow(&(PFVector2I){640, 480}); PFGLRendererRef renderer = PFGLRendererCreate(PFGLDeviceCreate(PF_GL_VERSION_GL3, 0), PFFilesystemResourceLoaderLocate(), - dest_framebuffer); - - // Clear to white. - PFGLDeviceClear(PFGLRendererGetDevice(renderer), &(PFClearParams){ - (PFColorF){1.0, 1.0, 1.0, 1.0}, 0.0, 0, {0}, PF_CLEAR_FLAGS_HAS_COLOR + dest_framebuffer, + &(PFRendererOptions){ + (PFColorF){1.0, 1.0, 1.0, 1.0}, PF_RENDERER_OPTIONS_FLAGS_HAS_BACKGROUND_COLOR }); // Make a canvas. We're going to draw a house. @@ -89,7 +87,7 @@ int main(int argc, const char **argv) { // Render the canvas to screen. PFSceneRef scene = PFCanvasCreateScene(canvas); PFSceneProxyRef scene_proxy = PFSceneProxyCreateFromSceneAndRayonExecutor(scene); - PFSceneProxyBuildAndRenderGL(scene_proxy, renderer, &(PFRenderOptions){0}); + PFSceneProxyBuildAndRenderGL(scene_proxy, renderer, &(PFBuildOptions){0}); SDL_GL_SwapWindow(window); // Wait for a keypress. diff --git a/examples/canvas_glutin_minimal/src/main.rs b/examples/canvas_glutin_minimal/src/main.rs index ce9360f4..b73a0fdb 100644 --- a/examples/canvas_glutin_minimal/src/main.rs +++ b/examples/canvas_glutin_minimal/src/main.rs @@ -12,18 +12,18 @@ use glutin::dpi::PhysicalSize; use glutin::{ContextBuilder, ControlFlow, Event, EventsLoop, GlProfile, GlRequest, KeyboardInput}; -use glutin::{VirtualKeyCode, WindowBuilder, WindowEvent}; +use glutin::{VirtualKeyCode, WindowBuilder, WindowEvent}; use pathfinder_canvas::{CanvasFontContext, CanvasRenderingContext2D, Path2D}; use pathfinder_geometry::basic::vector::{Vector2F, Vector2I}; use pathfinder_geometry::basic::rect::RectF; use pathfinder_geometry::color::ColorF; use pathfinder_gl::{GLDevice, GLVersion}; use pathfinder_gpu::resources::FilesystemResourceLoader; -use pathfinder_gpu::{ClearParams, Device}; use pathfinder_renderer::concurrent::rayon::RayonExecutor; use pathfinder_renderer::concurrent::scene_proxy::SceneProxy; -use pathfinder_renderer::gpu::renderer::{DestFramebuffer, Renderer}; -use pathfinder_renderer::options::RenderOptions; +use pathfinder_renderer::gpu::renderer::Renderer; +use pathfinder_renderer::gpu::options::{DestFramebuffer, RendererOptions}; +use pathfinder_renderer::options::BuildOptions; fn main() { // Calculate the right logical size of the window. @@ -50,10 +50,8 @@ fn main() { // Create a Pathfinder renderer. let mut renderer = Renderer::new(GLDevice::new(GLVersion::GL3, 0), &FilesystemResourceLoader::locate(), - DestFramebuffer::full_window(window_size)); - - // Clear to white. - renderer.device.clear(&ClearParams { color: Some(ColorF::white()), ..ClearParams::default() }); + DestFramebuffer::full_window(window_size), + RendererOptions { background_color: Some(ColorF::white()) }); // Make a canvas. We're going to draw a house. let mut canvas = CanvasRenderingContext2D::new(CanvasFontContext::new(), window_size.to_f32()); @@ -77,7 +75,7 @@ fn main() { // Render the canvas to screen. let scene = SceneProxy::from_scene(canvas.into_scene(), RayonExecutor); - scene.build_and_render(&mut renderer, RenderOptions::default()); + scene.build_and_render(&mut renderer, BuildOptions::default()); gl_context.swap_buffers().unwrap(); // Wait for a keypress. diff --git a/examples/canvas_metal_minimal/Cargo.toml b/examples/canvas_metal_minimal/Cargo.toml new file mode 100644 index 00000000..41673409 --- /dev/null +++ b/examples/canvas_metal_minimal/Cargo.toml @@ -0,0 +1,31 @@ +[package] +name = "canvas_metal_minimal" +version = "0.1.0" +authors = ["Patrick Walton "] +edition = "2018" + +[dependencies] +foreign-types = "0.3" +gl = "0.6" +metal = "0.14" +objc = "0.2" +sdl2 = "0.32" +sdl2-sys = "0.32" + +[dependencies.pathfinder_canvas] +path = "../../canvas" + +[dependencies.pathfinder_geometry] +path = "../../geometry" + +[dependencies.pathfinder_gl] +path = "../../gl" + +[dependencies.pathfinder_gpu] +path = "../../gpu" + +[dependencies.pathfinder_metal] +path = "../../metal" + +[dependencies.pathfinder_renderer] +path = "../../renderer" diff --git a/examples/canvas_metal_minimal/src/main.rs b/examples/canvas_metal_minimal/src/main.rs new file mode 100644 index 00000000..043b9d5d --- /dev/null +++ b/examples/canvas_metal_minimal/src/main.rs @@ -0,0 +1,87 @@ +// pathfinder/examples/canvas_metal_minimal/src/main.rs +// +// Copyright © 2019 The Pathfinder Project Developers. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use foreign_types::ForeignTypeRef; +use metal::{CAMetalLayer, CoreAnimationLayerRef}; +use pathfinder_canvas::{CanvasFontContext, CanvasRenderingContext2D, Path2D}; +use pathfinder_geometry::basic::vector::{Vector2F, Vector2I}; +use pathfinder_geometry::basic::rect::RectF; +use pathfinder_geometry::color::ColorF; +use pathfinder_gpu::resources::FilesystemResourceLoader; +use pathfinder_metal::MetalDevice; +use pathfinder_renderer::concurrent::rayon::RayonExecutor; +use pathfinder_renderer::concurrent::scene_proxy::SceneProxy; +use pathfinder_renderer::gpu::options::{DestFramebuffer, RendererOptions}; +use pathfinder_renderer::gpu::renderer::Renderer; +use pathfinder_renderer::options::BuildOptions; +use sdl2::event::Event; +use sdl2::hint; +use sdl2::keyboard::Keycode; +use sdl2_sys::SDL_RenderGetMetalLayer; + +fn main() { + // Set up SDL2. + assert!(hint::set("SDL_RENDER_DRIVER", "metal")); + let sdl_context = sdl2::init().unwrap(); + let video = sdl_context.video().unwrap(); + + // Open a window. + let window_size = Vector2I::new(640, 480); + let window = video.window("Minimal example", window_size.x() as u32, window_size.y() as u32) + .opengl() + .build() + .unwrap(); + + // Create a Metal context. + let canvas = window.into_canvas().present_vsync().build().unwrap(); + let metal_layer = unsafe { + CoreAnimationLayerRef::from_ptr(SDL_RenderGetMetalLayer(canvas.raw()) as *mut CAMetalLayer) + }; + + // Create a Pathfinder renderer. + let mut renderer = Renderer::new(MetalDevice::new(metal_layer), + &FilesystemResourceLoader::locate(), + DestFramebuffer::full_window(window_size), + RendererOptions { background_color: Some(ColorF::white()) }); + + // Make a canvas. We're going to draw a house. + let mut canvas = CanvasRenderingContext2D::new(CanvasFontContext::new(), window_size.to_f32()); + + // Set line width. + canvas.set_line_width(10.0); + + // Draw walls. + canvas.stroke_rect(RectF::new(Vector2F::new(75.0, 140.0), Vector2F::new(150.0, 110.0))); + + // Draw door. + canvas.fill_rect(RectF::new(Vector2F::new(130.0, 190.0), Vector2F::new(40.0, 60.0))); + + // Draw roof. + let mut path = Path2D::new(); + path.move_to(Vector2F::new(50.0, 140.0)); + path.line_to(Vector2F::new(150.0, 60.0)); + path.line_to(Vector2F::new(250.0, 140.0)); + path.close_path(); + canvas.stroke_path(path); + + // Render the canvas to screen. + let scene = SceneProxy::from_scene(canvas.into_scene(), RayonExecutor); + scene.build_and_render(&mut renderer, BuildOptions::default()); + renderer.device.present_drawable(); + + // Wait for a keypress. + let mut event_pump = sdl_context.event_pump().unwrap(); + loop { + match event_pump.wait_event() { + Event::Quit {..} | Event::KeyDown { keycode: Some(Keycode::Escape), .. } => return, + _ => {} + } + } +} diff --git a/examples/canvas_minimal/src/main.rs b/examples/canvas_minimal/src/main.rs index 07588dcc..06fc1a7e 100644 --- a/examples/canvas_minimal/src/main.rs +++ b/examples/canvas_minimal/src/main.rs @@ -14,11 +14,11 @@ use pathfinder_geometry::basic::rect::RectF; use pathfinder_geometry::color::ColorF; use pathfinder_gl::{GLDevice, GLVersion}; use pathfinder_gpu::resources::FilesystemResourceLoader; -use pathfinder_gpu::{ClearParams, Device}; use pathfinder_renderer::concurrent::rayon::RayonExecutor; use pathfinder_renderer::concurrent::scene_proxy::SceneProxy; -use pathfinder_renderer::gpu::renderer::{DestFramebuffer, Renderer}; -use pathfinder_renderer::options::RenderOptions; +use pathfinder_renderer::gpu::options::{DestFramebuffer, RendererOptions}; +use pathfinder_renderer::gpu::renderer::Renderer; +use pathfinder_renderer::options::BuildOptions; use sdl2::event::Event; use sdl2::keyboard::Keycode; use sdl2::video::GLProfile; @@ -48,10 +48,8 @@ fn main() { // Create a Pathfinder renderer. let mut renderer = Renderer::new(GLDevice::new(GLVersion::GL3, 0), &FilesystemResourceLoader::locate(), - DestFramebuffer::full_window(window_size)); - - // Clear to white. - renderer.device.clear(&ClearParams { color: Some(ColorF::white()), ..ClearParams::default() }); + DestFramebuffer::full_window(window_size), + RendererOptions { background_color: Some(ColorF::white()) }); // Make a canvas. We're going to draw a house. let mut canvas = CanvasRenderingContext2D::new(CanvasFontContext::new(), window_size.to_f32()); @@ -75,7 +73,7 @@ fn main() { // Render the canvas to screen. let scene = SceneProxy::from_scene(canvas.into_scene(), RayonExecutor); - scene.build_and_render(&mut renderer, RenderOptions::default()); + scene.build_and_render(&mut renderer, BuildOptions::default()); window.gl_swap_window(); // Wait for a keypress. diff --git a/examples/canvas_moire/src/main.rs b/examples/canvas_moire/src/main.rs index 7a55404e..0ac8fffd 100644 --- a/examples/canvas_moire/src/main.rs +++ b/examples/canvas_moire/src/main.rs @@ -13,11 +13,11 @@ use pathfinder_geometry::basic::vector::{Vector2F, Vector2I}; use pathfinder_geometry::color::{ColorF, ColorU}; use pathfinder_gl::{GLDevice, GLVersion}; use pathfinder_gpu::resources::FilesystemResourceLoader; -use pathfinder_gpu::{ClearParams, Device}; use pathfinder_renderer::concurrent::rayon::RayonExecutor; use pathfinder_renderer::concurrent::scene_proxy::SceneProxy; -use pathfinder_renderer::gpu::renderer::{DestFramebuffer, Renderer}; -use pathfinder_renderer::options::RenderOptions; +use pathfinder_renderer::gpu::options::{DestFramebuffer, RendererOptions}; +use pathfinder_renderer::gpu::renderer::Renderer; +use pathfinder_renderer::options::BuildOptions; use sdl2::event::Event; use sdl2::keyboard::Keycode; use sdl2::video::GLProfile; @@ -67,7 +67,8 @@ fn main() { // Create our renderers. let renderer = Renderer::new(GLDevice::new(GLVersion::GL3, 0), &FilesystemResourceLoader::locate(), - DestFramebuffer::full_window(drawable_size)); + DestFramebuffer::full_window(drawable_size), + RendererOptions { background_color: Some(ColorF::white()) }); let mut moire_renderer = MoireRenderer::new(renderer, window_size, drawable_size); // Enter main render loop. @@ -124,10 +125,7 @@ impl MoireRenderer { Vector2F::new(1.0, sin_time).scale(cos_time * INNER_RADIUS); // Clear to background color. - self.renderer.device.clear(&ClearParams { - color: Some(background_color), - ..ClearParams::default() - }); + self.renderer.set_options(RendererOptions { background_color: Some(background_color) }); // Make a canvas. let mut canvas = CanvasRenderingContext2D::new(self.font_context.clone(), @@ -142,7 +140,7 @@ impl MoireRenderer { // Build and render scene. self.scene.replace_scene(canvas.into_scene()); - self.scene.build_and_render(&mut self.renderer, RenderOptions::default()); + self.scene.build_and_render(&mut self.renderer, BuildOptions::default()); self.frame += 1; } diff --git a/examples/canvas_text/src/main.rs b/examples/canvas_text/src/main.rs index 0829723e..de69fbe4 100644 --- a/examples/canvas_text/src/main.rs +++ b/examples/canvas_text/src/main.rs @@ -13,11 +13,11 @@ use pathfinder_geometry::basic::vector::{Vector2F, Vector2I}; use pathfinder_geometry::color::ColorF; use pathfinder_gl::{GLDevice, GLVersion}; use pathfinder_gpu::resources::FilesystemResourceLoader; -use pathfinder_gpu::{ClearParams, Device}; use pathfinder_renderer::concurrent::rayon::RayonExecutor; use pathfinder_renderer::concurrent::scene_proxy::SceneProxy; -use pathfinder_renderer::gpu::renderer::{DestFramebuffer, Renderer}; -use pathfinder_renderer::options::RenderOptions; +use pathfinder_renderer::gpu::options::{DestFramebuffer, RendererOptions}; +use pathfinder_renderer::gpu::renderer::Renderer; +use pathfinder_renderer::options::BuildOptions; use sdl2::event::Event; use sdl2::keyboard::Keycode; use sdl2::video::GLProfile; @@ -47,10 +47,8 @@ fn main() { // Create a Pathfinder renderer. let mut renderer = Renderer::new(GLDevice::new(GLVersion::GL3, 0), &FilesystemResourceLoader::locate(), - DestFramebuffer::full_window(window_size)); - - // Clear to white. - renderer.device.clear(&ClearParams { color: Some(ColorF::white()), ..ClearParams::default() }); + DestFramebuffer::full_window(window_size), + RendererOptions { background_color: Some(ColorF::white()) }); // Make a canvas. We're going to draw some text. let mut canvas = CanvasRenderingContext2D::new(CanvasFontContext::new(), window_size.to_f32()); @@ -63,7 +61,7 @@ fn main() { // Render the canvas to screen. let scene = SceneProxy::from_scene(canvas.into_scene(), RayonExecutor); - scene.build_and_render(&mut renderer, RenderOptions::default()); + scene.build_and_render(&mut renderer, BuildOptions::default()); window.gl_swap_window(); // Wait for a keypress. diff --git a/geometry/src/color.rs b/geometry/src/color.rs index cde14be6..5f3676be 100644 --- a/geometry/src/color.rs +++ b/geometry/src/color.rs @@ -75,13 +75,18 @@ impl Debug for ColorU { } } -#[derive(Clone, Copy)] +#[derive(Clone, Copy, Default)] pub struct ColorF(pub F32x4); impl ColorF { + #[inline] + pub fn new(r: f32, g: f32, b: f32, a: f32) -> ColorF { + ColorF(F32x4::new(r, g, b, a)) + } + #[inline] pub fn transparent_black() -> ColorF { - ColorF(F32x4::default()) + ColorF::default() } #[inline] @@ -120,3 +125,16 @@ impl ColorF { self.0[3] } } + +impl Debug for ColorF { + fn fmt(&self, formatter: &mut Formatter) -> fmt::Result { + write!( + formatter, + "rgba({}, {}, {}, {})", + self.r() * 255.0, + self.g() * 255.0, + self.b() * 255.0, + self.a() + ) + } +} diff --git a/gl/src/lib.rs b/gl/src/lib.rs index aa08233a..f53faeaf 100644 --- a/gl/src/lib.rs +++ b/gl/src/lib.rs @@ -14,13 +14,13 @@ extern crate log; use gl::types::{GLboolean, GLchar, GLenum, GLfloat, GLint, GLsizei, GLsizeiptr, GLuint, GLvoid}; -use pathfinder_geometry::basic::vector::Vector2I; use pathfinder_geometry::basic::rect::RectI; +use pathfinder_geometry::basic::vector::Vector2I; use pathfinder_gpu::resources::ResourceLoader; -use pathfinder_gpu::{BlendState, BufferData, BufferTarget, BufferUploadMode, ClearParams}; -use pathfinder_gpu::{DepthFunc, Device, Primitive, RenderState, ShaderKind, StencilFunc}; -use pathfinder_gpu::{TextureFormat, UniformData, VertexAttrClass}; -use pathfinder_gpu::{VertexAttrDescriptor, VertexAttrType}; +use pathfinder_gpu::{RenderTarget, BlendState, BufferData, BufferTarget, BufferUploadMode}; +use pathfinder_gpu::{ClearOps, DepthFunc, Device, Primitive, RenderOptions, RenderState}; +use pathfinder_gpu::{ShaderKind, StencilFunc, TextureData, TextureFormat, UniformData}; +use pathfinder_gpu::{VertexAttrClass, VertexAttrDescriptor, VertexAttrType}; use pathfinder_simd::default::F32x4; use std::ffi::CString; use std::mem; @@ -60,10 +60,32 @@ impl GLDevice { } } - fn set_render_state(&self, render_state: &RenderState) { + fn set_render_state(&self, render_state: &RenderState) { + self.bind_render_target(render_state.target); + + unsafe { + let (origin, size) = (render_state.viewport.origin(), render_state.viewport.size()); + gl::Viewport(origin.x(), origin.y(), size.x(), size.y()); + } + + if render_state.options.clear_ops.has_ops() { + self.clear(&render_state.options.clear_ops); + } + + self.use_program(render_state.program); + self.bind_vertex_array(render_state.vertex_array); + for (texture_unit, texture) in render_state.textures.iter().enumerate() { + self.bind_texture(texture, texture_unit as u32); + } + + render_state.uniforms.iter().for_each(|(uniform, data)| self.set_uniform(uniform, data)); + self.set_render_options(&render_state.options); + } + + fn set_render_options(&self, render_options: &RenderOptions) { unsafe { // Set blend. - match render_state.blend { + match render_options.blend { BlendState::Off => { gl::Disable(gl::BLEND); ck(); } @@ -91,7 +113,7 @@ impl GLDevice { } // Set depth. - match render_state.depth { + match render_options.depth { None => { gl::Disable(gl::DEPTH_TEST); ck(); } @@ -103,7 +125,7 @@ impl GLDevice { } // Set stencil. - match render_state.stencil { + match render_options.stencil { None => { gl::Disable(gl::STENCIL_TEST); ck(); } @@ -123,14 +145,50 @@ impl GLDevice { } // Set color mask. - let color_mask = render_state.color_mask as GLboolean; + let color_mask = render_options.color_mask as GLboolean; gl::ColorMask(color_mask, color_mask, color_mask, color_mask); ck(); } } - fn reset_render_state(&self, render_state: &RenderState) { + fn set_uniform(&self, uniform: &GLUniform, data: &UniformData) { unsafe { - match render_state.blend { + match *data { + UniformData::Int(value) => { + gl::Uniform1i(uniform.location, value); ck(); + } + UniformData::Mat4(data) => { + assert_eq!(mem::size_of::<[F32x4; 4]>(), 4 * 4 * 4); + let data_ptr: *const F32x4 = data.as_ptr(); + gl::UniformMatrix4fv(uniform.location, + 1, + gl::FALSE, + data_ptr as *const GLfloat); + } + UniformData::Vec2(data) => { + gl::Uniform2f(uniform.location, data.x(), data.y()); ck(); + } + UniformData::Vec4(data) => { + gl::Uniform4f(uniform.location, data.x(), data.y(), data.z(), data.w()); ck(); + } + UniformData::TextureUnit(unit) => { + gl::Uniform1i(uniform.location, unit as GLint); ck(); + } + } + } + } + + fn reset_render_state(&self, render_state: &RenderState) { + self.reset_render_options(&render_state.options); + for texture_unit in 0..(render_state.textures.len() as u32) { + self.unbind_texture(texture_unit); + } + self.unuse_program(); + self.unbind_vertex_array(); + } + + fn reset_render_options(&self, render_options: &RenderOptions) { + unsafe { + match render_options.blend { BlendState::Off => {} BlendState::RGBOneAlphaOneMinusSrcAlpha | BlendState::RGBOneAlphaOne | @@ -139,11 +197,11 @@ impl GLDevice { } } - if render_state.depth.is_some() { + if render_options.depth.is_some() { gl::Disable(gl::DEPTH_TEST); ck(); } - if render_state.stencil.is_some() { + if render_options.stencil.is_some() { gl::StencilMask(!0); ck(); gl::Disable(gl::STENCIL_TEST); ck(); } @@ -165,37 +223,18 @@ impl Device for GLDevice { type VertexAttr = GLVertexAttr; fn create_texture(&self, format: TextureFormat, size: Vector2I) -> GLTexture { - let (gl_internal_format, gl_format, gl_type); - match format { - TextureFormat::R8 => { - gl_internal_format = gl::R8 as GLint; - gl_format = gl::RED; - gl_type = gl::UNSIGNED_BYTE; - } - TextureFormat::R16F => { - gl_internal_format = gl::R16F as GLint; - gl_format = gl::RED; - gl_type = gl::HALF_FLOAT; - } - TextureFormat::RGBA8 => { - gl_internal_format = gl::RGBA as GLint; - gl_format = gl::RGBA; - gl_type = gl::UNSIGNED_BYTE; - } - } - - let mut texture = GLTexture { gl_texture: 0, size }; + let mut texture = GLTexture { gl_texture: 0, size, format }; unsafe { gl::GenTextures(1, &mut texture.gl_texture); ck(); self.bind_texture(&texture, 0); gl::TexImage2D(gl::TEXTURE_2D, 0, - gl_internal_format, + format.gl_internal_format(), size.x() as GLsizei, size.y() as GLsizei, 0, - gl_format, - gl_type, + format.gl_format(), + format.gl_type(), ptr::null()); ck(); } @@ -206,7 +245,7 @@ impl Device for GLDevice { fn create_texture_from_data(&self, size: Vector2I, data: &[u8]) -> GLTexture { assert!(data.len() >= size.x() as usize * size.y() as usize); - let mut texture = GLTexture { gl_texture: 0, size }; + let mut texture = GLTexture { gl_texture: 0, size, format: TextureFormat::R8 }; unsafe { gl::GenTextures(1, &mut texture.gl_texture); ck(); self.bind_texture(&texture, 0); @@ -324,13 +363,14 @@ impl Device for GLDevice { GLUniform { location } } - fn use_program(&self, program: &Self::Program) { - unsafe { - gl::UseProgram(program.gl_program); ck(); - } - } + fn configure_vertex_attr(&self, + vertex_array: &GLVertexArray, + attr: &GLVertexAttr, + descriptor: &VertexAttrDescriptor) { + debug_assert_ne!(descriptor.stride, 0); + + self.bind_vertex_array(vertex_array); - fn configure_vertex_attr(&self, attr: &GLVertexAttr, descriptor: &VertexAttrDescriptor) { unsafe { let attr_type = descriptor.attr_type.to_gl_type(); match descriptor.class { @@ -359,41 +399,8 @@ impl Device for GLDevice { gl::VertexAttribDivisor(attr.attr, descriptor.divisor); ck(); gl::EnableVertexAttribArray(attr.attr); ck(); } - } - fn set_uniform(&self, uniform: &Self::Uniform, data: UniformData) { - unsafe { - match data { - UniformData::Int(value) => { - gl::Uniform1i(uniform.location, value); ck(); - } - UniformData::Mat2(data) => { - assert_eq!(mem::size_of::(), 4 * 4); - let data_ptr: *const F32x4 = &data; - gl::UniformMatrix2fv(uniform.location, - 1, - gl::FALSE, - data_ptr as *const GLfloat); - } - UniformData::Mat4(data) => { - assert_eq!(mem::size_of::<[F32x4; 4]>(), 4 * 4 * 4); - let data_ptr: *const F32x4 = data.as_ptr(); - gl::UniformMatrix4fv(uniform.location, - 1, - gl::FALSE, - data_ptr as *const GLfloat); - } - UniformData::Vec2(data) => { - gl::Uniform2f(uniform.location, data.x(), data.y()); ck(); - } - UniformData::Vec4(data) => { - gl::Uniform4f(uniform.location, data.x(), data.y(), data.z(), data.w()); ck(); - } - UniformData::TextureUnit(unit) => { - gl::Uniform1i(uniform.location, unit as GLint); ck(); - } - } - } + self.unbind_vertex_array(); } fn create_framebuffer(&self, texture: GLTexture) -> GLFramebuffer { @@ -470,77 +477,67 @@ impl Device for GLDevice { self.set_texture_parameters(texture); } - fn read_pixels_from_default_framebuffer(&self, size: Vector2I) -> Vec { - let mut pixels = vec![0; size.x() as usize * size.y() as usize * 4]; - unsafe { - gl::BindFramebuffer(gl::FRAMEBUFFER, self.default_framebuffer); ck(); - gl::ReadPixels(0, - 0, - size.x() as GLsizei, - size.y() as GLsizei, - gl::RGBA, - gl::UNSIGNED_BYTE, - pixels.as_mut_ptr() as *mut GLvoid); ck(); - } + fn read_pixels(&self, render_target: &RenderTarget, viewport: RectI) -> TextureData { + let (origin, size) = (viewport.origin(), viewport.size()); + let format = self.render_target_format(render_target); + self.bind_render_target(render_target); - // Flip right-side-up. - let stride = size.x() as usize * 4; - for y in 0..(size.y() as usize / 2) { - let (index_a, index_b) = (y * stride, (size.y() as usize - y - 1) * stride); - for offset in 0..stride { - pixels.swap(index_a + offset, index_b + offset); + match format { + TextureFormat::R8 | TextureFormat::RGBA8 => { + let channels = format.channels(); + let mut pixels = vec![0; size.x() as usize * size.y() as usize * channels]; + unsafe { + gl::ReadPixels(origin.x(), + origin.y(), + size.x() as GLsizei, + size.y() as GLsizei, + format.gl_format(), + format.gl_type(), + pixels.as_mut_ptr() as *mut GLvoid); ck(); + } + flip_y(&mut pixels, size, channels); + TextureData::U8(pixels) } - } - - pixels - } - - fn clear(&self, params: &ClearParams) { - unsafe { - if let Some(rect) = params.rect { - let (origin, size) = (rect.origin(), rect.size()); - gl::Scissor(origin.x(), origin.y(), size.x(), size.y()); ck(); - gl::Enable(gl::SCISSOR_TEST); ck(); - } - - let mut flags = 0; - if let Some(color) = params.color { - gl::ColorMask(gl::TRUE, gl::TRUE, gl::TRUE, gl::TRUE); ck(); - gl::ClearColor(color.r(), color.g(), color.b(), color.a()); ck(); - flags |= gl::COLOR_BUFFER_BIT; - } - if let Some(depth) = params.depth { - gl::DepthMask(gl::TRUE); ck(); - gl::ClearDepthf(depth as _); ck(); // FIXME(pcwalton): GLES - flags |= gl::DEPTH_BUFFER_BIT; - } - if let Some(stencil) = params.stencil { - gl::StencilMask(!0); ck(); - gl::ClearStencil(stencil as GLint); ck(); - flags |= gl::STENCIL_BUFFER_BIT; - } - if flags != 0 { - gl::Clear(flags); ck(); - } - - if params.rect.is_some() { - gl::Disable(gl::SCISSOR_TEST); ck(); + TextureFormat::R16F => { + let mut pixels = vec![0; size.x() as usize * size.y() as usize]; + unsafe { + gl::ReadPixels(origin.x(), + origin.y(), + size.x() as GLsizei, + size.y() as GLsizei, + format.gl_format(), + format.gl_type(), + pixels.as_mut_ptr() as *mut GLvoid); ck(); + } + flip_y(&mut pixels, size, 1); + TextureData::U16(pixels) } } } - fn draw_arrays(&self, primitive: Primitive, index_count: u32, render_state: &RenderState) { + fn begin_commands(&self) { + // TODO(pcwalton): Add some checks in debug mode to make sure render commands are bracketed + // by these? + } + + fn end_commands(&self) { + unsafe { gl::Flush(); } + } + + fn draw_arrays(&self, index_count: u32, render_state: &RenderState) { self.set_render_state(render_state); unsafe { - gl::DrawArrays(primitive.to_gl_primitive(), 0, index_count as GLsizei); ck(); + gl::DrawArrays(render_state.primitive.to_gl_primitive(), + 0, + index_count as GLsizei); ck(); } self.reset_render_state(render_state); } - fn draw_elements(&self, primitive: Primitive, index_count: u32, render_state: &RenderState) { + fn draw_elements(&self, index_count: u32, render_state: &RenderState) { self.set_render_state(render_state); unsafe { - gl::DrawElements(primitive.to_gl_primitive(), + gl::DrawElements(render_state.primitive.to_gl_primitive(), index_count as GLsizei, gl::UNSIGNED_INT, ptr::null()); ck(); @@ -549,13 +546,12 @@ impl Device for GLDevice { } fn draw_elements_instanced(&self, - primitive: Primitive, index_count: u32, instance_count: u32, - render_state: &RenderState) { + render_state: &RenderState) { self.set_render_state(render_state); unsafe { - gl::DrawElementsInstanced(primitive.to_gl_primitive(), + gl::DrawElementsInstanced(render_state.primitive.to_gl_primitive(), index_count as GLsizei, gl::UNSIGNED_INT, ptr::null(), @@ -588,66 +584,102 @@ impl Device for GLDevice { } #[inline] - fn timer_query_is_available(&self, query: &Self::TimerQuery) -> bool { + fn get_timer_query(&self, query: &Self::TimerQuery) -> Option { unsafe { let mut result = 0; gl::GetQueryObjectiv(query.gl_query, gl::QUERY_RESULT_AVAILABLE, &mut result); ck(); - result != gl::FALSE as GLint - } - } - - #[inline] - fn get_timer_query(&self, query: &Self::TimerQuery) -> Duration { - unsafe { + if result == gl::FALSE as GLint { + return None; + } let mut result = 0; gl::GetQueryObjectui64v(query.gl_query, gl::QUERY_RESULT, &mut result); ck(); - Duration::from_nanos(result) + Some(Duration::from_nanos(result)) } } #[inline] + fn bind_buffer(&self, vertex_array: &GLVertexArray, buffer: &GLBuffer, target: BufferTarget) { + self.bind_vertex_array(vertex_array); + unsafe { + gl::BindBuffer(target.to_gl_target(), buffer.gl_buffer); ck(); + } + self.unbind_vertex_array(); + } + + #[inline] + fn create_shader( + &self, + resources: &dyn ResourceLoader, + name: &str, + kind: ShaderKind, + ) -> Self::Shader { + let suffix = match kind { + ShaderKind::Vertex => 'v', + ShaderKind::Fragment => 'f', + }; + let path = format!("shaders/gl3/{}.{}s.glsl", name, suffix); + self.create_shader_from_source(name, &resources.slurp(&path).unwrap(), kind) + } +} + +impl GLDevice { + fn bind_render_target(&self, attachment: &RenderTarget) { + match *attachment { + RenderTarget::Default => self.bind_default_framebuffer(), + RenderTarget::Framebuffer(framebuffer) => self.bind_framebuffer(framebuffer), + } + } + fn bind_vertex_array(&self, vertex_array: &GLVertexArray) { unsafe { gl::BindVertexArray(vertex_array.gl_vertex_array); ck(); } } - #[inline] - fn bind_buffer(&self, buffer: &GLBuffer, target: BufferTarget) { + fn unbind_vertex_array(&self) { unsafe { - gl::BindBuffer(target.to_gl_target(), buffer.gl_buffer); ck(); + gl::BindVertexArray(0); ck(); } } - #[inline] - fn bind_default_framebuffer(&self, viewport: RectI) { - unsafe { - gl::BindFramebuffer(gl::FRAMEBUFFER, self.default_framebuffer); ck(); - gl::Viewport(viewport.origin().x(), - viewport.origin().y(), - viewport.size().x(), - viewport.size().y()); ck(); - } - } - - #[inline] - fn bind_framebuffer(&self, framebuffer: &GLFramebuffer) { - unsafe { - gl::BindFramebuffer(gl::FRAMEBUFFER, framebuffer.gl_framebuffer); ck(); - gl::Viewport(0, 0, framebuffer.texture.size.x(), framebuffer.texture.size.y()); ck(); - } - } - - #[inline] fn bind_texture(&self, texture: &GLTexture, unit: u32) { unsafe { gl::ActiveTexture(gl::TEXTURE0 + unit); ck(); gl::BindTexture(gl::TEXTURE_2D, texture.gl_texture); ck(); } } -} -impl GLDevice { + fn unbind_texture(&self, unit: u32) { + unsafe { + gl::ActiveTexture(gl::TEXTURE0 + unit); ck(); + gl::BindTexture(gl::TEXTURE_2D, 0); ck(); + } + } + + fn use_program(&self, program: &GLProgram) { + unsafe { + gl::UseProgram(program.gl_program); ck(); + } + } + + fn unuse_program(&self) { + unsafe { + gl::UseProgram(0); ck(); + } + } + + fn bind_default_framebuffer(&self) { + unsafe { + gl::BindFramebuffer(gl::FRAMEBUFFER, self.default_framebuffer); ck(); + } + } + + fn bind_framebuffer(&self, framebuffer: &GLFramebuffer) { + unsafe { + gl::BindFramebuffer(gl::FRAMEBUFFER, framebuffer.gl_framebuffer); ck(); + } + } + fn preprocess(&self, output: &mut Vec, source: &[u8], version: &str) { let mut index = 0; while index < source.len() { @@ -669,6 +701,39 @@ impl GLDevice { } } } + + fn clear(&self, ops: &ClearOps) { + unsafe { + let mut flags = 0; + if let Some(color) = ops.color { + gl::ColorMask(gl::TRUE, gl::TRUE, gl::TRUE, gl::TRUE); ck(); + gl::ClearColor(color.r(), color.g(), color.b(), color.a()); ck(); + flags |= gl::COLOR_BUFFER_BIT; + } + if let Some(depth) = ops.depth { + gl::DepthMask(gl::TRUE); ck(); + gl::ClearDepthf(depth as _); ck(); // FIXME(pcwalton): GLES + flags |= gl::DEPTH_BUFFER_BIT; + } + if let Some(stencil) = ops.stencil { + gl::StencilMask(!0); ck(); + gl::ClearStencil(stencil as GLint); ck(); + flags |= gl::STENCIL_BUFFER_BIT; + } + if flags != 0 { + gl::Clear(flags); ck(); + } + } + } + + fn render_target_format(&self, render_target: &RenderTarget) -> TextureFormat { + match *render_target { + RenderTarget::Default => TextureFormat::RGBA8, + RenderTarget::Framebuffer(ref framebuffer) => { + self.framebuffer_texture(framebuffer).format + } + } + } } pub struct GLVertexArray { @@ -753,7 +818,7 @@ impl Drop for GLBuffer { #[derive(Debug)] pub struct GLUniform { - pub location: GLint, + location: GLint, } pub struct GLProgram { @@ -787,6 +852,7 @@ impl Drop for GLShader { pub struct GLTexture { gl_texture: GLuint, pub size: Vector2I, + pub format: TextureFormat, } pub struct GLTimerQuery { @@ -863,7 +929,36 @@ impl StencilFuncExt for StencilFunc { match self { StencilFunc::Always => gl::ALWAYS, StencilFunc::Equal => gl::EQUAL, - StencilFunc::NotEqual => gl::NOTEQUAL, + } + } +} + +trait TextureFormatExt { + fn gl_internal_format(self) -> GLint; + fn gl_format(self) -> GLuint; + fn gl_type(self) -> GLuint; +} + +impl TextureFormatExt for TextureFormat { + fn gl_internal_format(self) -> GLint { + match self { + TextureFormat::R8 => gl::R8 as GLint, + TextureFormat::R16F => gl::R16F as GLint, + TextureFormat::RGBA8 => gl::RGBA as GLint, + } + } + + fn gl_format(self) -> GLuint { + match self { + TextureFormat::R8 | TextureFormat::R16F => gl::RED, + TextureFormat::RGBA8 => gl::RGBA, + } + } + + fn gl_type(self) -> GLuint { + match self { + TextureFormat::R8 | TextureFormat::RGBA8 => gl::UNSIGNED_BYTE, + TextureFormat::R16F => gl::HALF_FLOAT, } } } @@ -929,4 +1024,15 @@ fn ck() { #[cfg(not(debug_assertions))] fn ck() {} -// Shader preprocessing +// Utilities + +// Flips a buffer of image data upside-down. +fn flip_y(pixels: &mut [T], size: Vector2I, channels: usize) { + let stride = size.x() as usize * channels; + for y in 0..(size.y() as usize / 2) { + let (index_a, index_b) = (y * stride, (size.y() as usize - y - 1) * stride); + for offset in 0..stride { + pixels.swap(index_a + offset, index_b + offset); + } + } +} diff --git a/gpu/src/lib.rs b/gpu/src/lib.rs index 7d1fde49..227b0993 100644 --- a/gpu/src/lib.rs +++ b/gpu/src/lib.rs @@ -21,7 +21,7 @@ use std::time::Duration; pub mod resources; -pub trait Device { +pub trait Device: Sized { type Buffer; type Framebuffer; type Program; @@ -34,6 +34,8 @@ pub trait Device { fn create_texture(&self, format: TextureFormat, size: Vector2I) -> Self::Texture; fn create_texture_from_data(&self, size: Vector2I, data: &[u8]) -> Self::Texture; + fn create_shader(&self, resources: &dyn ResourceLoader, name: &str, kind: ShaderKind) + -> Self::Shader; fn create_shader_from_source(&self, name: &str, source: &[u8], kind: ShaderKind) -> Self::Shader; fn create_vertex_array(&self) -> Self::VertexArray; @@ -46,9 +48,14 @@ pub trait Device { ) -> Self::Program; fn get_vertex_attr(&self, program: &Self::Program, name: &str) -> Option; fn get_uniform(&self, program: &Self::Program, name: &str) -> Self::Uniform; - fn use_program(&self, program: &Self::Program); - fn configure_vertex_attr(&self, attr: &Self::VertexAttr, descriptor: &VertexAttrDescriptor); - fn set_uniform(&self, uniform: &Self::Uniform, data: UniformData); + fn bind_buffer(&self, + vertex_array: &Self::VertexArray, + buffer: &Self::Buffer, + target: BufferTarget); + fn configure_vertex_attr(&self, + vertex_array: &Self::VertexArray, + attr: &Self::VertexAttr, + descriptor: &VertexAttrDescriptor); fn create_framebuffer(&self, texture: Self::Texture) -> Self::Framebuffer; fn create_buffer(&self) -> Self::Buffer; fn allocate_buffer( @@ -61,27 +68,19 @@ pub trait Device { fn framebuffer_texture<'f>(&self, framebuffer: &'f Self::Framebuffer) -> &'f Self::Texture; fn texture_size(&self, texture: &Self::Texture) -> Vector2I; fn upload_to_texture(&self, texture: &Self::Texture, size: Vector2I, data: &[u8]); - fn read_pixels_from_default_framebuffer(&self, size: Vector2I) -> Vec; - fn clear(&self, params: &ClearParams); - fn draw_arrays(&self, primitive: Primitive, index_count: u32, render_state: &RenderState); - fn draw_elements(&self, primitive: Primitive, index_count: u32, render_state: &RenderState); + fn read_pixels(&self, target: &RenderTarget, viewport: RectI) -> TextureData; + fn begin_commands(&self); + fn end_commands(&self); + fn draw_arrays(&self, index_count: u32, render_state: &RenderState); + fn draw_elements(&self, index_count: u32, render_state: &RenderState); fn draw_elements_instanced(&self, - primitive: Primitive, index_count: u32, instance_count: u32, - render_state: &RenderState); + render_state: &RenderState); fn create_timer_query(&self) -> Self::TimerQuery; fn begin_timer_query(&self, query: &Self::TimerQuery); fn end_timer_query(&self, query: &Self::TimerQuery); - fn timer_query_is_available(&self, query: &Self::TimerQuery) -> bool; - fn get_timer_query(&self, query: &Self::TimerQuery) -> Duration; - - // TODO(pcwalton): Go bindless... - fn bind_vertex_array(&self, vertex_array: &Self::VertexArray); - fn bind_buffer(&self, buffer: &Self::Buffer, target: BufferTarget); - fn bind_default_framebuffer(&self, viewport: RectI); - fn bind_framebuffer(&self, framebuffer: &Self::Framebuffer); - fn bind_texture(&self, texture: &Self::Texture, unit: u32); + fn get_timer_query(&self, query: &Self::TimerQuery) -> Option; fn create_texture_from_png(&self, resources: &dyn ResourceLoader, name: &str) -> Self::Texture { let data = resources.slurp(&format!("textures/{}.png", name)).unwrap(); @@ -92,20 +91,6 @@ pub trait Device { self.create_texture_from_data(size, &image) } - fn create_shader( - &self, - resources: &dyn ResourceLoader, - name: &str, - kind: ShaderKind, - ) -> Self::Shader { - let suffix = match kind { - ShaderKind::Vertex => 'v', - ShaderKind::Fragment => 'f', - }; - let source = resources.slurp(&format!("shaders/gl3/{}.{}s.glsl", name, suffix)).unwrap(); - self.create_shader_from_source(name, &source, kind) - } - fn create_program_from_shader_names( &self, resources: &dyn ResourceLoader, @@ -124,7 +109,7 @@ pub trait Device { } } -#[derive(Clone, Copy, Debug)] +#[derive(Clone, Copy, Debug, PartialEq)] pub enum TextureFormat { R8, R16F, @@ -167,7 +152,6 @@ pub enum ShaderKind { #[derive(Clone, Copy)] pub enum UniformData { Int(i32), - Mat2(F32x4), Mat4([F32x4; 4]), Vec2(F32x4), Vec4(F32x4), @@ -180,23 +164,41 @@ pub enum Primitive { Lines, } -#[derive(Clone, Copy, Default)] -pub struct ClearParams { +#[derive(Clone)] +pub struct RenderState<'a, D> where D: Device { + pub target: &'a RenderTarget<'a, D>, + pub program: &'a D::Program, + pub vertex_array: &'a D::VertexArray, + pub primitive: Primitive, + pub uniforms: &'a [(&'a D::Uniform, UniformData)], + pub textures: &'a [&'a D::Texture], + pub viewport: RectI, + pub options: RenderOptions, +} + +#[derive(Clone, Debug)] +pub struct RenderOptions { + pub blend: BlendState, + pub depth: Option, + pub stencil: Option, + pub clear_ops: ClearOps, + pub color_mask: bool, +} + +#[derive(Clone, Copy, Debug, Default)] +pub struct ClearOps { pub color: Option, - pub rect: Option, pub depth: Option, pub stencil: Option, } -#[derive(Clone, Debug)] -pub struct RenderState { - pub blend: BlendState, - pub depth: Option, - pub stencil: Option, - pub color_mask: bool, +#[derive(Clone, Copy, Debug)] +pub enum RenderTarget<'a, D> where D: Device { + Default, + Framebuffer(&'a D::Framebuffer), } -#[derive(Clone, Copy, Debug)] +#[derive(Clone, Copy, Debug, PartialEq)] pub enum BlendState { Off, RGBOneAlphaOne, @@ -228,16 +230,16 @@ pub struct StencilState { pub enum StencilFunc { Always, Equal, - NotEqual, } -impl Default for RenderState { +impl Default for RenderOptions { #[inline] - fn default() -> RenderState { - RenderState { + fn default() -> RenderOptions { + RenderOptions { blend: BlendState::default(), depth: None, stencil: None, + clear_ops: ClearOps::default(), color_mask: true, } } @@ -276,6 +278,12 @@ impl Default for StencilFunc { } } +#[derive(Clone, Debug)] +pub enum TextureData { + U8(Vec), + U16(Vec), +} + impl UniformData { #[inline] pub fn from_transform_3d(transform: &Transform3DF) -> UniformData { @@ -291,6 +299,7 @@ pub struct VertexAttrDescriptor { pub stride: usize, pub offset: usize, pub divisor: u32, + pub buffer_index: u32, } #[derive(Clone, Copy, Debug, PartialEq)] @@ -299,3 +308,20 @@ pub enum VertexAttrClass { FloatNorm, Int, } + +impl TextureFormat { + #[inline] + pub fn channels(self) -> usize { + match self { + TextureFormat::R8 | TextureFormat::R16F => 1, + TextureFormat::RGBA8 => 4, + } + } +} + +impl ClearOps { + #[inline] + pub fn has_ops(&self) -> bool { + self.color.is_some() || self.depth.is_some() || self.stencil.is_some() + } +} diff --git a/metal/Cargo.toml b/metal/Cargo.toml new file mode 100644 index 00000000..8ddef24b --- /dev/null +++ b/metal/Cargo.toml @@ -0,0 +1,24 @@ +[package] +name = "pathfinder_metal" +version = "0.1.0" +authors = ["Patrick Walton "] +edition = "2018" + +[dependencies] +bitflags = "1.0" +byteorder = "1.3" +block = "0.1" +cocoa = "0.18" +core-foundation = "0.6" +foreign-types = "0.3" +metal = "0.14" +objc = "0.2" + +[dependencies.pathfinder_geometry] +path = "../geometry" + +[dependencies.pathfinder_gpu] +path = "../gpu" + +[dependencies.pathfinder_simd] +path = "../simd" diff --git a/metal/src/lib.rs b/metal/src/lib.rs new file mode 100644 index 00000000..63856a09 --- /dev/null +++ b/metal/src/lib.rs @@ -0,0 +1,1484 @@ +// pathfinder/metal/src/lib.rs +// +// Copyright © 2019 The Pathfinder Project Developers. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! A Metal implementation of the device abstraction, for macOS and iOS. + +#![allow(non_upper_case_globals)] + +#[macro_use] +extern crate bitflags; +#[macro_use] +extern crate objc; + +use block::{Block, ConcreteBlock, RcBlock}; +use byteorder::{NativeEndian, WriteBytesExt}; +use cocoa::foundation::{NSRange, NSUInteger}; +use core_foundation::base::TCFType; +use core_foundation::string::{CFString, CFStringRef}; +use foreign_types::{ForeignType, ForeignTypeRef}; +use metal::{self, Argument, ArgumentEncoder, Buffer, CommandBuffer, CommandBufferRef}; +use metal::{CommandQueue, CompileOptions, CoreAnimationDrawable, CoreAnimationDrawableRef}; +use metal::{CoreAnimationLayer, CoreAnimationLayerRef, DepthStencilDescriptor, Function, Library}; +use metal::{MTLArgument, MTLArgumentEncoder, MTLBlendFactor, MTLClearColor, MTLColorWriteMask}; +use metal::{MTLCompareFunction, MTLDataType, MTLDevice, MTLFunctionType, MTLIndexType}; +use metal::{MTLLoadAction, MTLOrigin, MTLPixelFormat, MTLPrimitiveType, MTLRegion}; +use metal::{MTLRenderPipelineReflection, MTLRenderPipelineState, MTLResourceOptions}; +use metal::{MTLResourceUsage, MTLSamplerAddressMode, MTLSamplerMinMagFilter, MTLSize}; +use metal::{MTLStencilOperation, MTLStorageMode, MTLStoreAction, MTLTextureType, MTLTextureUsage}; +use metal::{MTLVertexFormat, MTLVertexStepFunction, MTLViewport, RenderCommandEncoder}; +use metal::{RenderCommandEncoderRef, RenderPassDescriptor, RenderPassDescriptorRef}; +use metal::{RenderPipelineColorAttachmentDescriptorRef, RenderPipelineDescriptor}; +use metal::{RenderPipelineReflection, RenderPipelineReflectionRef, RenderPipelineState}; +use metal::{SamplerDescriptor, SamplerState, StencilDescriptor, StructMemberRef, StructType}; +use metal::{StructTypeRef, TextureDescriptor, Texture, TextureRef, VertexAttribute}; +use metal::{VertexAttributeRef, VertexDescriptor, VertexDescriptorRef}; +use objc::runtime::{Class, Object}; +use pathfinder_geometry::basic::rect::RectI; +use pathfinder_geometry::basic::vector::Vector2I; +use pathfinder_gpu::resources::ResourceLoader; +use pathfinder_gpu::{BlendState, BufferData, BufferTarget, BufferUploadMode, DepthFunc, Device}; +use pathfinder_gpu::{Primitive, RenderState, RenderTarget, ShaderKind, StencilFunc, TextureData}; +use pathfinder_gpu::{TextureFormat, UniformData, VertexAttrClass}; +use pathfinder_gpu::{VertexAttrDescriptor, VertexAttrType}; +use pathfinder_simd::default::F32x4; +use std::cell::{Cell, RefCell}; +use std::mem; +use std::ptr; +use std::rc::Rc; +use std::slice; +use std::sync::Arc; +use std::time::{Duration, Instant}; + +const FIRST_VERTEX_BUFFER_INDEX: u64 = 1; + +pub struct MetalDevice { + device: metal::Device, + layer: CoreAnimationLayer, + drawable: CoreAnimationDrawable, + main_depth_stencil_texture: Texture, + command_queue: CommandQueue, + command_buffers: RefCell>, + sampler: SamplerState, + shared_event: SharedEvent, + shared_event_listener: SharedEventListener, + next_timer_query_event_value: Cell, +} + +pub struct MetalProgram { + vertex: MetalShader, + fragment: MetalShader, +} + +#[derive(Clone)] +pub struct MetalBuffer { + buffer: Rc>>, +} + +impl MetalDevice { + #[inline] + pub fn new(layer: &CoreAnimationLayerRef) -> MetalDevice { + let layer = layer.retain(); + let device = layer.device(); + let drawable = layer.next_drawable().unwrap().retain(); + let command_queue = device.new_command_queue(); + + let sampler_descriptor = SamplerDescriptor::new(); + sampler_descriptor.set_support_argument_buffers(true); + sampler_descriptor.set_normalized_coordinates(true); + sampler_descriptor.set_min_filter(MTLSamplerMinMagFilter::Linear); + sampler_descriptor.set_mag_filter(MTLSamplerMinMagFilter::Linear); + sampler_descriptor.set_address_mode_s(MTLSamplerAddressMode::ClampToEdge); + sampler_descriptor.set_address_mode_t(MTLSamplerAddressMode::ClampToEdge); + let sampler = device.new_sampler(&sampler_descriptor); + + let main_color_texture = drawable.texture(); + let framebuffer_size = Vector2I::new(main_color_texture.width() as i32, + main_color_texture.height() as i32); + let main_depth_stencil_texture = device.create_depth_stencil_texture(framebuffer_size); + + let shared_event = device.new_shared_event(); + + MetalDevice { + device, + layer, + drawable, + main_depth_stencil_texture, + command_queue, + command_buffers: RefCell::new(vec![]), + sampler, + shared_event, + shared_event_listener: SharedEventListener::new(), + next_timer_query_event_value: Cell::new(1), + } + } + + pub fn present_drawable(&mut self) { + self.begin_commands(); + self.command_buffers.borrow_mut().last().unwrap().present_drawable(&self.drawable); + self.end_commands(); + self.drawable = self.layer.next_drawable().unwrap().retain(); + } +} + +pub struct MetalFramebuffer(MetalTexture); + +pub struct MetalShader { + #[allow(dead_code)] + library: Library, + function: Function, + uniforms: RefCell, +} + +enum ShaderUniforms { + Unknown, + NoUniforms, + Uniforms { encoder: ArgumentEncoder, struct_type: StructType } +} + +pub struct MetalTexture { + texture: Texture, + dirty: Cell, +} + +pub struct MetalTimerQuery { + event_value: u64, + start_time: Cell>, + end_time: Cell>, +} + +#[derive(Clone)] +pub struct MetalUniform { + indices: RefCell>, + name: String, +} + +#[derive(Clone, Copy)] +pub struct MetalUniformIndices { + vertex: Option, + fragment: Option, +} + +#[derive(Clone, Copy)] +pub struct MetalUniformIndex { + main: u64, + sampler: Option, +} + +pub struct MetalVertexArray { + descriptor: VertexDescriptor, + vertex_buffers: RefCell>, + index_buffer: RefCell>, +} + +impl Device for MetalDevice { + type Buffer = MetalBuffer; + type Framebuffer = MetalFramebuffer; + type Program = MetalProgram; + type Shader = MetalShader; + type Texture = MetalTexture; + type TimerQuery = Arc; + type Uniform = MetalUniform; + type VertexArray = MetalVertexArray; + type VertexAttr = VertexAttribute; + + // TODO: Add texture usage hint. + fn create_texture(&self, format: TextureFormat, size: Vector2I) -> MetalTexture { + let descriptor = TextureDescriptor::new(); + descriptor.set_texture_type(MTLTextureType::D2); + match format { + TextureFormat::R8 => descriptor.set_pixel_format(MTLPixelFormat::R8Unorm), + TextureFormat::R16F => descriptor.set_pixel_format(MTLPixelFormat::R16Float), + TextureFormat::RGBA8 => descriptor.set_pixel_format(MTLPixelFormat::RGBA8Unorm), + } + descriptor.set_width(size.x() as u64); + descriptor.set_height(size.y() as u64); + descriptor.set_storage_mode(MTLStorageMode::Managed); + descriptor.set_usage(MTLTextureUsage::Unknown); + MetalTexture { texture: self.device.new_texture(&descriptor), dirty: Cell::new(false) } + } + + fn create_texture_from_data(&self, size: Vector2I, data: &[u8]) -> MetalTexture { + assert!(data.len() >= size.x() as usize * size.y() as usize); + let texture = self.create_texture(TextureFormat::R8, size); + self.upload_to_texture(&texture, size, data); + texture + } + + fn create_shader_from_source(&self, _: &str, source: &[u8], _: ShaderKind) -> MetalShader { + let source = String::from_utf8(source.to_vec()).expect("Source wasn't valid UTF-8!"); + + let compile_options = CompileOptions::new(); + let library = self.device.new_library_with_source(&source, &compile_options).unwrap(); + let function = library.get_function("main0", None).unwrap(); + + MetalShader { library, function, uniforms: RefCell::new(ShaderUniforms::Unknown) } + } + + fn create_vertex_array(&self) -> MetalVertexArray { + MetalVertexArray { + descriptor: VertexDescriptor::new().retain(), + vertex_buffers: RefCell::new(vec![]), + index_buffer: RefCell::new(None), + } + } + + fn bind_buffer(&self, + vertex_array: &MetalVertexArray, + buffer: &MetalBuffer, + target: BufferTarget) { + match target { + BufferTarget::Vertex => { + vertex_array.vertex_buffers.borrow_mut().push((*buffer).clone()) + } + BufferTarget::Index => { + *vertex_array.index_buffer.borrow_mut() = Some((*buffer).clone()) + } + } + } + + fn create_program_from_shaders(&self, + _: &dyn ResourceLoader, + _: &str, + vertex_shader: MetalShader, + fragment_shader: MetalShader) + -> MetalProgram { + MetalProgram { vertex: vertex_shader, fragment: fragment_shader } + } + + fn get_vertex_attr(&self, program: &MetalProgram, name: &str) -> Option { + // TODO(pcwalton): Cache the function? + let attributes = program.vertex.function.real_vertex_attributes(); + for attribute_index in 0..attributes.len() { + let attribute = attributes.object_at(attribute_index); + let this_name = attribute.name().as_bytes(); + if this_name[0] == b'a' && this_name[1..] == *name.as_bytes() { + return Some(attribute.retain()) + } + } + None + } + + fn get_uniform(&self, _: &Self::Program, name: &str) -> MetalUniform { + MetalUniform { indices: RefCell::new(None), name: name.to_owned() } + } + + fn configure_vertex_attr(&self, + vertex_array: &MetalVertexArray, + attr: &VertexAttribute, + descriptor: &VertexAttrDescriptor) { + debug_assert_ne!(descriptor.stride, 0); + + let attribute_index = attr.attribute_index(); + + let attr_info = vertex_array.descriptor + .attributes() + .object_at(attribute_index as usize) + .unwrap(); + let format = match (descriptor.class, descriptor.attr_type, descriptor.size) { + (VertexAttrClass::Int, VertexAttrType::I8, 2) => MTLVertexFormat::Char2, + (VertexAttrClass::Int, VertexAttrType::I8, 3) => MTLVertexFormat::Char3, + (VertexAttrClass::Int, VertexAttrType::I8, 4) => MTLVertexFormat::Char4, + (VertexAttrClass::Int, VertexAttrType::U8, 2) => MTLVertexFormat::UChar2, + (VertexAttrClass::Int, VertexAttrType::U8, 3) => MTLVertexFormat::UChar3, + (VertexAttrClass::Int, VertexAttrType::U8, 4) => MTLVertexFormat::UChar4, + (VertexAttrClass::FloatNorm, VertexAttrType::U8, 2) => { + MTLVertexFormat::UChar2Normalized + } + (VertexAttrClass::FloatNorm, VertexAttrType::U8, 3) => { + MTLVertexFormat::UChar3Normalized + } + (VertexAttrClass::FloatNorm, VertexAttrType::U8, 4) => { + MTLVertexFormat::UChar4Normalized + } + (VertexAttrClass::FloatNorm, VertexAttrType::I8, 2) => { + MTLVertexFormat::Char2Normalized + } + (VertexAttrClass::FloatNorm, VertexAttrType::I8, 3) => { + MTLVertexFormat::Char3Normalized + } + (VertexAttrClass::FloatNorm, VertexAttrType::I8, 4) => { + MTLVertexFormat::Char4Normalized + } + (VertexAttrClass::Int, VertexAttrType::I16, 2) => MTLVertexFormat::Short2, + (VertexAttrClass::Int, VertexAttrType::I16, 3) => MTLVertexFormat::Short3, + (VertexAttrClass::Int, VertexAttrType::I16, 4) => MTLVertexFormat::Short4, + (VertexAttrClass::Int, VertexAttrType::U16, 2) => MTLVertexFormat::UShort2, + (VertexAttrClass::Int, VertexAttrType::U16, 3) => MTLVertexFormat::UShort3, + (VertexAttrClass::Int, VertexAttrType::U16, 4) => MTLVertexFormat::UShort4, + (VertexAttrClass::FloatNorm, VertexAttrType::U16, 2) => { + MTLVertexFormat::UShort2Normalized + } + (VertexAttrClass::FloatNorm, VertexAttrType::U16, 3) => { + MTLVertexFormat::UShort3Normalized + } + (VertexAttrClass::FloatNorm, VertexAttrType::U16, 4) => { + MTLVertexFormat::UShort4Normalized + } + (VertexAttrClass::FloatNorm, VertexAttrType::I16, 2) => { + MTLVertexFormat::Short2Normalized + } + (VertexAttrClass::FloatNorm, VertexAttrType::I16, 3) => { + MTLVertexFormat::Short3Normalized + } + (VertexAttrClass::FloatNorm, VertexAttrType::I16, 4) => { + MTLVertexFormat::Short4Normalized + } + (VertexAttrClass::Float, VertexAttrType::F32, 1) => MTLVertexFormat::Float, + (VertexAttrClass::Float, VertexAttrType::F32, 2) => MTLVertexFormat::Float2, + (VertexAttrClass::Float, VertexAttrType::F32, 3) => MTLVertexFormat::Float3, + (VertexAttrClass::Float, VertexAttrType::F32, 4) => MTLVertexFormat::Float4, + (VertexAttrClass::Int, VertexAttrType::I8, 1) => MTLVertexFormat::Char, + (VertexAttrClass::Int, VertexAttrType::U8, 1) => MTLVertexFormat::UChar, + (VertexAttrClass::FloatNorm, VertexAttrType::I8, 1) => MTLVertexFormat::CharNormalized, + (VertexAttrClass::Int, VertexAttrType::I16, 1) => MTLVertexFormat::Short, + (VertexAttrClass::Int, VertexAttrType::U16, 1) => MTLVertexFormat::UShort, + (VertexAttrClass::FloatNorm, VertexAttrType::U16, 1) => { + MTLVertexFormat::UShortNormalized + } + (VertexAttrClass::FloatNorm, VertexAttrType::I16, 1) => { + MTLVertexFormat::ShortNormalized + } + (attr_class, attr_type, attr_size) => { + panic!("Unsupported vertex class/type/size combination: {:?}/{:?}/{}!", + attr_class, + attr_type, + attr_size) + } + }; + attr_info.set_format(format); + attr_info.set_offset(descriptor.offset as u64); + let buffer_index = descriptor.buffer_index as u64 + FIRST_VERTEX_BUFFER_INDEX; + attr_info.set_buffer_index(buffer_index); + + // FIXME(pcwalton): Metal separates out per-buffer info from per-vertex info, while our + // GL-like API does not. So we end up setting this state over and over again. Not great. + let layout = vertex_array.descriptor.layouts().object_at(buffer_index as usize).unwrap(); + if descriptor.divisor == 0 { + layout.set_step_function(MTLVertexStepFunction::PerVertex); + layout.set_step_rate(1); + } else { + layout.set_step_function(MTLVertexStepFunction::PerInstance); + layout.set_step_rate(descriptor.divisor as u64); + } + layout.set_stride(descriptor.stride as u64); + } + + fn create_framebuffer(&self, texture: MetalTexture) -> MetalFramebuffer { + MetalFramebuffer(texture) + } + + fn create_buffer(&self) -> MetalBuffer { + MetalBuffer { buffer: Rc::new(RefCell::new(None)) } + } + + fn allocate_buffer(&self, + buffer: &MetalBuffer, + data: BufferData, + _: BufferTarget, + mode: BufferUploadMode) { + let mut options = match mode { + BufferUploadMode::Static => MTLResourceOptions::CPUCacheModeWriteCombined, + BufferUploadMode::Dynamic => MTLResourceOptions::CPUCacheModeDefaultCache, + }; + options |= MTLResourceOptions::StorageModeManaged; + + match data { + BufferData::Uninitialized(size) => { + let size = (size * mem::size_of::()) as u64; + let new_buffer = self.device.new_buffer(size, options); + *buffer.buffer.borrow_mut() = Some(new_buffer); + } + BufferData::Memory(slice) => { + let size = (slice.len() * mem::size_of::()) as u64; + let new_buffer = self.device.new_buffer_with_data(slice.as_ptr() as *const _, + size, + options); + *buffer.buffer.borrow_mut() = Some(new_buffer); + } + } + } + + fn framebuffer_texture<'f>(&self, framebuffer: &'f MetalFramebuffer) -> &'f MetalTexture { + &framebuffer.0 + } + + fn texture_size(&self, texture: &MetalTexture) -> Vector2I { + Vector2I::new(texture.texture.width() as i32, texture.texture.height() as i32) + } + + fn upload_to_texture(&self, texture: &MetalTexture, size: Vector2I, data: &[u8]) { + assert!(data.len() >= size.x() as usize * size.y() as usize); + let format = self.texture_format(&texture.texture).expect("Unexpected texture format!"); + assert!(format == TextureFormat::R8 || format == TextureFormat::RGBA8); + + let origin = MTLOrigin { x: 0, y: 0, z: 0 }; + let size = MTLSize { width: size.x() as u64, height: size.y() as u64, depth: 1 }; + let region = MTLRegion { origin, size }; + let stride = size.width * format.channels() as u64; + texture.texture.replace_region(region, 0, stride, data.as_ptr() as *const _); + + texture.dirty.set(true); + } + + fn read_pixels(&self, target: &RenderTarget, viewport: RectI) -> TextureData { + let texture = self.render_target_color_texture(target); + self.synchronize_texture(&texture); + + let (origin, size) = (viewport.origin(), viewport.size()); + let metal_origin = MTLOrigin { x: origin.x() as u64, y: origin.y() as u64, z: 0 }; + let metal_size = MTLSize { width: size.x() as u64, height: size.y() as u64, depth: 1 }; + let metal_region = MTLRegion { origin: metal_origin, size: metal_size }; + + let format = self.texture_format(&texture) + .expect("Unexpected framebuffer texture format!"); + match format { + TextureFormat::R8 | TextureFormat::RGBA8 => { + let channels = format.channels(); + let stride = size.x() as usize * channels; + let mut pixels = vec![0; stride * size.y() as usize]; + texture.get_bytes(pixels.as_mut_ptr() as *mut _, metal_region, 0, stride as u64); + TextureData::U8(pixels) + } + TextureFormat::R16F => { + let stride = size.x() as usize; + let mut pixels = vec![0; stride * size.y() as usize]; + texture.get_bytes(pixels.as_mut_ptr() as *mut _, + metal_region, + 0, + stride as u64 * 2); + TextureData::U16(pixels) + } + } + } + + fn begin_commands(&self) { + self.command_buffers.borrow_mut().push(self.command_queue.new_command_buffer().retain()); + } + + fn end_commands(&self) { + let command_buffer = self.command_buffers.borrow_mut().pop().unwrap(); + command_buffer.commit(); + } + + fn draw_arrays(&self, index_count: u32, render_state: &RenderState) { + let encoder = self.prepare_to_draw(render_state); + let primitive = render_state.primitive.to_metal_primitive(); + encoder.draw_primitives(primitive, 0, index_count as u64); + encoder.end_encoding(); + } + + fn draw_elements(&self, index_count: u32, render_state: &RenderState) { + let encoder = self.prepare_to_draw(render_state); + let primitive = render_state.primitive.to_metal_primitive(); + let index_type = MTLIndexType::UInt32; + let index_count = index_count as u64; + let index_buffer = render_state.vertex_array + .index_buffer + .borrow(); + let index_buffer = index_buffer.as_ref().expect("No index buffer bound to VAO!"); + let index_buffer = index_buffer.buffer.borrow(); + let index_buffer = index_buffer.as_ref().expect("Index buffer not allocated!"); + encoder.draw_indexed_primitives(primitive, index_count, index_type, index_buffer, 0); + encoder.end_encoding(); + } + + fn draw_elements_instanced(&self, + index_count: u32, + instance_count: u32, + render_state: &RenderState) { + let encoder = self.prepare_to_draw(render_state); + let primitive = render_state.primitive.to_metal_primitive(); + let index_type = MTLIndexType::UInt32; + let index_buffer = render_state.vertex_array + .index_buffer + .borrow(); + let index_buffer = index_buffer.as_ref().expect("No index buffer bound to VAO!"); + let index_buffer = index_buffer.buffer.borrow(); + let index_buffer = index_buffer.as_ref().expect("Index buffer not allocated!"); + encoder.draw_indexed_primitives_instanced(primitive, + index_count as u64, + index_type, + index_buffer, + 0, + instance_count as u64); + encoder.end_encoding(); + } + + fn create_timer_query(&self) -> Arc { + let event_value = self.next_timer_query_event_value.get(); + self.next_timer_query_event_value.set(event_value + 2); + + let query = Arc::new(MetalTimerQuery { + event_value, + start_time: Cell::new(None), + end_time: Cell::new(None), + }); + + let captured_query = query.clone(); + let start_block = ConcreteBlock::new(move |_: *mut Object, _: u64| { + captured_query.start_time.set(Some(Instant::now())) + }); + let captured_query = query.clone(); + let end_block = ConcreteBlock::new(move |_: *mut Object, _: u64| { + captured_query.end_time.set(Some(Instant::now())) + }); + self.shared_event.notify_listener_at_value(&self.shared_event_listener, + event_value, + start_block.copy()); + self.shared_event.notify_listener_at_value(&self.shared_event_listener, + event_value + 1, + end_block.copy()); + + query + } + + fn begin_timer_query(&self, query: &Arc) { + self.command_buffers + .borrow_mut() + .last() + .unwrap() + .encode_signal_event(&self.shared_event, query.event_value); + } + + fn end_timer_query(&self, query: &Arc) { + self.command_buffers + .borrow_mut() + .last() + .unwrap() + .encode_signal_event(&self.shared_event, query.event_value + 1); + } + + fn get_timer_query(&self, query: &Arc) -> Option { + match (query.start_time.get(), query.end_time.get()) { + (Some(start_time), Some(end_time)) => Some(end_time - start_time), + _ => None, + } + } + + #[inline] + fn create_shader( + &self, + resources: &dyn ResourceLoader, + name: &str, + kind: ShaderKind, + ) -> Self::Shader { + let suffix = match kind { + ShaderKind::Vertex => 'v', + ShaderKind::Fragment => 'f', + }; + let path = format!("shaders/metal/{}.{}s.metal", name, suffix); + self.create_shader_from_source(name, &resources.slurp(&path).unwrap(), kind) + } +} + +impl MetalDevice { + fn get_uniform_index(&self, shader: &MetalShader, name: &str) -> Option { + let uniforms = shader.uniforms.borrow(); + let struct_type = match *uniforms { + ShaderUniforms::Unknown => panic!("get_uniform_index() called before reflection!"), + ShaderUniforms::NoUniforms => return None, + ShaderUniforms::Uniforms { ref struct_type, .. } => struct_type, + }; + let main_member = match struct_type.member_from_name(&format!("u{}", name)) { + None => return None, + Some(main_member) => main_member, + }; + let main_index = main_member.argument_index(); + let sampler_index = match struct_type.member_from_name(&format!("u{}Smplr", name)) { + None => None, + Some(sampler_member) => Some(sampler_member.argument_index()), + }; + Some(MetalUniformIndex { main: main_index, sampler: sampler_index }) + } + + fn populate_uniform_indices_if_necessary(&self, + uniform: &MetalUniform, + program: &MetalProgram) { + + let mut indices = uniform.indices.borrow_mut(); + if indices.is_some() { + return; + } + + *indices = Some(MetalUniformIndices { + vertex: self.get_uniform_index(&program.vertex, &uniform.name), + fragment: self.get_uniform_index(&program.fragment, &uniform.name), + }); + } + + fn render_target_color_texture(&self, render_target: &RenderTarget) + -> Texture { + match *render_target { + RenderTarget::Default {..} => self.drawable.texture().retain(), + RenderTarget::Framebuffer(framebuffer) => framebuffer.0.texture.retain(), + } + } + + fn render_target_depth_texture(&self, render_target: &RenderTarget) + -> Option { + match *render_target { + RenderTarget::Default {..} => Some(self.main_depth_stencil_texture.retain()), + RenderTarget::Framebuffer(_) => None, + } + } + + fn render_target_has_depth(&self, render_target: &RenderTarget) -> bool { + match *render_target { + RenderTarget::Default {..} => true, + RenderTarget::Framebuffer(_) => false, + } + } + + fn prepare_to_draw(&self, render_state: &RenderState) -> RenderCommandEncoder { + let command_buffers = self.command_buffers.borrow(); + let command_buffer = command_buffers.last().unwrap(); + + // FIXME(pcwalton): Is this necessary? + let mut blit_command_encoder = None; + for texture in render_state.textures { + if !texture.dirty.get() { + continue; + } + if blit_command_encoder.is_none() { + blit_command_encoder = Some(command_buffer.new_blit_command_encoder()); + } + let blit_command_encoder = blit_command_encoder.as_ref().unwrap(); + blit_command_encoder.synchronize_resource(&texture.texture); + texture.dirty.set(false); + } + if let Some(blit_command_encoder) = blit_command_encoder { + blit_command_encoder.end_encoding(); + } + + let render_pass_descriptor = self.create_render_pass_descriptor(render_state); + + let encoder = command_buffer.new_render_command_encoder(&render_pass_descriptor).retain(); + self.set_viewport(&encoder, &render_state.viewport); + + let render_pipeline_descriptor = RenderPipelineDescriptor::new(); + render_pipeline_descriptor.set_vertex_function(Some(&render_state.program + .vertex + .function)); + render_pipeline_descriptor.set_fragment_function(Some(&render_state.program + .fragment + .function)); + render_pipeline_descriptor.set_vertex_descriptor(Some(&render_state.vertex_array + .descriptor)); + + // Create render pipeline state. + let pipeline_color_attachment = render_pipeline_descriptor.color_attachments() + .object_at(0) + .unwrap(); + self.prepare_pipeline_color_attachment_for_render(pipeline_color_attachment, + render_state); + + if self.render_target_has_depth(render_state.target) { + let depth_stencil_format = MTLPixelFormat::Depth32Float_Stencil8; + render_pipeline_descriptor.set_depth_attachment_pixel_format(depth_stencil_format); + render_pipeline_descriptor.set_stencil_attachment_pixel_format(depth_stencil_format); + } + + let reflection_options = MTLPipelineOption::ArgumentInfo | + MTLPipelineOption::BufferTypeInfo; + let (render_pipeline_state, reflection) = + self.device.real_new_render_pipeline_state_with_reflection(&render_pipeline_descriptor, + reflection_options); + + self.populate_shader_uniforms_if_necessary(&render_state.program.vertex, &reflection); + self.populate_shader_uniforms_if_necessary(&render_state.program.fragment, &reflection); + + for (vertex_buffer_index, vertex_buffer) in render_state.vertex_array + .vertex_buffers + .borrow() + .iter() + .enumerate() { + let real_index = vertex_buffer_index as u64 + FIRST_VERTEX_BUFFER_INDEX; + let buffer = vertex_buffer.buffer.borrow(); + let buffer = buffer.as_ref().map(|buffer| buffer.as_ref()).unwrap(); + encoder.set_vertex_buffer(real_index, Some(buffer), 0); + encoder.use_resource(buffer, MTLResourceUsage::Read); + } + + self.set_uniforms(&encoder, render_state); + encoder.set_render_pipeline_state(&render_pipeline_state); + self.set_depth_stencil_state(&encoder, render_state); + encoder + } + + fn populate_shader_uniforms_if_necessary(&self, + shader: &MetalShader, + reflection: &RenderPipelineReflectionRef) { + let mut uniforms = shader.uniforms.borrow_mut(); + match *uniforms { + ShaderUniforms::Unknown => {} + ShaderUniforms::NoUniforms | ShaderUniforms::Uniforms { .. } => return, + } + + let arguments = match shader.function.function_type() { + MTLFunctionType::Vertex => reflection.real_vertex_arguments(), + MTLFunctionType::Fragment => reflection.real_fragment_arguments(), + _ => panic!("Unexpected shader function type!"), + }; + + let mut has_descriptor_set = false; + for argument_index in 0..arguments.len() { + let argument = arguments.object_at(argument_index); + if argument.name() == "spvDescriptorSet0" { + has_descriptor_set = true; + break; + } + } + if !has_descriptor_set { + *uniforms = ShaderUniforms::NoUniforms; + return; + } + + let (encoder, argument) = shader.function.new_argument_encoder_with_reflection(0); + match argument.buffer_data_type() { + MTLDataType::Struct => {} + data_type => { + panic!("Unexpected data type for argument buffer: {}!", data_type as u32) + } + } + let struct_type = argument.buffer_struct_type().retain(); + *uniforms = ShaderUniforms::Uniforms { encoder, struct_type }; + } + + fn create_argument_buffer(&self, shader: &MetalShader) -> Option { + let uniforms = shader.uniforms.borrow(); + let encoder = match *uniforms { + ShaderUniforms::Unknown => unreachable!(), + ShaderUniforms::NoUniforms => return None, + ShaderUniforms::Uniforms { ref encoder, .. } => encoder, + }; + + let buffer_options = MTLResourceOptions::CPUCacheModeDefaultCache | + MTLResourceOptions::StorageModeManaged; + let buffer = self.device.new_buffer(encoder.encoded_length(), buffer_options); + encoder.set_argument_buffer(&buffer, 0); + Some(buffer) + } + + fn set_uniforms(&self, + render_command_encoder: &RenderCommandEncoderRef, + render_state: &RenderState) { + let vertex_argument_buffer = self.create_argument_buffer(&render_state.program.vertex); + let fragment_argument_buffer = self.create_argument_buffer(&render_state.program.fragment); + + let vertex_uniforms = render_state.program.vertex.uniforms.borrow(); + let fragment_uniforms = render_state.program.fragment.uniforms.borrow(); + + let (mut have_vertex_uniforms, mut have_fragment_uniforms) = (false, false); + if let ShaderUniforms::Uniforms { .. } = *vertex_uniforms { + have_vertex_uniforms = true; + let vertex_argument_buffer = vertex_argument_buffer.as_ref().unwrap(); + render_command_encoder.use_resource(vertex_argument_buffer, MTLResourceUsage::Read); + render_command_encoder.set_vertex_buffer(0, Some(vertex_argument_buffer), 0); + } + if let ShaderUniforms::Uniforms { .. } = *fragment_uniforms { + have_fragment_uniforms = true; + let fragment_argument_buffer = fragment_argument_buffer.as_ref().unwrap(); + render_command_encoder.use_resource(fragment_argument_buffer, MTLResourceUsage::Read); + render_command_encoder.set_fragment_buffer(0, Some(fragment_argument_buffer), 0); + } + + if !have_vertex_uniforms && !have_fragment_uniforms { + return; + } + + let (mut uniform_buffer_data, mut uniform_buffer_ranges) = (vec![], vec![]); + for &(_, uniform_data) in render_state.uniforms.iter() { + let start_index = uniform_buffer_data.len(); + match uniform_data { + UniformData::Int(value) => { + uniform_buffer_data.write_i32::(value).unwrap() + } + UniformData::Mat4(matrix) => { + for column in &matrix { + uniform_buffer_data.write_f32::(column.x()).unwrap(); + uniform_buffer_data.write_f32::(column.y()).unwrap(); + uniform_buffer_data.write_f32::(column.z()).unwrap(); + uniform_buffer_data.write_f32::(column.w()).unwrap(); + } + } + UniformData::Vec2(vector) => { + uniform_buffer_data.write_f32::(vector.x()).unwrap(); + uniform_buffer_data.write_f32::(vector.y()).unwrap(); + } + UniformData::Vec4(vector) => { + uniform_buffer_data.write_f32::(vector.x()).unwrap(); + uniform_buffer_data.write_f32::(vector.y()).unwrap(); + uniform_buffer_data.write_f32::(vector.z()).unwrap(); + uniform_buffer_data.write_f32::(vector.w()).unwrap(); + } + UniformData::TextureUnit(_) => {} + } + let end_index = uniform_buffer_data.len(); + uniform_buffer_ranges.push(start_index..end_index); + } + + let buffer_options = MTLResourceOptions::CPUCacheModeWriteCombined | + MTLResourceOptions::StorageModeManaged; + let data_buffer = self.device + .new_buffer_with_data(uniform_buffer_data.as_ptr() as *const _, + uniform_buffer_data.len() as u64, + buffer_options); + + for (&(uniform, ref uniform_data), buffer_range) in + render_state.uniforms.iter().zip(uniform_buffer_ranges.iter()) { + self.populate_uniform_indices_if_necessary(uniform, &render_state.program); + let indices = uniform.indices.borrow_mut(); + let indices = indices.as_ref().unwrap(); + if let Some(vertex_index) = indices.vertex { + if let ShaderUniforms::Uniforms { + encoder: ref argument_encoder, + .. + } = *vertex_uniforms { + self.set_uniform(vertex_index, + argument_encoder, + uniform_data, + &data_buffer, + buffer_range.start as u64, + render_command_encoder, + render_state); + } + } + if let Some(fragment_index) = indices.fragment { + if let ShaderUniforms::Uniforms { + encoder: ref argument_encoder, + .. + } = *fragment_uniforms { + self.set_uniform(fragment_index, + argument_encoder, + uniform_data, + &data_buffer, + buffer_range.start as u64, + render_command_encoder, + render_state); + } + } + } + + render_command_encoder.use_resource(&data_buffer, MTLResourceUsage::Read); + + if let Some(vertex_argument_buffer) = vertex_argument_buffer { + let range = NSRange::new(0, vertex_argument_buffer.length()); + vertex_argument_buffer.did_modify_range(range); + } + if let Some(fragment_argument_buffer) = fragment_argument_buffer { + let range = NSRange::new(0, fragment_argument_buffer.length()); + fragment_argument_buffer.did_modify_range(range); + } + } + + fn set_uniform(&self, + argument_index: MetalUniformIndex, + argument_encoder: &ArgumentEncoder, + uniform_data: &UniformData, + buffer: &Buffer, + buffer_offset: u64, + render_command_encoder: &RenderCommandEncoderRef, + render_state: &RenderState) { + match *uniform_data { + UniformData::TextureUnit(unit) => { + let texture = render_state.textures[unit as usize]; + argument_encoder.set_texture(&texture.texture, argument_index.main); + let mut resource_usage = MTLResourceUsage::Read; + if let Some(sampler_index) = argument_index.sampler { + argument_encoder.set_sampler_state(&self.sampler, sampler_index); + resource_usage |= MTLResourceUsage::Sample; + } + render_command_encoder.use_resource(&texture.texture, resource_usage); + } + _ => argument_encoder.set_buffer(buffer, buffer_offset, argument_index.main), + } + } + + fn prepare_pipeline_color_attachment_for_render( + &self, + pipeline_color_attachment: &RenderPipelineColorAttachmentDescriptorRef, + render_state: &RenderState) { + let pixel_format = self.render_target_color_texture(&render_state.target).pixel_format(); + pipeline_color_attachment.set_pixel_format(pixel_format); + + let blending_enabled = render_state.options.blend != BlendState::Off; + pipeline_color_attachment.set_blending_enabled(blending_enabled); + match render_state.options.blend { + BlendState::Off => {} + BlendState::RGBOneAlphaOne => { + pipeline_color_attachment.set_source_rgb_blend_factor(MTLBlendFactor::One); + pipeline_color_attachment.set_destination_rgb_blend_factor(MTLBlendFactor::One); + pipeline_color_attachment.set_source_alpha_blend_factor(MTLBlendFactor::One); + pipeline_color_attachment.set_destination_alpha_blend_factor(MTLBlendFactor::One); + } + BlendState::RGBOneAlphaOneMinusSrcAlpha => { + pipeline_color_attachment.set_source_rgb_blend_factor(MTLBlendFactor::One); + pipeline_color_attachment.set_destination_rgb_blend_factor( + MTLBlendFactor::OneMinusSourceAlpha); + pipeline_color_attachment.set_source_alpha_blend_factor(MTLBlendFactor::One); + pipeline_color_attachment.set_destination_alpha_blend_factor(MTLBlendFactor::One); + } + BlendState::RGBSrcAlphaAlphaOneMinusSrcAlpha => { + pipeline_color_attachment.set_source_rgb_blend_factor(MTLBlendFactor::SourceAlpha); + pipeline_color_attachment.set_destination_rgb_blend_factor( + MTLBlendFactor::OneMinusSourceAlpha); + pipeline_color_attachment.set_source_alpha_blend_factor(MTLBlendFactor::One); + pipeline_color_attachment.set_destination_alpha_blend_factor(MTLBlendFactor::One); + } + } + + if render_state.options.color_mask { + pipeline_color_attachment.set_write_mask(MTLColorWriteMask::all()); + } else { + pipeline_color_attachment.set_write_mask(MTLColorWriteMask::empty()); + } + } + + fn create_render_pass_descriptor(&self, render_state: &RenderState) + -> RenderPassDescriptor { + let render_pass_descriptor = RenderPassDescriptor::new().retain(); + let color_attachment = render_pass_descriptor.color_attachments().object_at(0).unwrap(); + color_attachment.set_texture(Some(&self.render_target_color_texture(render_state.target))); + + match render_state.options.clear_ops.color { + Some(color) => { + let color = MTLClearColor::new(color.r() as f64, + color.g() as f64, + color.b() as f64, + color.a() as f64); + color_attachment.set_clear_color(color); + color_attachment.set_load_action(MTLLoadAction::Clear); + } + None => color_attachment.set_load_action(MTLLoadAction::Load), + } + color_attachment.set_store_action(MTLStoreAction::Store); + + let depth_stencil_texture = self.render_target_depth_texture(render_state.target); + if let Some(depth_stencil_texture) = depth_stencil_texture { + let depth_attachment = render_pass_descriptor.depth_attachment().unwrap(); + let stencil_attachment = render_pass_descriptor.stencil_attachment().unwrap(); + depth_attachment.set_texture(Some(&depth_stencil_texture)); + stencil_attachment.set_texture(Some(&depth_stencil_texture)); + + match render_state.options.clear_ops.depth { + Some(depth) => { + depth_attachment.set_clear_depth(depth as f64); + depth_attachment.set_load_action(MTLLoadAction::Clear); + } + None => depth_attachment.set_load_action(MTLLoadAction::Load), + } + depth_attachment.set_store_action(MTLStoreAction::Store); + + match render_state.options.clear_ops.stencil { + Some(value) => { + stencil_attachment.set_clear_stencil(value as u32); + stencil_attachment.set_load_action(MTLLoadAction::Clear); + } + None => stencil_attachment.set_load_action(MTLLoadAction::Load), + } + stencil_attachment.set_store_action(MTLStoreAction::Store); + } + + render_pass_descriptor + } + + fn set_depth_stencil_state(&self, + encoder: &RenderCommandEncoderRef, + render_state: &RenderState) { + let depth_stencil_descriptor = DepthStencilDescriptor::new(); + + match render_state.options.depth { + Some(depth_state) => { + let compare_function = depth_state.func.to_metal_compare_function(); + depth_stencil_descriptor.set_depth_compare_function(compare_function); + depth_stencil_descriptor.set_depth_write_enabled(depth_state.write); + } + None => { + depth_stencil_descriptor.set_depth_compare_function(MTLCompareFunction::Always); + depth_stencil_descriptor.set_depth_write_enabled(false); + } + } + + match render_state.options.stencil { + Some(stencil_state) => { + let stencil_descriptor = StencilDescriptor::new(); + let compare_function = stencil_state.func.to_metal_compare_function(); + let (pass_operation, write_mask) = if stencil_state.write { + (MTLStencilOperation::Replace, stencil_state.mask) + } else { + (MTLStencilOperation::Keep, 0) + }; + stencil_descriptor.set_stencil_compare_function(compare_function); + stencil_descriptor.set_stencil_failure_operation(MTLStencilOperation::Keep); + stencil_descriptor.set_depth_failure_operation(MTLStencilOperation::Keep); + stencil_descriptor.set_depth_stencil_pass_operation(pass_operation); + stencil_descriptor.set_write_mask(write_mask); + depth_stencil_descriptor.set_front_face_stencil(Some(&stencil_descriptor)); + depth_stencil_descriptor.set_back_face_stencil(Some(&stencil_descriptor)); + encoder.set_stencil_reference_value(stencil_state.reference); + } + None => { + depth_stencil_descriptor.set_front_face_stencil(None); + depth_stencil_descriptor.set_back_face_stencil(None); + } + } + + let depth_stencil_state = self.device.new_depth_stencil_state(&depth_stencil_descriptor); + encoder.set_depth_stencil_state(&depth_stencil_state); + } + + fn texture_format(&self, texture: &Texture) -> Option { + match texture.pixel_format() { + MTLPixelFormat::R8Unorm => Some(TextureFormat::R8), + MTLPixelFormat::R16Float => Some(TextureFormat::R16F), + MTLPixelFormat::RGBA8Unorm => Some(TextureFormat::RGBA8), + _ => None, + } + } + + fn set_viewport(&self, encoder: &RenderCommandEncoderRef, viewport: &RectI) { + encoder.set_viewport(MTLViewport { + originX: viewport.origin().x() as f64, + originY: viewport.origin().y() as f64, + width: viewport.size().x() as f64, + height: viewport.size().y() as f64, + znear: 0.0, + zfar: 1.0, + }) + } + + fn synchronize_texture(&self, texture: &Texture) { + { + let command_buffers = self.command_buffers.borrow(); + let encoder = command_buffers.last().unwrap().new_blit_command_encoder(); + encoder.synchronize_resource(&texture); + encoder.end_encoding(); + } + + self.end_commands(); + self.begin_commands(); + } +} + +trait DeviceExtra { + fn create_depth_stencil_texture(&self, size: Vector2I) -> Texture; +} + +impl DeviceExtra for metal::Device { + fn create_depth_stencil_texture(&self, size: Vector2I) -> Texture { + let descriptor = TextureDescriptor::new(); + descriptor.set_texture_type(MTLTextureType::D2); + descriptor.set_pixel_format(MTLPixelFormat::Depth32Float_Stencil8); + descriptor.set_width(size.x() as u64); + descriptor.set_height(size.y() as u64); + descriptor.set_storage_mode(MTLStorageMode::Private); + descriptor.set_usage(MTLTextureUsage::Unknown); + self.new_texture(&descriptor) + } +} + +// Conversion helpers + +trait DepthFuncExt { + fn to_metal_compare_function(self) -> MTLCompareFunction; +} + +impl DepthFuncExt for DepthFunc { + fn to_metal_compare_function(self) -> MTLCompareFunction { + match self { + DepthFunc::Less => MTLCompareFunction::Less, + DepthFunc::Always => MTLCompareFunction::Always, + } + } +} + +trait PrimitiveExt { + fn to_metal_primitive(self) -> MTLPrimitiveType; +} + +impl PrimitiveExt for Primitive { + fn to_metal_primitive(self) -> MTLPrimitiveType { + match self { + Primitive::Triangles => MTLPrimitiveType::Triangle, + Primitive::Lines => MTLPrimitiveType::Line, + } + } +} + +trait StencilFuncExt { + fn to_metal_compare_function(self) -> MTLCompareFunction; +} + +impl StencilFuncExt for StencilFunc { + fn to_metal_compare_function(self) -> MTLCompareFunction { + match self { + StencilFunc::Always => MTLCompareFunction::Always, + StencilFunc::Equal => MTLCompareFunction::Equal, + } + } +} + +trait UniformDataExt { + fn as_bytes(&self) -> Option<&[u8]>; +} + +impl UniformDataExt for UniformData { + fn as_bytes(&self) -> Option<&[u8]> { + unsafe { + match *self { + UniformData::TextureUnit(_) => None, + UniformData::Int(ref data) => { + Some(slice::from_raw_parts(data as *const i32 as *const u8, 4 * 1)) + } + UniformData::Mat4(ref data) => { + Some(slice::from_raw_parts(&data[0] as *const F32x4 as *const u8, 4 * 16)) + } + UniformData::Vec2(ref data) => { + Some(slice::from_raw_parts(data as *const F32x4 as *const u8, 4 * 2)) + } + UniformData::Vec4(ref data) => { + Some(slice::from_raw_parts(data as *const F32x4 as *const u8, 4 * 4)) + } + } + } + } +} + +// Extra structs missing from `metal-rs` + +bitflags! { + struct MTLPipelineOption: NSUInteger { + const ArgumentInfo = 1 << 0; + const BufferTypeInfo = 1 << 1; + } +} + +// Extra objects missing from `metal-rs` + +struct ArgumentArray(*mut Object); + +impl Drop for ArgumentArray { + fn drop(&mut self) { + unsafe { msg_send![self.0, release] } + } +} + +impl ArgumentArray { + unsafe fn from_ptr(object: *mut Object) -> ArgumentArray { + ArgumentArray(msg_send![object, retain]) + } + + fn len(&self) -> u64 { + unsafe { msg_send![self.0, count] } + } + + fn object_at(&self, index: u64) -> Argument { + unsafe { + let argument: *mut MTLArgument = msg_send![self.0, objectAtIndex:index]; + Argument::from_ptr(msg_send![argument, retain]) + } + } +} + +struct SharedEvent(*mut Object); + +impl Drop for SharedEvent { + fn drop(&mut self) { + unsafe { msg_send![self.0, release] } + } +} + +impl SharedEvent { + fn notify_listener_at_value(&self, + listener: &SharedEventListener, + value: u64, + block: RcBlock<(*mut Object, u64), ()>) { + unsafe { + // If the block doesn't have a signature, this segfaults. + let block = &*block as + *const Block<(*mut Object, u64), ()> as + *mut Block<(*mut Object, u64), ()> as + *mut BlockBase<(*mut Object, u64), ()>; + (*block).flags |= BLOCK_HAS_SIGNATURE | BLOCK_HAS_COPY_DISPOSE; + (*block).extra = &BLOCK_EXTRA; + msg_send![self.0, notifyListener:listener.0 atValue:value block:block]; + mem::forget(block); + } + + extern "C" fn dtor(_: *mut BlockBase<(*mut Object, u64), ()>) {} + + static mut SIGNATURE: &[u8] = b"v16@?0Q8\0"; + static mut SIGNATURE_PTR: *const i8 = unsafe { &SIGNATURE[0] as *const u8 as *const i8 }; + static mut BLOCK_EXTRA: BlockExtra<(*mut Object, u64), ()> = BlockExtra { + unknown0: 0 as *mut i32, + unknown1: 0 as *mut i32, + unknown2: 0 as *mut i32, + dtor: dtor, + signature: unsafe { &SIGNATURE_PTR }, + }; + } +} + +struct SharedEventListener(*mut Object); + +impl Drop for SharedEventListener { + fn drop(&mut self) { + unsafe { msg_send![self.0, release] } + } +} + +impl SharedEventListener { + fn new() -> SharedEventListener { + unsafe { + let listener: *mut Object = msg_send![class!(MTLSharedEventListener), alloc]; + SharedEventListener(msg_send![listener, init]) + } + } +} + +struct VertexAttributeArray(*mut Object); + +impl Drop for VertexAttributeArray { + fn drop(&mut self) { + unsafe { msg_send![self.0, release] } + } +} + +impl VertexAttributeArray { + unsafe fn from_ptr(object: *mut Object) -> VertexAttributeArray { + VertexAttributeArray(msg_send![object, retain]) + } + + fn len(&self) -> u64 { + unsafe { msg_send![self.0, count] } + } + + fn object_at(&self, index: u64) -> &VertexAttributeRef { + unsafe { VertexAttributeRef::from_ptr(msg_send![self.0, objectAtIndex:index]) } + } +} + +// Extra methods missing from `metal-rs` + +trait CoreAnimationLayerExt { + fn device(&self) -> metal::Device; +} + +impl CoreAnimationLayerExt for CoreAnimationLayer { + fn device(&self) -> metal::Device { + unsafe { + let device: *mut MTLDevice = msg_send![self.as_ptr(), device]; + metal::Device::from_ptr(msg_send![device, retain]) + } + } +} + +trait CommandBufferExt { + fn encode_signal_event(&self, event: &SharedEvent, value: u64); +} + +impl CommandBufferExt for CommandBuffer { + fn encode_signal_event(&self, event: &SharedEvent, value: u64) { + unsafe { + msg_send![self.as_ptr(), encodeSignalEvent:event.0 value:value] + } + } +} + +trait DeviceExt { + // `new_render_pipeline_state_with_reflection()` in `metal-rs` doesn't correctly initialize the + // `reflection` argument. This is a better definition. + fn real_new_render_pipeline_state_with_reflection(&self, + descriptor: &RenderPipelineDescriptor, + options: MTLPipelineOption) + -> (RenderPipelineState, + RenderPipelineReflection); + fn new_shared_event(&self) -> SharedEvent; +} + +impl DeviceExt for metal::Device { + fn real_new_render_pipeline_state_with_reflection(&self, + descriptor: &RenderPipelineDescriptor, + options: MTLPipelineOption) + -> (RenderPipelineState, + RenderPipelineReflection) { + unsafe { + let mut reflection_ptr: *mut MTLRenderPipelineReflection = ptr::null_mut(); + let mut error_ptr: *mut Object = ptr::null_mut(); + let render_pipeline_state_ptr: *mut MTLRenderPipelineState = + msg_send![self.as_ptr(), + newRenderPipelineStateWithDescriptor:descriptor.as_ptr() + options:options + reflection:&mut reflection_ptr + error:&mut error_ptr]; + if !error_ptr.is_null() { + let description: CFStringRef = msg_send![error_ptr, description]; + panic!("Render pipeline state construction failed: {}", + CFString::wrap_under_get_rule(description).to_string()); + } + assert!(!render_pipeline_state_ptr.is_null()); + assert!(!reflection_ptr.is_null()); + (RenderPipelineState::from_ptr(render_pipeline_state_ptr), + RenderPipelineReflection::from_ptr(msg_send![reflection_ptr, retain])) + } + } + + fn new_shared_event(&self) -> SharedEvent { + unsafe { SharedEvent(msg_send![self.as_ptr(), newSharedEvent]) } + } +} + +trait FunctionExt { + // `vertex_attributes()` in `metal-rs` segfaults! This is a better definition. + fn real_vertex_attributes(&self) -> VertexAttributeArray; + fn new_argument_encoder_with_reflection(&self, buffer_index: u64) + -> (ArgumentEncoder, Argument); +} + +impl FunctionExt for Function { + fn real_vertex_attributes(&self) -> VertexAttributeArray { + unsafe { + VertexAttributeArray::from_ptr(msg_send![(*self).as_ptr(), vertexAttributes]) + } + } + + fn new_argument_encoder_with_reflection(&self, buffer_index: u64) + -> (ArgumentEncoder, Argument) { + unsafe { + let mut reflection = ptr::null_mut(); + let encoder: *mut MTLArgumentEncoder = + msg_send![self.as_ptr(), newArgumentEncoderWithBufferIndex:buffer_index + reflection:&mut reflection]; + (ArgumentEncoder::from_ptr(encoder), Argument::from_ptr(reflection)) + } + } +} + +trait RenderPipelineReflectionExt { + // `vertex_arguments()` in `metal-rs` segfaults! This is a better definition. + fn real_vertex_arguments(&self) -> ArgumentArray; + // `fragment_arguments()` in `metal-rs` segfaults! This is a better definition. + fn real_fragment_arguments(&self) -> ArgumentArray; +} + +impl RenderPipelineReflectionExt for RenderPipelineReflectionRef { + fn real_vertex_arguments(&self) -> ArgumentArray { + unsafe { ArgumentArray::from_ptr(msg_send![self.as_ptr(), vertexArguments]) } + } + + fn real_fragment_arguments(&self) -> ArgumentArray { + unsafe { ArgumentArray::from_ptr(msg_send![self.as_ptr(), fragmentArguments]) } + } +} + +trait StructMemberExt { + fn argument_index(&self) -> u64; +} + +impl StructMemberExt for StructMemberRef { + fn argument_index(&self) -> u64 { + unsafe { msg_send![self.as_ptr(), argumentIndex] } + } +} + +// Memory management helpers + +trait Retain { + type Owned; + fn retain(&self) -> Self::Owned; +} + +impl Retain for CommandBufferRef { + type Owned = CommandBuffer; + fn retain(&self) -> CommandBuffer { + unsafe { CommandBuffer::from_ptr(msg_send![self.as_ptr(), retain]) } + } +} + +impl Retain for CoreAnimationDrawableRef { + type Owned = CoreAnimationDrawable; + fn retain(&self) -> CoreAnimationDrawable { + unsafe { CoreAnimationDrawable::from_ptr(msg_send![self.as_ptr(), retain]) } + } +} + +impl Retain for CoreAnimationLayerRef { + type Owned = CoreAnimationLayer; + fn retain(&self) -> CoreAnimationLayer { + unsafe { CoreAnimationLayer::from_ptr(msg_send![self.as_ptr(), retain]) } + } +} + +impl Retain for RenderCommandEncoderRef { + type Owned = RenderCommandEncoder; + fn retain(&self) -> RenderCommandEncoder { + unsafe { RenderCommandEncoder::from_ptr(msg_send![self.as_ptr(), retain]) } + } +} + +impl Retain for RenderPassDescriptorRef { + type Owned = RenderPassDescriptor; + fn retain(&self) -> RenderPassDescriptor { + unsafe { RenderPassDescriptor::from_ptr(msg_send![self.as_ptr(), retain]) } + } +} + +impl Retain for StructTypeRef { + type Owned = StructType; + fn retain(&self) -> StructType { + unsafe { StructType::from_ptr(msg_send![self.as_ptr(), retain]) } + } +} + +impl Retain for TextureRef { + type Owned = Texture; + fn retain(&self) -> Texture { + unsafe { Texture::from_ptr(msg_send![self.as_ptr(), retain]) } + } +} + +impl Retain for VertexAttributeRef { + type Owned = VertexAttribute; + fn retain(&self) -> VertexAttribute { + unsafe { VertexAttribute::from_ptr(msg_send![self.as_ptr(), retain]) } + } +} + +impl Retain for VertexDescriptorRef { + type Owned = VertexDescriptor; + fn retain(&self) -> VertexDescriptor { + unsafe { VertexDescriptor::from_ptr(msg_send![self.as_ptr(), retain]) } + } +} + +// Extra block stuff not supported by `block` + +const BLOCK_HAS_COPY_DISPOSE: i32 = 0x02000000; +const BLOCK_HAS_SIGNATURE: i32 = 0x40000000; + +#[repr(C)] +struct BlockBase { + isa: *const Class, // 0x00 + flags: i32, // 0x08 + _reserved: i32, // 0x0c + invoke: unsafe extern fn(*mut Block, ...) -> R, // 0x10 + extra: *const BlockExtra, // 0x18 +} + +type BlockExtraDtor = extern "C" fn(*mut BlockBase); + +#[repr(C)] +struct BlockExtra { + unknown0: *mut i32, // 0x00 + unknown1: *mut i32, // 0x08 + unknown2: *mut i32, // 0x10 + dtor: BlockExtraDtor, // 0x18 + signature: *const *const i8, // 0x20 +} diff --git a/renderer/Cargo.toml b/renderer/Cargo.toml index 0a575b30..106c0bab 100644 --- a/renderer/Cargo.toml +++ b/renderer/Cargo.toml @@ -5,6 +5,7 @@ edition = "2018" authors = ["Patrick Walton "] [dependencies] +bitflags = "1.0" byteorder = "1.2" fixedbitset = "0.1" hashbrown = "0.1" diff --git a/renderer/src/builder.rs b/renderer/src/builder.rs index 73562f8d..ff054432 100644 --- a/renderer/src/builder.rs +++ b/renderer/src/builder.rs @@ -12,7 +12,7 @@ use crate::concurrent::executor::Executor; use crate::gpu_data::{AlphaTileBatchPrimitive, BuiltObject, FillBatchPrimitive, RenderCommand}; -use crate::options::{PreparedRenderOptions, RenderCommandListener}; +use crate::options::{PreparedBuildOptions, RenderCommandListener}; use crate::scene::Scene; use crate::tile_map::DenseTileMap; use crate::tiles::{self, TILE_HEIGHT, TILE_WIDTH, Tiler}; @@ -28,7 +28,7 @@ use std::u16; pub(crate) struct SceneBuilder<'a> { scene: &'a Scene, - built_options: &'a PreparedRenderOptions, + built_options: &'a PreparedBuildOptions, pub(crate) next_alpha_tile_index: AtomicUsize, pub(crate) z_buffer: ZBuffer, @@ -38,7 +38,7 @@ pub(crate) struct SceneBuilder<'a> { impl<'a> SceneBuilder<'a> { pub(crate) fn new( scene: &'a Scene, - built_options: &'a PreparedRenderOptions, + built_options: &'a PreparedBuildOptions, listener: Box, ) -> SceneBuilder<'a> { let effective_view_box = scene.effective_view_box(built_options); @@ -76,7 +76,7 @@ impl<'a> SceneBuilder<'a> { &self, path_index: usize, view_box: RectF, - built_options: &PreparedRenderOptions, + built_options: &PreparedBuildOptions, scene: &Scene, ) -> Vec { let path_object = &scene.paths[path_index]; diff --git a/renderer/src/concurrent/scene_proxy.rs b/renderer/src/concurrent/scene_proxy.rs index 09c0e38d..a85d3e89 100644 --- a/renderer/src/concurrent/scene_proxy.rs +++ b/renderer/src/concurrent/scene_proxy.rs @@ -22,7 +22,7 @@ use crate::concurrent::executor::Executor; use crate::gpu::renderer::Renderer; use crate::gpu_data::RenderCommand; -use crate::options::{RenderCommandListener, RenderOptions}; +use crate::options::{BuildOptions, RenderCommandListener}; use crate::scene::Scene; use pathfinder_geometry::basic::rect::RectF; use pathfinder_gpu::Device; @@ -59,15 +59,15 @@ impl SceneProxy { #[inline] pub fn build_with_listener(&self, - options: RenderOptions, + options: BuildOptions, listener: Box) { self.sender.send(MainToWorkerMsg::Build(options, listener)).unwrap(); } #[inline] - pub fn build_with_stream(&self, options: RenderOptions) -> RenderCommandStream { + pub fn build_with_stream(&self, options: BuildOptions) -> RenderCommandStream { let (sender, receiver) = mpsc::sync_channel(MAX_MESSAGES_IN_FLIGHT); - let listener = Box::new(move |command| sender.send(command).unwrap()); + let listener = Box::new(move |command| drop(sender.send(command))); self.build_with_listener(options, listener); RenderCommandStream::new(receiver) } @@ -81,11 +81,11 @@ impl SceneProxy { /// renderer.render_command(&command) /// } #[inline] - pub fn build_and_render(&self, renderer: &mut Renderer, options: RenderOptions) + pub fn build_and_render(&self, renderer: &mut Renderer, build_options: BuildOptions) where D: Device { renderer.begin_scene(); - for command in self.build_with_stream(options) { - renderer.render_command(&command) + for command in self.build_with_stream(build_options) { + renderer.render_command(&command); } renderer.end_scene(); } @@ -118,7 +118,7 @@ fn scene_thread(mut scene: Scene, enum MainToWorkerMsg { ReplaceScene(Scene), SetViewBox(RectF), - Build(RenderOptions, Box), + Build(BuildOptions, Box), GetSVG(Sender>), } diff --git a/renderer/src/gpu/mod.rs b/renderer/src/gpu/mod.rs index cc28fc80..a5e818e0 100644 --- a/renderer/src/gpu/mod.rs +++ b/renderer/src/gpu/mod.rs @@ -11,4 +11,5 @@ //! The GPU renderer for Pathfinder 3. pub mod debug; +pub mod options; pub mod renderer; diff --git a/renderer/src/gpu/options.rs b/renderer/src/gpu/options.rs new file mode 100644 index 00000000..04c9af59 --- /dev/null +++ b/renderer/src/gpu/options.rs @@ -0,0 +1,60 @@ +// pathfinder/renderer/src/gpu/options.rs +// +// Copyright © 2019 The Pathfinder Project Developers. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use pathfinder_geometry::basic::rect::RectI; +use pathfinder_geometry::basic::vector::Vector2I; +use pathfinder_geometry::color::ColorF; +use pathfinder_gpu::Device; + +/// Options that influence rendering. +#[derive(Default)] +pub struct RendererOptions { + pub background_color: Option, +} + +#[derive(Clone)] +pub enum DestFramebuffer +where + D: Device, +{ + Default { + viewport: RectI, + window_size: Vector2I, + }, + Other(D::Framebuffer), +} + +impl Default for DestFramebuffer where D: Device { + #[inline] + fn default() -> DestFramebuffer { + DestFramebuffer::Default { viewport: RectI::default(), window_size: Vector2I::default() } + } +} + +impl DestFramebuffer +where + D: Device, +{ + #[inline] + pub fn full_window(window_size: Vector2I) -> DestFramebuffer { + let viewport = RectI::new(Vector2I::default(), window_size); + DestFramebuffer::Default { viewport, window_size } + } + + #[inline] + pub fn window_size(&self, device: &D) -> Vector2I { + match *self { + DestFramebuffer::Default { window_size, .. } => window_size, + DestFramebuffer::Other(ref framebuffer) => { + device.texture_size(device.framebuffer_texture(framebuffer)) + } + } + } +} diff --git a/renderer/src/gpu/renderer.rs b/renderer/src/gpu/renderer.rs index 80bdc477..e616615e 100644 --- a/renderer/src/gpu/renderer.rs +++ b/renderer/src/gpu/renderer.rs @@ -9,6 +9,7 @@ // except according to those terms. use crate::gpu::debug::DebugUIPresenter; +use crate::gpu::options::{DestFramebuffer, RendererOptions}; use crate::gpu_data::{AlphaTileBatchPrimitive, FillBatchPrimitive, PaintData}; use crate::gpu_data::{RenderCommand, SolidTileBatchPrimitive}; use crate::post::DefringingKernel; @@ -18,10 +19,10 @@ use pathfinder_geometry::basic::rect::RectI; use pathfinder_geometry::basic::transform3d::Transform3DF; use pathfinder_geometry::color::ColorF; use pathfinder_gpu::resources::ResourceLoader; -use pathfinder_gpu::{BlendState, BufferData, BufferTarget, BufferUploadMode, ClearParams}; -use pathfinder_gpu::{DepthFunc, DepthState, Device, Primitive, RenderState, StencilFunc}; -use pathfinder_gpu::{StencilState, TextureFormat, UniformData, VertexAttrClass}; -use pathfinder_gpu::{VertexAttrDescriptor, VertexAttrType}; +use pathfinder_gpu::{BlendState, BufferData, BufferTarget, BufferUploadMode, ClearOps}; +use pathfinder_gpu::{DepthFunc, DepthState, Device, Primitive, RenderOptions, RenderState}; +use pathfinder_gpu::{RenderTarget, StencilFunc, StencilState, TextureFormat, UniformData}; +use pathfinder_gpu::{VertexAttrClass, VertexAttrDescriptor, VertexAttrType}; use pathfinder_simd::default::{F32x4, I32x4}; use std::cmp; use std::collections::VecDeque; @@ -30,7 +31,7 @@ use std::ops::{Add, Div}; use std::time::Duration; use std::u32; -static QUAD_VERTEX_POSITIONS: [u8; 8] = [0, 0, 1, 0, 1, 1, 0, 1]; +static QUAD_VERTEX_POSITIONS: [u16; 8] = [0, 0, 1, 0, 1, 1, 0, 1]; static QUAD_VERTEX_INDICES: [u32; 6] = [0, 1, 3, 1, 2, 3]; // FIXME(pcwalton): Shrink this again! @@ -39,7 +40,7 @@ const MASK_FRAMEBUFFER_HEIGHT: i32 = TILE_HEIGHT as i32 * 256; // TODO(pcwalton): Replace with `mem::size_of` calls? const FILL_INSTANCE_SIZE: usize = 8; -const SOLID_TILE_INSTANCE_SIZE: usize = 10; +const SOLID_TILE_INSTANCE_SIZE: usize = 12; const MASK_TILE_INSTANCE_SIZE: usize = 12; const MAX_FILLS_PER_BATCH: usize = 0x4000; @@ -53,6 +54,7 @@ where // Core data dest_framebuffer: DestFramebuffer, + options: RendererOptions, fill_program: FillProgram, solid_multicolor_tile_program: SolidTileMulticolorProgram, alpha_multicolor_tile_program: AlphaTileMulticolorProgram, @@ -84,7 +86,7 @@ where reprojection_vertex_array: ReprojectionVertexArray, // Rendering state - mask_framebuffer_cleared: bool, + framebuffer_flags: FramebufferFlags, buffered_fills: Vec, // Debug @@ -103,11 +105,11 @@ impl Renderer where D: Device, { - pub fn new( - device: D, - resources: &dyn ResourceLoader, - dest_framebuffer: DestFramebuffer, - ) -> Renderer { + pub fn new(device: D, + resources: &dyn ResourceLoader, + dest_framebuffer: DestFramebuffer, + options: RendererOptions) + -> Renderer { let fill_program = FillProgram::new(&device, resources); let solid_multicolor_tile_program = SolidTileMulticolorProgram::new(&device, resources); @@ -190,10 +192,11 @@ where let window_size = dest_framebuffer.window_size(&device); let debug_ui_presenter = DebugUIPresenter::new(&device, resources, window_size); - let renderer = Renderer { + Renderer { device, dest_framebuffer, + options, fill_program, solid_monochrome_tile_program, alpha_monochrome_tile_program, @@ -227,23 +230,18 @@ where free_timer_queries: vec![], debug_ui_presenter, - mask_framebuffer_cleared: false, + framebuffer_flags: FramebufferFlags::empty(), buffered_fills: vec![], render_mode: RenderMode::default(), use_depth: false, - }; - - // As a convenience, bind the destination framebuffer. - renderer.bind_dest_framebuffer(); - - renderer + } } pub fn begin_scene(&mut self) { + self.framebuffer_flags = FramebufferFlags::empty(); + self.device.begin_commands(); self.init_postprocessing_framebuffer(); - - self.mask_framebuffer_cleared = false; self.stats = RenderStats::default(); } @@ -258,8 +256,8 @@ where RenderCommand::AddPaintData(ref paint_data) => self.upload_paint_data(paint_data), RenderCommand::AddFills(ref fills) => self.add_fills(fills), RenderCommand::FlushFills => { - self.begin_composite_timer_query(); self.draw_buffered_fills(); + self.begin_composite_timer_query(); } RenderCommand::SolidTile(ref solid_tiles) => { let count = solid_tiles.len(); @@ -284,10 +282,11 @@ where self.end_composite_timer_query(); self.pending_timers.push_back(mem::replace(&mut self.current_timers, RenderTimers::new())); + + self.device.end_commands(); } pub fn draw_debug_ui(&self) { - self.bind_dest_framebuffer(); self.debug_ui_presenter.draw(&self.device); } @@ -297,19 +296,19 @@ where // Accumulate stage-0 time. let mut total_stage_0_time = Duration::new(0, 0); for timer_query in &timers.stage_0 { - if !self.device.timer_query_is_available(timer_query) { - return None; + match self.device.get_timer_query(timer_query) { + None => return None, + Some(stage_0_time) => total_stage_0_time += stage_0_time, } - total_stage_0_time += self.device.get_timer_query(timer_query); } // Get stage-1 time. let stage_1_time = { let stage_1_timer_query = timers.stage_1.as_ref().unwrap(); - if !self.device.timer_query_is_available(&stage_1_timer_query) { - return None; + match self.device.get_timer_query(stage_1_timer_query) { + None => return None, + Some(query) => query, } - self.device.get_timer_query(stage_1_timer_query) }; // Recycle all timer queries. @@ -333,6 +332,11 @@ where mem::replace(&mut self.dest_framebuffer, new_dest_framebuffer) } + #[inline] + pub fn set_options(&mut self, new_options: RendererOptions) { + self.options = new_options + } + #[inline] pub fn set_main_framebuffer_size(&mut self, new_framebuffer_size: Vector2I) { self.debug_ui_presenter.ui_presenter.set_framebuffer_size(new_framebuffer_size); @@ -396,24 +400,11 @@ where ); } - fn clear_mask_framebuffer(&mut self) { - self.device.bind_framebuffer(&self.mask_framebuffer); - - // TODO(pcwalton): Only clear the appropriate portion? - self.device.clear(&ClearParams { - color: Some(ColorF::transparent_black()), - ..ClearParams::default() - }); - } - fn add_fills(&mut self, mut fills: &[FillBatchPrimitive]) { if fills.is_empty() { return; } - let timer_query = self.allocate_timer_query(); - self.device.begin_timer_query(&timer_query); - self.stats.fill_count += fills.len(); while !fills.is_empty() { @@ -424,9 +415,6 @@ where self.draw_buffered_fills(); } } - - self.device.end_timer_query(&timer_query); - self.current_timers.stage_0.push(timer_query); } fn draw_buffered_fills(&mut self) { @@ -441,178 +429,184 @@ where BufferUploadMode::Dynamic, ); - if !self.mask_framebuffer_cleared { - self.clear_mask_framebuffer(); - self.mask_framebuffer_cleared = true; - } - - self.device.bind_framebuffer(&self.mask_framebuffer); - - self.device - .bind_vertex_array(&self.fill_vertex_array.vertex_array); - self.device.use_program(&self.fill_program.program); - self.device.set_uniform( - &self.fill_program.framebuffer_size_uniform, - UniformData::Vec2( - I32x4::new(MASK_FRAMEBUFFER_WIDTH, MASK_FRAMEBUFFER_HEIGHT, 0, 0).to_f32x4(), - ), - ); - self.device.set_uniform( - &self.fill_program.tile_size_uniform, - UniformData::Vec2(I32x4::new(TILE_WIDTH as i32, TILE_HEIGHT as i32, 0, 0).to_f32x4()), - ); - self.device.bind_texture(&self.area_lut_texture, 0); - self.device.set_uniform( - &self.fill_program.area_lut_uniform, - UniformData::TextureUnit(0), - ); - let render_state = RenderState { - blend: BlendState::RGBOneAlphaOne, - ..RenderState::default() + let mut clear_color = None; + if !self.framebuffer_flags.contains( + FramebufferFlags::MUST_PRESERVE_MASK_FRAMEBUFFER_CONTENTS) { + clear_color = Some(ColorF::default()); }; - debug_assert!(self.buffered_fills.len() <= u32::MAX as usize); - self.device.draw_elements_instanced( - Primitive::Triangles, - 6, - self.buffered_fills.len() as u32, - &render_state, - ); - self.buffered_fills.clear() + let timer_query = self.allocate_timer_query(); + self.device.begin_timer_query(&timer_query); + + debug_assert!(self.buffered_fills.len() <= u32::MAX as usize); + self.device.draw_elements_instanced(6, self.buffered_fills.len() as u32, &RenderState { + target: &RenderTarget::Framebuffer(&self.mask_framebuffer), + program: &self.fill_program.program, + vertex_array: &self.fill_vertex_array.vertex_array, + primitive: Primitive::Triangles, + textures: &[&self.area_lut_texture], + uniforms: &[ + (&self.fill_program.framebuffer_size_uniform, + UniformData::Vec2(I32x4::new(MASK_FRAMEBUFFER_WIDTH, + MASK_FRAMEBUFFER_HEIGHT, + 0, + 0).to_f32x4())), + (&self.fill_program.tile_size_uniform, + UniformData::Vec2(I32x4::new(TILE_WIDTH as i32, + TILE_HEIGHT as i32, + 0, + 0).to_f32x4())), + (&self.fill_program.area_lut_uniform, UniformData::TextureUnit(0)), + ], + viewport: self.mask_viewport(), + options: RenderOptions { + blend: BlendState::RGBOneAlphaOne, + clear_ops: ClearOps { color: clear_color, ..ClearOps::default() }, + ..RenderOptions::default() + }, + }); + + self.device.end_timer_query(&timer_query); + self.current_timers.stage_0.push(timer_query); + + self.framebuffer_flags.insert(FramebufferFlags::MUST_PRESERVE_MASK_FRAMEBUFFER_CONTENTS); + self.buffered_fills.clear(); } fn draw_alpha_tiles(&mut self, count: u32) { - self.bind_draw_framebuffer(); + let clear_color = self.clear_color_for_draw_operation(); let alpha_tile_vertex_array = self.alpha_tile_vertex_array(); let alpha_tile_program = self.alpha_tile_program(); - self.device - .bind_vertex_array(&alpha_tile_vertex_array.vertex_array); - self.device.use_program(&alpha_tile_program.program); - self.device.set_uniform( - &alpha_tile_program.framebuffer_size_uniform, - UniformData::Vec2(self.draw_viewport().size().to_f32().0), - ); - self.device.set_uniform( - &alpha_tile_program.tile_size_uniform, - UniformData::Vec2(I32x4::new(TILE_WIDTH as i32, TILE_HEIGHT as i32, 0, 0).to_f32x4()), - ); - self.device - .bind_texture(self.device.framebuffer_texture(&self.mask_framebuffer), 0); - self.device.set_uniform( - &alpha_tile_program.stencil_texture_uniform, - UniformData::TextureUnit(0), - ); - self.device.set_uniform( - &alpha_tile_program.stencil_texture_size_uniform, - UniformData::Vec2( - I32x4::new(MASK_FRAMEBUFFER_WIDTH, MASK_FRAMEBUFFER_HEIGHT, 0, 0).to_f32x4(), - ), - ); + let draw_viewport = self.draw_viewport(); + let mut textures = vec![self.device.framebuffer_texture(&self.mask_framebuffer)]; + let mut uniforms = vec![ + (&alpha_tile_program.framebuffer_size_uniform, + UniformData::Vec2(draw_viewport.size().to_f32().0)), + (&alpha_tile_program.tile_size_uniform, + UniformData::Vec2(I32x4::new(TILE_WIDTH as i32, + TILE_HEIGHT as i32, + 0, + 0).to_f32x4())), + (&alpha_tile_program.stencil_texture_uniform, UniformData::TextureUnit(0)), + (&alpha_tile_program.stencil_texture_size_uniform, + UniformData::Vec2(I32x4::new(MASK_FRAMEBUFFER_WIDTH, + MASK_FRAMEBUFFER_HEIGHT, + 0, + 0).to_f32x4())), + // FIXME(pcwalton): Fill this in properly! + (&alpha_tile_program.view_box_origin_uniform, UniformData::Vec2(F32x4::default())), + ]; match self.render_mode { RenderMode::Multicolor => { let paint_texture = self.paint_texture.as_ref().unwrap(); - self.device.bind_texture(paint_texture, 1); - self.device.set_uniform( - &self.alpha_multicolor_tile_program.paint_texture_uniform, - UniformData::TextureUnit(1), - ); - self.device.set_uniform( - &self.alpha_multicolor_tile_program.paint_texture_size_uniform, - UniformData::Vec2(self.device.texture_size(paint_texture).0.to_f32x4()) - ); + textures.push(paint_texture); + uniforms.push((&self.alpha_multicolor_tile_program.paint_texture_uniform, + UniformData::TextureUnit(1))); + uniforms.push((&self.alpha_multicolor_tile_program.paint_texture_size_uniform, + UniformData::Vec2(self.device + .texture_size(paint_texture) + .0 + .to_f32x4()))); } RenderMode::Monochrome { .. } if self.postprocessing_needed() => { - self.device.set_uniform( - &self.alpha_monochrome_tile_program.color_uniform, - UniformData::Vec4(F32x4::splat(1.0)), - ); + uniforms.push((&self.alpha_monochrome_tile_program.color_uniform, + UniformData::Vec4(F32x4::splat(1.0)))); } RenderMode::Monochrome { fg_color, .. } => { - self.device.set_uniform( - &self.alpha_monochrome_tile_program.color_uniform, - UniformData::Vec4(fg_color.0), - ); + uniforms.push((&self.alpha_monochrome_tile_program.color_uniform, + UniformData::Vec4(fg_color.0))); } } - // FIXME(pcwalton): Fill this in properly! - self.device.set_uniform( - &alpha_tile_program.view_box_origin_uniform, - UniformData::Vec2(F32x4::default()), - ); - let render_state = RenderState { - blend: BlendState::RGBSrcAlphaAlphaOneMinusSrcAlpha, - stencil: self.stencil_state(), - ..RenderState::default() - }; - self.device.draw_elements_instanced(Primitive::Triangles, 6, count, &render_state); + self.device.draw_elements_instanced(6, count, &RenderState { + target: &self.draw_render_target(), + program: &alpha_tile_program.program, + vertex_array: &alpha_tile_vertex_array.vertex_array, + primitive: Primitive::Triangles, + textures: &textures, + uniforms: &uniforms, + viewport: draw_viewport, + options: RenderOptions { + blend: BlendState::RGBSrcAlphaAlphaOneMinusSrcAlpha, + stencil: self.stencil_state(), + clear_ops: ClearOps { color: clear_color, ..ClearOps::default() }, + ..RenderOptions::default() + }, + }); + + self.preserve_draw_framebuffer(); } fn draw_solid_tiles(&mut self, count: u32) { - self.bind_draw_framebuffer(); + let clear_color = self.clear_color_for_draw_operation(); let solid_tile_vertex_array = self.solid_tile_vertex_array(); let solid_tile_program = self.solid_tile_program(); - self.device - .bind_vertex_array(&solid_tile_vertex_array.vertex_array); - self.device.use_program(&solid_tile_program.program); - self.device.set_uniform( - &solid_tile_program.framebuffer_size_uniform, - UniformData::Vec2(self.draw_viewport().size().0.to_f32x4()), - ); - self.device.set_uniform( - &solid_tile_program.tile_size_uniform, - UniformData::Vec2(I32x4::new(TILE_WIDTH as i32, TILE_HEIGHT as i32, 0, 0).to_f32x4()), - ); + let draw_viewport = self.draw_viewport(); + let mut textures = vec![]; + let mut uniforms = vec![ + (&solid_tile_program.framebuffer_size_uniform, + UniformData::Vec2(draw_viewport.size().0.to_f32x4())), + (&solid_tile_program.tile_size_uniform, + UniformData::Vec2(I32x4::new(TILE_WIDTH as i32, + TILE_HEIGHT as i32, + 0, + 0).to_f32x4())), + // FIXME(pcwalton): Fill this in properly! + (&solid_tile_program.view_box_origin_uniform, UniformData::Vec2(F32x4::default())), + ]; match self.render_mode { RenderMode::Multicolor => { let paint_texture = self.paint_texture.as_ref().unwrap(); - self.device.bind_texture(paint_texture, 0); - self.device.set_uniform( - &self - .solid_multicolor_tile_program - .paint_texture_uniform, - UniformData::TextureUnit(0), - ); - self.device.set_uniform( - &self - .solid_multicolor_tile_program - .paint_texture_size_uniform, - UniformData::Vec2(self.device.texture_size(paint_texture).0.to_f32x4()) - ); + textures.push(paint_texture); + uniforms.push((&self.solid_multicolor_tile_program.paint_texture_uniform, + UniformData::TextureUnit(0))); + uniforms.push((&self.solid_multicolor_tile_program.paint_texture_size_uniform, + UniformData::Vec2(self.device + .texture_size(paint_texture) + .0 + .to_f32x4()))); } RenderMode::Monochrome { .. } if self.postprocessing_needed() => { - self.device.set_uniform( - &self.solid_monochrome_tile_program.color_uniform, - UniformData::Vec4(F32x4::splat(1.0)), - ); + uniforms.push((&self.solid_monochrome_tile_program.color_uniform, + UniformData::Vec4(F32x4::splat(1.0)))); } RenderMode::Monochrome { fg_color, .. } => { - self.device.set_uniform( - &self.solid_monochrome_tile_program.color_uniform, - UniformData::Vec4(fg_color.0), - ); + uniforms.push((&self.solid_monochrome_tile_program.color_uniform, + UniformData::Vec4(fg_color.0))); } } - // FIXME(pcwalton): Fill this in properly! - self.device.set_uniform( - &solid_tile_program.view_box_origin_uniform, - UniformData::Vec2(F32x4::default()), - ); - let render_state = RenderState { - stencil: self.stencil_state(), - ..RenderState::default() - }; - self.device.draw_elements_instanced(Primitive::Triangles, 6, count, &render_state); + self.device.draw_elements_instanced(6, count, &RenderState { + target: &self.draw_render_target(), + program: &solid_tile_program.program, + vertex_array: &solid_tile_vertex_array.vertex_array, + primitive: Primitive::Triangles, + textures: &textures, + uniforms: &uniforms, + viewport: draw_viewport, + options: RenderOptions { + stencil: self.stencil_state(), + clear_ops: ClearOps { color: clear_color, ..ClearOps::default() }, + ..RenderOptions::default() + }, + }); + + self.preserve_draw_framebuffer(); } fn postprocess(&mut self) { + let mut clear_color = None; + if !self.framebuffer_flags + .contains(FramebufferFlags::MUST_PRESERVE_DEST_FRAMEBUFFER_CONTENTS) { + clear_color = self.options.background_color; + } + let (fg_color, bg_color, defringing_kernel, gamma_correction_enabled); match self.render_mode { RenderMode::Multicolor => return, @@ -629,62 +623,52 @@ where } } - self.bind_dest_framebuffer(); - - self.device - .bind_vertex_array(&self.postprocess_vertex_array.vertex_array); - self.device.use_program(&self.postprocess_program.program); - self.device.set_uniform( - &self.postprocess_program.framebuffer_size_uniform, - UniformData::Vec2(self.main_viewport().size().to_f32().0), - ); - match defringing_kernel { - Some(ref kernel) => { - self.device.set_uniform( - &self.postprocess_program.kernel_uniform, - UniformData::Vec4(F32x4::from_slice(&kernel.0)), - ); - } - None => { - self.device.set_uniform( - &self.postprocess_program.kernel_uniform, - UniformData::Vec4(F32x4::default()), - ); - } - } - let postprocess_source_framebuffer = self.postprocess_source_framebuffer.as_ref().unwrap(); let source_texture = self .device .framebuffer_texture(postprocess_source_framebuffer); let source_texture_size = self.device.texture_size(source_texture); - self.device.bind_texture(&source_texture, 0); - self.device.set_uniform( - &self.postprocess_program.source_uniform, - UniformData::TextureUnit(0), - ); - self.device.set_uniform( - &self.postprocess_program.source_size_uniform, - UniformData::Vec2(source_texture_size.0.to_f32x4()), - ); - self.device.bind_texture(&self.gamma_lut_texture, 1); - self.device.set_uniform( - &self.postprocess_program.gamma_lut_uniform, - UniformData::TextureUnit(1), - ); - self.device.set_uniform( - &self.postprocess_program.fg_color_uniform, - UniformData::Vec4(fg_color.0), - ); - self.device.set_uniform( - &self.postprocess_program.bg_color_uniform, - UniformData::Vec4(bg_color.0), - ); - self.device.set_uniform( - &self.postprocess_program.gamma_correction_enabled_uniform, - UniformData::Int(gamma_correction_enabled as i32), - ); - self.device.draw_arrays(Primitive::Triangles, 4, &RenderState::default()); + let main_viewport = self.main_viewport(); + + let mut uniforms = vec![ + (&self.postprocess_program.framebuffer_size_uniform, + UniformData::Vec2(main_viewport.size().to_f32().0)), + (&self.postprocess_program.source_uniform, UniformData::TextureUnit(0)), + (&self.postprocess_program.source_size_uniform, + UniformData::Vec2(source_texture_size.0.to_f32x4())), + (&self.postprocess_program.gamma_lut_uniform, UniformData::TextureUnit(1)), + (&self.postprocess_program.fg_color_uniform, UniformData::Vec4(fg_color.0)), + (&self.postprocess_program.bg_color_uniform, UniformData::Vec4(bg_color.0)), + (&self.postprocess_program.gamma_correction_enabled_uniform, + UniformData::Int(gamma_correction_enabled as i32)), + ]; + + match defringing_kernel { + Some(ref kernel) => { + uniforms.push((&self.postprocess_program.kernel_uniform, + UniformData::Vec4(F32x4::from_slice(&kernel.0)))); + } + None => { + uniforms.push((&self.postprocess_program.kernel_uniform, + UniformData::Vec4(F32x4::default()))); + } + } + + self.device.draw_arrays(4, &RenderState { + target: &self.dest_render_target(), + program: &self.postprocess_program.program, + vertex_array: &self.postprocess_vertex_array.vertex_array, + primitive: Primitive::Triangles, + textures: &[&source_texture, &self.gamma_lut_texture], + uniforms: &uniforms, + viewport: main_viewport, + options: RenderOptions { + clear_ops: ClearOps { color: clear_color, ..ClearOps::default() }, + ..RenderOptions::default() + }, + }); + + self.framebuffer_flags.insert(FramebufferFlags::MUST_PRESERVE_DEST_FRAMEBUFFER_CONTENTS); } fn solid_tile_program(&self) -> &SolidTileProgram { @@ -715,7 +699,7 @@ where } } - fn draw_stencil(&self, quad_positions: &[Vector4F]) { + fn draw_stencil(&mut self, quad_positions: &[Vector4F]) { self.device.allocate_buffer( &self.stencil_vertex_array.vertex_buffer, BufferData::Memory(quad_positions), @@ -736,19 +720,17 @@ where BufferUploadMode::Dynamic, ); - self.bind_draw_framebuffer(); - - self.device.bind_vertex_array(&self.stencil_vertex_array.vertex_array); - self.device.use_program(&self.stencil_program.program); - self.device.draw_elements( - Primitive::Triangles, - indices.len() as u32, - &RenderState { + self.device.draw_elements(indices.len() as u32, &RenderState { + target: &self.draw_render_target(), + program: &self.stencil_program.program, + vertex_array: &self.stencil_vertex_array.vertex_array, + primitive: Primitive::Triangles, + textures: &[], + uniforms: &[], + viewport: self.draw_viewport(), + options: RenderOptions { // FIXME(pcwalton): Should we really write to the depth buffer? - depth: Some(DepthState { - func: DepthFunc::Less, - write: true, - }), + depth: Some(DepthState { func: DepthFunc::Less, write: true }), stencil: Some(StencilState { func: StencilFunc::Always, reference: 1, @@ -756,63 +738,57 @@ where write: true, }), color_mask: false, - ..RenderState::default() + clear_ops: ClearOps { stencil: Some(0), ..ClearOps::default() }, + ..RenderOptions::default() }, - ) + }); } pub fn reproject_texture( - &self, + &mut self, texture: &D::Texture, old_transform: &Transform3DF, new_transform: &Transform3DF, ) { - self.bind_draw_framebuffer(); + let clear_color = self.clear_color_for_draw_operation(); - self.device.bind_vertex_array(&self.reprojection_vertex_array.vertex_array); - self.device.use_program(&self.reprojection_program.program); - self.device.set_uniform( - &self.reprojection_program.old_transform_uniform, - UniformData::from_transform_3d(old_transform), - ); - self.device.set_uniform( - &self.reprojection_program.new_transform_uniform, - UniformData::from_transform_3d(new_transform), - ); - self.device.bind_texture(texture, 0); - self.device.set_uniform( - &self.reprojection_program.texture_uniform, - UniformData::TextureUnit(0), - ); - self.device.draw_elements( - Primitive::Triangles, - 6, - &RenderState { + self.device.draw_elements(6, &RenderState { + target: &self.draw_render_target(), + program: &self.reprojection_program.program, + vertex_array: &self.reprojection_vertex_array.vertex_array, + primitive: Primitive::Triangles, + textures: &[texture], + uniforms: &[ + (&self.reprojection_program.old_transform_uniform, + UniformData::from_transform_3d(old_transform)), + (&self.reprojection_program.new_transform_uniform, + UniformData::from_transform_3d(new_transform)), + (&self.reprojection_program.texture_uniform, UniformData::TextureUnit(0)), + ], + viewport: self.draw_viewport(), + options: RenderOptions { blend: BlendState::RGBSrcAlphaAlphaOneMinusSrcAlpha, - depth: Some(DepthState { - func: DepthFunc::Less, - write: false, - }), - ..RenderState::default() + depth: Some(DepthState { func: DepthFunc::Less, write: false, }), + clear_ops: ClearOps { color: clear_color, ..ClearOps::default() }, + ..RenderOptions::default() }, - ); + }); + + self.preserve_draw_framebuffer(); } - pub fn bind_draw_framebuffer(&self) { + pub fn draw_render_target(&self) -> RenderTarget { if self.postprocessing_needed() { - self.device - .bind_framebuffer(self.postprocess_source_framebuffer.as_ref().unwrap()); + RenderTarget::Framebuffer(self.postprocess_source_framebuffer.as_ref().unwrap()) } else { - self.bind_dest_framebuffer(); + self.dest_render_target() } } - pub fn bind_dest_framebuffer(&self) { + pub fn dest_render_target(&self) -> RenderTarget { match self.dest_framebuffer { - DestFramebuffer::Default { viewport, .. } => { - self.device.bind_default_framebuffer(viewport) - } - DestFramebuffer::Other(ref framebuffer) => self.device.bind_framebuffer(framebuffer), + DestFramebuffer::Default { .. } => RenderTarget::Default, + DestFramebuffer::Other(ref framebuffer) => RenderTarget::Framebuffer(framebuffer), } } @@ -833,16 +809,21 @@ where let texture = self .device .create_texture(TextureFormat::R8, source_framebuffer_size); - self.postprocess_source_framebuffer = Some(self.device.create_framebuffer(texture)) + self.postprocess_source_framebuffer = + Some(self.device.create_framebuffer(texture)); } }; - self.device - .bind_framebuffer(self.postprocess_source_framebuffer.as_ref().unwrap()); - self.device.clear(&ClearParams { - color: Some(ColorF::transparent_black()), - ..ClearParams::default() - }); + /* + self.device.clear(&RenderTarget::Framebuffer(self.postprocess_source_framebuffer + .as_ref() + .unwrap()), + RectI::new(Vector2I::default(), source_framebuffer_size), + &ClearParams { + color: Some(ColorF::transparent_black()), + ..ClearParams::default() + }); + */ } fn postprocessing_needed(&self) -> bool { @@ -869,7 +850,33 @@ where }) } - fn draw_viewport(&self) -> RectI { + fn clear_color_for_draw_operation(&mut self) -> Option { + let postprocessing_needed = self.postprocessing_needed(); + let flag = if postprocessing_needed { + FramebufferFlags::MUST_PRESERVE_POSTPROCESS_FRAMEBUFFER_CONTENTS + } else { + FramebufferFlags::MUST_PRESERVE_DEST_FRAMEBUFFER_CONTENTS + }; + + if self.framebuffer_flags.contains(flag) { + None + } else if !postprocessing_needed { + self.options.background_color + } else { + Some(ColorF::default()) + } + } + + fn preserve_draw_framebuffer(&mut self) { + let flag = if self.postprocessing_needed() { + FramebufferFlags::MUST_PRESERVE_POSTPROCESS_FRAMEBUFFER_CONTENTS + } else { + FramebufferFlags::MUST_PRESERVE_DEST_FRAMEBUFFER_CONTENTS + }; + self.framebuffer_flags.insert(flag); + } + + pub fn draw_viewport(&self) -> RectI { let main_viewport = self.main_viewport(); match self.render_mode { RenderMode::Monochrome { @@ -895,6 +902,11 @@ where } } + fn mask_viewport(&self) -> RectI { + let texture = self.device.framebuffer_texture(&self.mask_framebuffer); + RectI::new(Vector2I::default(), self.device.texture_size(texture)) + } + fn allocate_timer_query(&mut self) -> D::TimerQuery { match self.free_timer_queries.pop() { Some(query) => query, @@ -909,8 +921,9 @@ where } fn end_composite_timer_query(&mut self) { - let query = self.current_timers.stage_1.as_ref().expect("No stage 1 timer query yet?!"); - self.device.end_timer_query(&query); + if let Some(ref query) = self.current_timers.stage_1 { + self.device.end_timer_query(query); + } } } @@ -951,59 +964,63 @@ where let to_subpx_attr = device.get_vertex_attr(&fill_program.program, "ToSubpx").unwrap(); let tile_index_attr = device.get_vertex_attr(&fill_program.program, "TileIndex").unwrap(); - device.bind_vertex_array(&vertex_array); - device.use_program(&fill_program.program); - device.bind_buffer(quad_vertex_positions_buffer, BufferTarget::Vertex); - device.configure_vertex_attr(&tess_coord_attr, &VertexAttrDescriptor { + device.bind_buffer(&vertex_array, quad_vertex_positions_buffer, BufferTarget::Vertex); + device.configure_vertex_attr(&vertex_array, &tess_coord_attr, &VertexAttrDescriptor { size: 2, - class: VertexAttrClass::Float, - attr_type: VertexAttrType::U8, - stride: 0, + class: VertexAttrClass::Int, + attr_type: VertexAttrType::U16, + stride: 4, offset: 0, divisor: 0, + buffer_index: 0, }); - device.bind_buffer(&vertex_buffer, BufferTarget::Vertex); - device.configure_vertex_attr(&from_px_attr, &VertexAttrDescriptor { + device.bind_buffer(&vertex_array, &vertex_buffer, BufferTarget::Vertex); + device.configure_vertex_attr(&vertex_array, &from_px_attr, &VertexAttrDescriptor { size: 1, class: VertexAttrClass::Int, attr_type: VertexAttrType::U8, stride: FILL_INSTANCE_SIZE, offset: 0, divisor: 1, + buffer_index: 1, }); - device.configure_vertex_attr(&to_px_attr, &VertexAttrDescriptor { + device.configure_vertex_attr(&vertex_array, &to_px_attr, &VertexAttrDescriptor { size: 1, class: VertexAttrClass::Int, attr_type: VertexAttrType::U8, stride: FILL_INSTANCE_SIZE, offset: 1, divisor: 1, + buffer_index: 1, }); - device.configure_vertex_attr(&from_subpx_attr, &VertexAttrDescriptor { + device.configure_vertex_attr(&vertex_array, &from_subpx_attr, &VertexAttrDescriptor { size: 2, class: VertexAttrClass::FloatNorm, attr_type: VertexAttrType::U8, stride: FILL_INSTANCE_SIZE, offset: 2, divisor: 1, + buffer_index: 1, }); - device.configure_vertex_attr(&to_subpx_attr, &VertexAttrDescriptor { + device.configure_vertex_attr(&vertex_array, &to_subpx_attr, &VertexAttrDescriptor { size: 2, class: VertexAttrClass::FloatNorm, attr_type: VertexAttrType::U8, stride: FILL_INSTANCE_SIZE, offset: 4, divisor: 1, + buffer_index: 1, }); - device.configure_vertex_attr(&tile_index_attr, &VertexAttrDescriptor { + device.configure_vertex_attr(&vertex_array, &tile_index_attr, &VertexAttrDescriptor { size: 1, class: VertexAttrClass::Int, attr_type: VertexAttrType::U16, stride: FILL_INSTANCE_SIZE, offset: 6, divisor: 1, + buffer_index: 1, }); - device.bind_buffer(quad_vertex_indices_buffer, BufferTarget::Index); + device.bind_buffer(&vertex_array, quad_vertex_indices_buffer, BufferTarget::Index); FillVertexArray { vertex_array, vertex_buffer } } @@ -1042,53 +1059,58 @@ where // NB: The object must be of type `I16`, not `U16`, to work around a macOS Radeon // driver bug. - device.bind_vertex_array(&vertex_array); - device.use_program(&alpha_tile_program.program); - device.bind_buffer(quad_vertex_positions_buffer, BufferTarget::Vertex); - device.configure_vertex_attr(&tess_coord_attr, &VertexAttrDescriptor { + device.bind_buffer(&vertex_array, quad_vertex_positions_buffer, BufferTarget::Vertex); + device.configure_vertex_attr(&vertex_array, &tess_coord_attr, &VertexAttrDescriptor { size: 2, - class: VertexAttrClass::Float, - attr_type: VertexAttrType::U8, - stride: 0, + class: VertexAttrClass::Int, + attr_type: VertexAttrType::U16, + stride: 4, offset: 0, divisor: 0, + buffer_index: 0, }); - device.bind_buffer(&vertex_buffer, BufferTarget::Vertex); - device.configure_vertex_attr(&tile_origin_attr, &VertexAttrDescriptor { + device.bind_buffer(&vertex_array, &vertex_buffer, BufferTarget::Vertex); + device.configure_vertex_attr(&vertex_array, &tile_origin_attr, &VertexAttrDescriptor { size: 3, class: VertexAttrClass::Int, attr_type: VertexAttrType::U8, stride: MASK_TILE_INSTANCE_SIZE, offset: 0, divisor: 1, + buffer_index: 1, }); - device.configure_vertex_attr(&backdrop_attr, &VertexAttrDescriptor { + device.configure_vertex_attr(&vertex_array, &backdrop_attr, &VertexAttrDescriptor { size: 1, class: VertexAttrClass::Int, attr_type: VertexAttrType::I8, stride: MASK_TILE_INSTANCE_SIZE, offset: 3, divisor: 1, + buffer_index: 1, }); - device.configure_vertex_attr(&tile_index_attr, &VertexAttrDescriptor { + device.configure_vertex_attr(&vertex_array, &tile_index_attr, &VertexAttrDescriptor { size: 1, class: VertexAttrClass::Int, attr_type: VertexAttrType::I16, stride: MASK_TILE_INSTANCE_SIZE, offset: 6, divisor: 1, + buffer_index: 1, }); if let Some(color_tex_coord_attr) = color_tex_coord_attr { - device.configure_vertex_attr(&color_tex_coord_attr, &VertexAttrDescriptor { - size: 2, - class: VertexAttrClass::FloatNorm, - attr_type: VertexAttrType::U16, - stride: MASK_TILE_INSTANCE_SIZE, - offset: 8, - divisor: 1, - }); + device.configure_vertex_attr(&vertex_array, + &color_tex_coord_attr, + &VertexAttrDescriptor { + size: 2, + class: VertexAttrClass::FloatNorm, + attr_type: VertexAttrType::U16, + stride: MASK_TILE_INSTANCE_SIZE, + offset: 8, + divisor: 1, + buffer_index: 1, + }); } - device.bind_buffer(quad_vertex_indices_buffer, BufferTarget::Index); + device.bind_buffer(&vertex_array, quad_vertex_indices_buffer, BufferTarget::Index); AlphaTileVertexArray { vertex_array, vertex_buffer } } @@ -1123,37 +1145,40 @@ where // NB: The object must be of type short, not unsigned short, to work around a macOS // Radeon driver bug. - device.bind_vertex_array(&vertex_array); - device.use_program(&solid_tile_program.program); - device.bind_buffer(quad_vertex_positions_buffer, BufferTarget::Vertex); - device.configure_vertex_attr(&tess_coord_attr, &VertexAttrDescriptor { + device.bind_buffer(&vertex_array, quad_vertex_positions_buffer, BufferTarget::Vertex); + device.configure_vertex_attr(&vertex_array, &tess_coord_attr, &VertexAttrDescriptor { size: 2, - class: VertexAttrClass::Float, - attr_type: VertexAttrType::U8, - stride: 0, + class: VertexAttrClass::Int, + attr_type: VertexAttrType::U16, + stride: 4, offset: 0, divisor: 0, + buffer_index: 0, }); - device.bind_buffer(&vertex_buffer, BufferTarget::Vertex); - device.configure_vertex_attr(&tile_origin_attr, &VertexAttrDescriptor { + device.bind_buffer(&vertex_array, &vertex_buffer, BufferTarget::Vertex); + device.configure_vertex_attr(&vertex_array, &tile_origin_attr, &VertexAttrDescriptor { size: 2, - class: VertexAttrClass::Float, + class: VertexAttrClass::Int, attr_type: VertexAttrType::I16, stride: SOLID_TILE_INSTANCE_SIZE, offset: 0, divisor: 1, + buffer_index: 1, }); if let Some(color_tex_coord_attr) = color_tex_coord_attr { - device.configure_vertex_attr(&color_tex_coord_attr, &VertexAttrDescriptor { - size: 2, - class: VertexAttrClass::FloatNorm, - attr_type: VertexAttrType::U16, - stride: SOLID_TILE_INSTANCE_SIZE, - offset: 4, - divisor: 1, - }); + device.configure_vertex_attr(&vertex_array, + &color_tex_coord_attr, + &VertexAttrDescriptor { + size: 2, + class: VertexAttrClass::FloatNorm, + attr_type: VertexAttrType::U16, + stride: SOLID_TILE_INSTANCE_SIZE, + offset: 4, + divisor: 1, + buffer_index: 1, + }); } - device.bind_buffer(quad_vertex_indices_buffer, BufferTarget::Index); + device.bind_buffer(&vertex_array, quad_vertex_indices_buffer, BufferTarget::Index); SolidTileVertexArray { vertex_array, vertex_buffer } } @@ -1235,10 +1260,10 @@ where { fn new(device: &D, resources: &dyn ResourceLoader) -> SolidTileMulticolorProgram { let solid_tile_program = SolidTileProgram::new(device, "tile_solid_multicolor", resources); - let paint_texture_uniform = - device.get_uniform(&solid_tile_program.program, "PaintTexture"); - let paint_texture_size_uniform = - device.get_uniform(&solid_tile_program.program, "PaintTextureSize"); + let paint_texture_uniform = device.get_uniform(&solid_tile_program.program, + "PaintTexture"); + let paint_texture_size_uniform = device.get_uniform(&solid_tile_program.program, + "PaintTextureSize"); SolidTileMulticolorProgram { solid_tile_program, paint_texture_uniform, @@ -1383,8 +1408,8 @@ where let framebuffer_size_uniform = device.get_uniform(&program, "FramebufferSize"); let kernel_uniform = device.get_uniform(&program, "Kernel"); let gamma_lut_uniform = device.get_uniform(&program, "GammaLUT"); - let gamma_correction_enabled_uniform = - device.get_uniform(&program, "GammaCorrectionEnabled"); + let gamma_correction_enabled_uniform = device.get_uniform(&program, + "GammaCorrectionEnabled"); let fg_color_uniform = device.get_uniform(&program, "FGColor"); let bg_color_uniform = device.get_uniform(&program, "BGColor"); PostprocessProgram { @@ -1422,18 +1447,17 @@ where let position_attr = device.get_vertex_attr(&postprocess_program.program, "Position") .unwrap(); - device.bind_vertex_array(&vertex_array); - device.use_program(&postprocess_program.program); - device.bind_buffer(quad_vertex_positions_buffer, BufferTarget::Vertex); - device.configure_vertex_attr(&position_attr, &VertexAttrDescriptor { + device.bind_buffer(&vertex_array, quad_vertex_positions_buffer, BufferTarget::Vertex); + device.configure_vertex_attr(&vertex_array, &position_attr, &VertexAttrDescriptor { size: 2, - class: VertexAttrClass::Float, - attr_type: VertexAttrType::U8, - stride: 0, + class: VertexAttrClass::Int, + attr_type: VertexAttrType::U16, + stride: 4, offset: 0, divisor: 0, + buffer_index: 0, }); - device.bind_buffer(quad_vertex_indices_buffer, BufferTarget::Index); + device.bind_buffer(&vertex_array, quad_vertex_indices_buffer, BufferTarget::Index); PostprocessVertexArray { vertex_array } } @@ -1474,18 +1498,18 @@ where let (vertex_buffer, index_buffer) = (device.create_buffer(), device.create_buffer()); let position_attr = device.get_vertex_attr(&stencil_program.program, "Position").unwrap(); - device.bind_vertex_array(&vertex_array); - device.use_program(&stencil_program.program); - device.bind_buffer(&vertex_buffer, BufferTarget::Vertex); - device.configure_vertex_attr(&position_attr, &VertexAttrDescriptor { + + device.bind_buffer(&vertex_array, &vertex_buffer, BufferTarget::Vertex); + device.configure_vertex_attr(&vertex_array, &position_attr, &VertexAttrDescriptor { size: 3, class: VertexAttrClass::Float, attr_type: VertexAttrType::F32, stride: 4 * 4, offset: 0, divisor: 0, + buffer_index: 0, }); - device.bind_buffer(&index_buffer, BufferTarget::Index); + device.bind_buffer(&vertex_array, &index_buffer, BufferTarget::Index); StencilVertexArray { vertex_array, vertex_buffer, index_buffer } } @@ -1538,58 +1562,25 @@ where quad_vertex_indices_buffer: &D::Buffer, ) -> ReprojectionVertexArray { let vertex_array = device.create_vertex_array(); - let position_attr = device.get_vertex_attr(&reprojection_program.program, "Position") .unwrap(); - device.bind_vertex_array(&vertex_array); - device.use_program(&reprojection_program.program); - device.bind_buffer(quad_vertex_positions_buffer, BufferTarget::Vertex); - device.configure_vertex_attr(&position_attr, &VertexAttrDescriptor { + + device.bind_buffer(&vertex_array, quad_vertex_positions_buffer, BufferTarget::Vertex); + device.configure_vertex_attr(&vertex_array, &position_attr, &VertexAttrDescriptor { size: 2, - class: VertexAttrClass::Float, - attr_type: VertexAttrType::U8, - stride: 0, + class: VertexAttrClass::Int, + attr_type: VertexAttrType::I16, + stride: 4, offset: 0, divisor: 0, + buffer_index: 0, }); - device.bind_buffer(quad_vertex_indices_buffer, BufferTarget::Index); + device.bind_buffer(&vertex_array, quad_vertex_indices_buffer, BufferTarget::Index); ReprojectionVertexArray { vertex_array } } } -#[derive(Clone)] -pub enum DestFramebuffer -where - D: Device, -{ - Default { - viewport: RectI, - window_size: Vector2I, - }, - Other(D::Framebuffer), -} - -impl DestFramebuffer -where - D: Device, -{ - #[inline] - pub fn full_window(window_size: Vector2I) -> DestFramebuffer { - let viewport = RectI::new(Vector2I::default(), window_size); - DestFramebuffer::Default { viewport, window_size } - } - - fn window_size(&self, device: &D) -> Vector2I { - match *self { - DestFramebuffer::Default { window_size, .. } => window_size, - DestFramebuffer::Other(ref framebuffer) => { - device.texture_size(device.framebuffer_texture(framebuffer)) - } - } - } -} - #[derive(Clone, Copy)] pub enum RenderMode { Multicolor, @@ -1675,3 +1666,11 @@ impl Add for RenderTime { } } } + +bitflags! { + struct FramebufferFlags: u8 { + const MUST_PRESERVE_MASK_FRAMEBUFFER_CONTENTS = 0x01; + const MUST_PRESERVE_POSTPROCESS_FRAMEBUFFER_CONTENTS = 0x02; + const MUST_PRESERVE_DEST_FRAMEBUFFER_CONTENTS = 0x04; + } +} diff --git a/renderer/src/gpu_data.rs b/renderer/src/gpu_data.rs index 76734d59..6c5045f7 100644 --- a/renderer/src/gpu_data.rs +++ b/renderer/src/gpu_data.rs @@ -75,6 +75,7 @@ pub struct SolidTileBatchPrimitive { pub origin_u: u16, pub origin_v: u16, pub object_index: u16, + pub pad: u16, } #[derive(Clone, Copy, Debug, Default)] diff --git a/renderer/src/lib.rs b/renderer/src/lib.rs index 0f80405e..ea7f7072 100644 --- a/renderer/src/lib.rs +++ b/renderer/src/lib.rs @@ -10,6 +10,8 @@ //! The CPU portion of Pathfinder's renderer. +#[macro_use] +extern crate bitflags; #[macro_use] extern crate log; diff --git a/renderer/src/options.rs b/renderer/src/options.rs index 2cb34fe6..32357c08 100644 --- a/renderer/src/options.rs +++ b/renderer/src/options.rs @@ -11,10 +11,10 @@ //! Options that control how rendering is to be performed. use crate::gpu_data::RenderCommand; -use pathfinder_geometry::basic::vector::{Vector2F, Vector4F}; use pathfinder_geometry::basic::rect::RectF; use pathfinder_geometry::basic::transform2d::Transform2DF; use pathfinder_geometry::basic::transform3d::Perspective; +use pathfinder_geometry::basic::vector::{Vector2F, Vector4F}; use pathfinder_geometry::clip::PolygonClipper3D; pub trait RenderCommandListener: Send + Sync { @@ -31,16 +31,17 @@ where } } +/// Options that influence scene building. #[derive(Clone, Default)] -pub struct RenderOptions { +pub struct BuildOptions { pub transform: RenderTransform, pub dilation: Vector2F, pub subpixel_aa_enabled: bool, } -impl RenderOptions { - pub(crate) fn prepare(self, bounds: RectF) -> PreparedRenderOptions { - PreparedRenderOptions { +impl BuildOptions { + pub(crate) fn prepare(self, bounds: RectF) -> PreparedBuildOptions { + PreparedBuildOptions { transform: self.transform.prepare(bounds), dilation: self.dilation, subpixel_aa_enabled: self.subpixel_aa_enabled, @@ -119,13 +120,13 @@ impl RenderTransform { } } -pub(crate) struct PreparedRenderOptions { +pub(crate) struct PreparedBuildOptions { pub(crate) transform: PreparedRenderTransform, pub(crate) dilation: Vector2F, pub(crate) subpixel_aa_enabled: bool, } -impl PreparedRenderOptions { +impl PreparedBuildOptions { #[inline] pub(crate) fn bounding_quad(&self) -> BoundingQuad { match self.transform { diff --git a/renderer/src/scene.rs b/renderer/src/scene.rs index 45cc1c44..db5319c6 100644 --- a/renderer/src/scene.rs +++ b/renderer/src/scene.rs @@ -12,8 +12,8 @@ use crate::builder::SceneBuilder; use crate::concurrent::executor::Executor; -use crate::options::{PreparedRenderOptions, PreparedRenderTransform}; -use crate::options::{RenderCommandListener, RenderOptions}; +use crate::options::{BuildOptions, PreparedBuildOptions}; +use crate::options::{PreparedRenderTransform, RenderCommandListener}; use crate::paint::{Paint, PaintId}; use hashbrown::HashMap; use pathfinder_geometry::basic::vector::Vector2F; @@ -89,7 +89,7 @@ impl Scene { pub(crate) fn apply_render_options( &self, original_outline: &Outline, - options: &PreparedRenderOptions, + options: &PreparedBuildOptions, ) -> Outline { let effective_view_box = self.effective_view_box(options); @@ -156,7 +156,7 @@ impl Scene { } #[inline] - pub(crate) fn effective_view_box(&self, render_options: &PreparedRenderOptions) -> RectF { + pub(crate) fn effective_view_box(&self, render_options: &PreparedBuildOptions) -> RectF { if render_options.subpixel_aa_enabled { self.view_box.scale_xy(Vector2F::new(3.0, 1.0)) } else { @@ -166,7 +166,7 @@ impl Scene { #[inline] pub fn build(&self, - options: RenderOptions, + options: BuildOptions, listener: Box, executor: &E) where E: Executor { diff --git a/renderer/src/z_buffer.rs b/renderer/src/z_buffer.rs index 889cc666..858a9e90 100644 --- a/renderer/src/z_buffer.rs +++ b/renderer/src/z_buffer.rs @@ -91,6 +91,7 @@ impl SolidTileBatchPrimitive { object_index: object_index, origin_u: origin_uv.x() as u16, origin_v: origin_uv.y() as u16, + pad: 0, } } } diff --git a/resources/shaders/gl3/debug_solid.fs.glsl b/resources/shaders/gl3/debug_solid.fs.glsl index eeaaf489..06550da6 100644 --- a/resources/shaders/gl3/debug_solid.fs.glsl +++ b/resources/shaders/gl3/debug_solid.fs.glsl @@ -1,4 +1,6 @@ #version {{version}} +// Automatically generated from files in pathfinder/shaders/. Do not edit! + diff --git a/resources/shaders/gl3/debug_solid.vs.glsl b/resources/shaders/gl3/debug_solid.vs.glsl index 3c38f3f7..a5ac2df8 100644 --- a/resources/shaders/gl3/debug_solid.vs.glsl +++ b/resources/shaders/gl3/debug_solid.vs.glsl @@ -1,4 +1,6 @@ #version {{version}} +// Automatically generated from files in pathfinder/shaders/. Do not edit! + @@ -14,10 +16,10 @@ precision highp float; uniform vec2 uFramebufferSize; -in vec2 aPosition; +in ivec2 aPosition; void main(){ - vec2 position = aPosition / uFramebufferSize * 2.0 - 1.0; + vec2 position = vec2(aPosition)/ uFramebufferSize * 2.0 - 1.0; gl_Position = vec4(position . x, - position . y, 0.0, 1.0); } diff --git a/resources/shaders/gl3/debug_texture.fs.glsl b/resources/shaders/gl3/debug_texture.fs.glsl index 9601adf2..5670374b 100644 --- a/resources/shaders/gl3/debug_texture.fs.glsl +++ b/resources/shaders/gl3/debug_texture.fs.glsl @@ -1,4 +1,6 @@ #version {{version}} +// Automatically generated from files in pathfinder/shaders/. Do not edit! + diff --git a/resources/shaders/gl3/debug_texture.vs.glsl b/resources/shaders/gl3/debug_texture.vs.glsl index b3b546d8..d037b869 100644 --- a/resources/shaders/gl3/debug_texture.vs.glsl +++ b/resources/shaders/gl3/debug_texture.vs.glsl @@ -1,4 +1,6 @@ #version {{version}} +// Automatically generated from files in pathfinder/shaders/. Do not edit! + @@ -15,14 +17,14 @@ precision highp float; uniform vec2 uFramebufferSize; uniform vec2 uTextureSize; -in vec2 aPosition; -in vec2 aTexCoord; +in ivec2 aPosition; +in ivec2 aTexCoord; out vec2 vTexCoord; void main(){ - vTexCoord = aTexCoord / uTextureSize; - vec2 position = aPosition / uFramebufferSize * 2.0 - 1.0; + vTexCoord = vec2(aTexCoord)/ uTextureSize; + vec2 position = vec2(aPosition)/ uFramebufferSize * 2.0 - 1.0; gl_Position = vec4(position . x, - position . y, 0.0, 1.0); } diff --git a/resources/shaders/gl3/demo_ground.fs.glsl b/resources/shaders/gl3/demo_ground.fs.glsl index 3bf84270..49dd50dc 100644 --- a/resources/shaders/gl3/demo_ground.fs.glsl +++ b/resources/shaders/gl3/demo_ground.fs.glsl @@ -1,4 +1,6 @@ #version {{version}} +// Automatically generated from files in pathfinder/shaders/. Do not edit! + diff --git a/resources/shaders/gl3/demo_ground.vs.glsl b/resources/shaders/gl3/demo_ground.vs.glsl index 418eb50a..4f216416 100644 --- a/resources/shaders/gl3/demo_ground.vs.glsl +++ b/resources/shaders/gl3/demo_ground.vs.glsl @@ -1,4 +1,6 @@ #version {{version}} +// Automatically generated from files in pathfinder/shaders/. Do not edit! + @@ -15,12 +17,12 @@ precision highp float; uniform mat4 uTransform; uniform int uGridlineCount; -in vec2 aPosition; +in ivec2 aPosition; out vec2 vTexCoord; void main(){ - vTexCoord = aPosition * float(uGridlineCount); - gl_Position = uTransform * vec4(aPosition . x, 0.0, aPosition . y, 1.0); + vTexCoord = vec2(aPosition * uGridlineCount); + gl_Position = uTransform * vec4(ivec4(aPosition . x, 0, aPosition . y, 1)); } diff --git a/resources/shaders/gl3/fill.fs.glsl b/resources/shaders/gl3/fill.fs.glsl index aeebe141..d70a93bd 100644 --- a/resources/shaders/gl3/fill.fs.glsl +++ b/resources/shaders/gl3/fill.fs.glsl @@ -1,4 +1,6 @@ #version {{version}} +// Automatically generated from files in pathfinder/shaders/. Do not edit! + diff --git a/resources/shaders/gl3/fill.vs.glsl b/resources/shaders/gl3/fill.vs.glsl index fac4560a..83314eb1 100644 --- a/resources/shaders/gl3/fill.vs.glsl +++ b/resources/shaders/gl3/fill.vs.glsl @@ -1,4 +1,6 @@ #version {{version}} +// Automatically generated from files in pathfinder/shaders/. Do not edit! + @@ -15,7 +17,7 @@ precision highp float; uniform vec2 uFramebufferSize; uniform vec2 uTileSize; -in vec2 aTessCoord; +in uvec2 aTessCoord; in uint aFromPx; in uint aToPx; in vec2 aFromSubpx; @@ -27,7 +29,7 @@ out vec2 vTo; vec2 computeTileOffset(uint tileIndex, float stencilTextureWidth){ uint tilesPerRow = uint(stencilTextureWidth / uTileSize . x); - uvec2 tileOffset = uvec2(aTileIndex % tilesPerRow, aTileIndex / tilesPerRow); + uvec2 tileOffset = uvec2(tileIndex % tilesPerRow, tileIndex / tilesPerRow); return vec2(tileOffset)* uTileSize; } @@ -38,11 +40,11 @@ void main(){ vec2 to = vec2(aToPx & 15u, aToPx >> 4u)+ aToSubpx; vec2 position; - if(aTessCoord . x < 0.5) + if(aTessCoord . x == 0u) position . x = floor(min(from . x, to . x)); else position . x = ceil(max(from . x, to . x)); - if(aTessCoord . y < 0.5) + if(aTessCoord . y == 0u) position . y = floor(min(from . y, to . y)); else position . y = uTileSize . y; @@ -50,6 +52,10 @@ void main(){ vFrom = from - position; vTo = to - position; - gl_Position = vec4((tileOrigin + position)/ uFramebufferSize * 2.0 - 1.0, 0.0, 1.0); + vec2 globalPosition =(tileOrigin + position)/ uFramebufferSize * 2.0 - 1.0; + + + + gl_Position = vec4(globalPosition, 0.0, 1.0); } diff --git a/resources/shaders/gl3/post.fs.glsl b/resources/shaders/gl3/post.fs.glsl index 0a74556b..b9de3d7b 100644 --- a/resources/shaders/gl3/post.fs.glsl +++ b/resources/shaders/gl3/post.fs.glsl @@ -1,4 +1,6 @@ #version {{version}} +// Automatically generated from files in pathfinder/shaders/. Do not edit! + diff --git a/resources/shaders/gl3/post.vs.glsl b/resources/shaders/gl3/post.vs.glsl index 29e75ade..b30dcf8d 100644 --- a/resources/shaders/gl3/post.vs.glsl +++ b/resources/shaders/gl3/post.vs.glsl @@ -1,4 +1,6 @@ #version {{version}} +// Automatically generated from files in pathfinder/shaders/. Do not edit! + @@ -12,12 +14,12 @@ precision highp float; -in vec2 aPosition; +in ivec2 aPosition; out vec2 vTexCoord; void main(){ - vTexCoord = aPosition; - gl_Position = vec4(aPosition * 2.0 - 1.0, 0.0, 1.0); + vTexCoord = vec2(aPosition); + gl_Position = vec4(vec2(aPosition)* 2.0 - 1.0, 0.0, 1.0); } diff --git a/resources/shaders/gl3/reproject.fs.glsl b/resources/shaders/gl3/reproject.fs.glsl index 427b632c..f1344a2e 100644 --- a/resources/shaders/gl3/reproject.fs.glsl +++ b/resources/shaders/gl3/reproject.fs.glsl @@ -1,4 +1,6 @@ #version {{version}} +// Automatically generated from files in pathfinder/shaders/. Do not edit! + diff --git a/resources/shaders/gl3/reproject.vs.glsl b/resources/shaders/gl3/reproject.vs.glsl index d1c70544..35a3db40 100644 --- a/resources/shaders/gl3/reproject.vs.glsl +++ b/resources/shaders/gl3/reproject.vs.glsl @@ -1,4 +1,6 @@ #version {{version}} +// Automatically generated from files in pathfinder/shaders/. Do not edit! + @@ -14,12 +16,17 @@ precision highp float; uniform mat4 uNewTransform; -in vec2 aPosition; +in ivec2 aPosition; out vec2 vTexCoord; void main(){ - vTexCoord = aPosition; - gl_Position = uNewTransform * vec4(aPosition, 0.0, 1.0); + vec2 position = vec2(aPosition); + vTexCoord = position; + + + + + gl_Position = uNewTransform * vec4(position, 0.0, 1.0); } diff --git a/resources/shaders/gl3/stencil.fs.glsl b/resources/shaders/gl3/stencil.fs.glsl index e2e093ab..b37ee045 100644 --- a/resources/shaders/gl3/stencil.fs.glsl +++ b/resources/shaders/gl3/stencil.fs.glsl @@ -1,4 +1,6 @@ #version {{version}} +// Automatically generated from files in pathfinder/shaders/. Do not edit! + diff --git a/resources/shaders/gl3/stencil.vs.glsl b/resources/shaders/gl3/stencil.vs.glsl index 2fee81a2..0f44276e 100644 --- a/resources/shaders/gl3/stencil.vs.glsl +++ b/resources/shaders/gl3/stencil.vs.glsl @@ -1,4 +1,6 @@ #version {{version}} +// Automatically generated from files in pathfinder/shaders/. Do not edit! + diff --git a/resources/shaders/gl3/tile_alpha.fs.glsl b/resources/shaders/gl3/tile_alpha.fs.glsl index 3af9cf4d..0e7247d7 100644 --- a/resources/shaders/gl3/tile_alpha.fs.glsl +++ b/resources/shaders/gl3/tile_alpha.fs.glsl @@ -1,4 +1,6 @@ #version {{version}} +// Automatically generated from files in pathfinder/shaders/. Do not edit! + diff --git a/resources/shaders/gl3/tile_alpha_monochrome.vs.glsl b/resources/shaders/gl3/tile_alpha_monochrome.vs.glsl index d99d7dd7..df40901e 100644 --- a/resources/shaders/gl3/tile_alpha_monochrome.vs.glsl +++ b/resources/shaders/gl3/tile_alpha_monochrome.vs.glsl @@ -1,4 +1,6 @@ #version {{version}} +// Automatically generated from files in pathfinder/shaders/. Do not edit! + @@ -30,10 +32,10 @@ uniform vec2 uTileSize; uniform vec2 uStencilTextureSize; uniform vec2 uViewBoxOrigin; -in vec2 aTessCoord; +in uvec2 aTessCoord; in uvec3 aTileOrigin; in int aBackdrop; -in uint aTileIndex; +in int aTileIndex; out vec2 vTexCoord; out float vBackdrop; @@ -49,9 +51,9 @@ vec2 computeTileOffset(uint tileIndex, float stencilTextureWidth){ void computeVaryings(){ vec2 origin = vec2(aTileOrigin . xy)+ vec2(aTileOrigin . z & 15u, aTileOrigin . z >> 4u)* 256.0; - vec2 pixelPosition =(origin + aTessCoord)* uTileSize + uViewBoxOrigin; + vec2 pixelPosition =(origin + vec2(aTessCoord))* uTileSize + uViewBoxOrigin; vec2 position =(pixelPosition / uFramebufferSize * 2.0 - 1.0)* vec2(1.0, - 1.0); - vec2 maskTexCoordOrigin = computeTileOffset(aTileIndex, uStencilTextureSize . x); + vec2 maskTexCoordOrigin = computeTileOffset(uint(aTileIndex), uStencilTextureSize . x); vec2 maskTexCoord = maskTexCoordOrigin + aTessCoord * uTileSize; vTexCoord = maskTexCoord / uStencilTextureSize; diff --git a/resources/shaders/gl3/tile_alpha_multicolor.vs.glsl b/resources/shaders/gl3/tile_alpha_multicolor.vs.glsl index be655748..2adf4dc3 100644 --- a/resources/shaders/gl3/tile_alpha_multicolor.vs.glsl +++ b/resources/shaders/gl3/tile_alpha_multicolor.vs.glsl @@ -1,4 +1,6 @@ #version {{version}} +// Automatically generated from files in pathfinder/shaders/. Do not edit! + @@ -30,10 +32,10 @@ uniform vec2 uTileSize; uniform vec2 uStencilTextureSize; uniform vec2 uViewBoxOrigin; -in vec2 aTessCoord; +in uvec2 aTessCoord; in uvec3 aTileOrigin; in int aBackdrop; -in uint aTileIndex; +in int aTileIndex; out vec2 vTexCoord; out float vBackdrop; @@ -49,9 +51,9 @@ vec2 computeTileOffset(uint tileIndex, float stencilTextureWidth){ void computeVaryings(){ vec2 origin = vec2(aTileOrigin . xy)+ vec2(aTileOrigin . z & 15u, aTileOrigin . z >> 4u)* 256.0; - vec2 pixelPosition =(origin + aTessCoord)* uTileSize + uViewBoxOrigin; + vec2 pixelPosition =(origin + vec2(aTessCoord))* uTileSize + uViewBoxOrigin; vec2 position =(pixelPosition / uFramebufferSize * 2.0 - 1.0)* vec2(1.0, - 1.0); - vec2 maskTexCoordOrigin = computeTileOffset(aTileIndex, uStencilTextureSize . x); + vec2 maskTexCoordOrigin = computeTileOffset(uint(aTileIndex), uStencilTextureSize . x); vec2 maskTexCoord = maskTexCoordOrigin + aTessCoord * uTileSize; vTexCoord = maskTexCoord / uStencilTextureSize; diff --git a/resources/shaders/gl3/tile_solid.fs.glsl b/resources/shaders/gl3/tile_solid.fs.glsl index 2079d945..f8f8f7a7 100644 --- a/resources/shaders/gl3/tile_solid.fs.glsl +++ b/resources/shaders/gl3/tile_solid.fs.glsl @@ -1,4 +1,6 @@ #version {{version}} +// Automatically generated from files in pathfinder/shaders/. Do not edit! + diff --git a/resources/shaders/gl3/tile_solid_monochrome.vs.glsl b/resources/shaders/gl3/tile_solid_monochrome.vs.glsl index d7544c26..c0808cbd 100644 --- a/resources/shaders/gl3/tile_solid_monochrome.vs.glsl +++ b/resources/shaders/gl3/tile_solid_monochrome.vs.glsl @@ -1,4 +1,6 @@ #version {{version}} +// Automatically generated from files in pathfinder/shaders/. Do not edit! + @@ -29,19 +31,18 @@ uniform vec2 uFramebufferSize; uniform vec2 uTileSize; uniform vec2 uViewBoxOrigin; -in vec2 aTessCoord; -in vec2 aTileOrigin; +in uvec2 aTessCoord; +in ivec2 aTileOrigin; out vec4 vColor; vec4 getColor(); void computeVaryings(){ - vec2 pixelPosition =(aTileOrigin + aTessCoord)* uTileSize + uViewBoxOrigin; + vec2 pixelPosition = vec2(aTileOrigin + ivec2(aTessCoord))* uTileSize + uViewBoxOrigin; vec2 position =(pixelPosition / uFramebufferSize * 2.0 - 1.0)* vec2(1.0, - 1.0); vColor = getColor(); - gl_Position = vec4(position, 0.0, 1.0); } diff --git a/resources/shaders/gl3/tile_solid_multicolor.vs.glsl b/resources/shaders/gl3/tile_solid_multicolor.vs.glsl index 0e23e0a4..4ff5208c 100644 --- a/resources/shaders/gl3/tile_solid_multicolor.vs.glsl +++ b/resources/shaders/gl3/tile_solid_multicolor.vs.glsl @@ -1,4 +1,6 @@ #version {{version}} +// Automatically generated from files in pathfinder/shaders/. Do not edit! + @@ -29,19 +31,18 @@ uniform vec2 uFramebufferSize; uniform vec2 uTileSize; uniform vec2 uViewBoxOrigin; -in vec2 aTessCoord; -in vec2 aTileOrigin; +in uvec2 aTessCoord; +in ivec2 aTileOrigin; out vec4 vColor; vec4 getColor(); void computeVaryings(){ - vec2 pixelPosition =(aTileOrigin + aTessCoord)* uTileSize + uViewBoxOrigin; + vec2 pixelPosition = vec2(aTileOrigin + ivec2(aTessCoord))* uTileSize + uViewBoxOrigin; vec2 position =(pixelPosition / uFramebufferSize * 2.0 - 1.0)* vec2(1.0, - 1.0); vColor = getColor(); - gl_Position = vec4(position, 0.0, 1.0); } diff --git a/resources/shaders/metal/debug_solid.fs.metal b/resources/shaders/metal/debug_solid.fs.metal index 6fc13e2f..49f35a94 100644 --- a/resources/shaders/metal/debug_solid.fs.metal +++ b/resources/shaders/metal/debug_solid.fs.metal @@ -1,17 +1,23 @@ +// Automatically generated from files in pathfinder/shaders/. Do not edit! #include #include using namespace metal; +struct spvDescriptorSetBuffer0 +{ + constant float4* uColor [[id(0)]]; +}; + struct main0_out { float4 oFragColor [[color(0)]]; }; -fragment main0_out main0(float4 uColor [[buffer(0)]]) +fragment main0_out main0(constant spvDescriptorSetBuffer0& spvDescriptorSet0 [[buffer(0)]]) { main0_out out = {}; - out.oFragColor = float4(uColor.xyz, 1.0) * uColor.w; + out.oFragColor = float4((*spvDescriptorSet0.uColor).xyz, 1.0) * (*spvDescriptorSet0.uColor).w; return out; } diff --git a/resources/shaders/metal/debug_solid.vs.metal b/resources/shaders/metal/debug_solid.vs.metal index bcad2a03..ec9d440f 100644 --- a/resources/shaders/metal/debug_solid.vs.metal +++ b/resources/shaders/metal/debug_solid.vs.metal @@ -1,8 +1,14 @@ +// Automatically generated from files in pathfinder/shaders/. Do not edit! #include #include using namespace metal; +struct spvDescriptorSetBuffer0 +{ + constant float2* uFramebufferSize [[id(0)]]; +}; + struct main0_out { float4 gl_Position [[position]]; @@ -10,13 +16,13 @@ struct main0_out struct main0_in { - float2 aPosition [[attribute(0)]]; + int2 aPosition [[attribute(0)]]; }; -vertex main0_out main0(main0_in in [[stage_in]], float2 uFramebufferSize [[buffer(0)]], uint gl_VertexID [[vertex_id]], uint gl_InstanceID [[instance_id]]) +vertex main0_out main0(main0_in in [[stage_in]], constant spvDescriptorSetBuffer0& spvDescriptorSet0 [[buffer(0)]]) { main0_out out = {}; - float2 position = ((in.aPosition / uFramebufferSize) * 2.0) - float2(1.0); + float2 position = ((float2(in.aPosition) / (*spvDescriptorSet0.uFramebufferSize)) * 2.0) - float2(1.0); out.gl_Position = float4(position.x, -position.y, 0.0, 1.0); return out; } diff --git a/resources/shaders/metal/debug_texture.fs.metal b/resources/shaders/metal/debug_texture.fs.metal index 67bc2370..9949a558 100644 --- a/resources/shaders/metal/debug_texture.fs.metal +++ b/resources/shaders/metal/debug_texture.fs.metal @@ -1,8 +1,16 @@ +// Automatically generated from files in pathfinder/shaders/. Do not edit! #include #include using namespace metal; +struct spvDescriptorSetBuffer0 +{ + constant float4* uColor [[id(0)]]; + texture2d uTexture [[id(1)]]; + sampler uTextureSmplr [[id(2)]]; +}; + struct main0_out { float4 oFragColor [[color(0)]]; @@ -13,11 +21,11 @@ struct main0_in float2 vTexCoord [[user(locn0)]]; }; -fragment main0_out main0(main0_in in [[stage_in]], float4 uColor [[buffer(0)]], texture2d uTexture [[texture(0)]], sampler uTextureSmplr [[sampler(0)]]) +fragment main0_out main0(main0_in in [[stage_in]], constant spvDescriptorSetBuffer0& spvDescriptorSet0 [[buffer(0)]]) { main0_out out = {}; - float alpha = uTexture.sample(uTextureSmplr, in.vTexCoord).x * uColor.w; - out.oFragColor = float4(uColor.xyz, 1.0) * alpha; + float alpha = spvDescriptorSet0.uTexture.sample(spvDescriptorSet0.uTextureSmplr, in.vTexCoord).x * (*spvDescriptorSet0.uColor).w; + out.oFragColor = float4((*spvDescriptorSet0.uColor).xyz, 1.0) * alpha; return out; } diff --git a/resources/shaders/metal/debug_texture.vs.metal b/resources/shaders/metal/debug_texture.vs.metal index 25eb20b8..87a31507 100644 --- a/resources/shaders/metal/debug_texture.vs.metal +++ b/resources/shaders/metal/debug_texture.vs.metal @@ -1,8 +1,15 @@ +// Automatically generated from files in pathfinder/shaders/. Do not edit! #include #include using namespace metal; +struct spvDescriptorSetBuffer0 +{ + constant float2* uTextureSize [[id(0)]]; + constant float2* uFramebufferSize [[id(1)]]; +}; + struct main0_out { float2 vTexCoord [[user(locn0)]]; @@ -11,15 +18,15 @@ struct main0_out struct main0_in { - float2 aPosition [[attribute(0)]]; - float2 aTexCoord [[attribute(1)]]; + int2 aPosition [[attribute(0)]]; + int2 aTexCoord [[attribute(1)]]; }; -vertex main0_out main0(main0_in in [[stage_in]], float2 uTextureSize [[buffer(0)]], float2 uFramebufferSize [[buffer(1)]], uint gl_VertexID [[vertex_id]], uint gl_InstanceID [[instance_id]]) +vertex main0_out main0(main0_in in [[stage_in]], constant spvDescriptorSetBuffer0& spvDescriptorSet0 [[buffer(0)]]) { main0_out out = {}; - out.vTexCoord = in.aTexCoord / uTextureSize; - float2 position = ((in.aPosition / uFramebufferSize) * 2.0) - float2(1.0); + out.vTexCoord = float2(in.aTexCoord) / (*spvDescriptorSet0.uTextureSize); + float2 position = ((float2(in.aPosition) / (*spvDescriptorSet0.uFramebufferSize)) * 2.0) - float2(1.0); out.gl_Position = float4(position.x, -position.y, 0.0, 1.0); return out; } diff --git a/resources/shaders/metal/demo_ground.fs.metal b/resources/shaders/metal/demo_ground.fs.metal index 919b2f37..1b64111f 100644 --- a/resources/shaders/metal/demo_ground.fs.metal +++ b/resources/shaders/metal/demo_ground.fs.metal @@ -1,8 +1,15 @@ +// Automatically generated from files in pathfinder/shaders/. Do not edit! #include #include using namespace metal; +struct spvDescriptorSetBuffer0 +{ + constant float4* uGridlineColor [[id(0)]]; + constant float4* uGroundColor [[id(1)]]; +}; + struct main0_out { float4 oFragColor [[color(0)]]; @@ -13,12 +20,12 @@ struct main0_in float2 vTexCoord [[user(locn0)]]; }; -fragment main0_out main0(main0_in in [[stage_in]], float4 uGridlineColor [[buffer(0)]], float4 uGroundColor [[buffer(1)]]) +fragment main0_out main0(main0_in in [[stage_in]], constant spvDescriptorSetBuffer0& spvDescriptorSet0 [[buffer(0)]]) { main0_out out = {}; float2 texCoordPx = fract(in.vTexCoord) / fwidth(in.vTexCoord); bool4 _33 = bool4(any(texCoordPx <= float2(1.0))); - out.oFragColor = float4(_33.x ? uGridlineColor.x : uGroundColor.x, _33.y ? uGridlineColor.y : uGroundColor.y, _33.z ? uGridlineColor.z : uGroundColor.z, _33.w ? uGridlineColor.w : uGroundColor.w); + out.oFragColor = float4(_33.x ? (*spvDescriptorSet0.uGridlineColor).x : (*spvDescriptorSet0.uGroundColor).x, _33.y ? (*spvDescriptorSet0.uGridlineColor).y : (*spvDescriptorSet0.uGroundColor).y, _33.z ? (*spvDescriptorSet0.uGridlineColor).z : (*spvDescriptorSet0.uGroundColor).z, _33.w ? (*spvDescriptorSet0.uGridlineColor).w : (*spvDescriptorSet0.uGroundColor).w); return out; } diff --git a/resources/shaders/metal/demo_ground.vs.metal b/resources/shaders/metal/demo_ground.vs.metal index 049083ea..997185f5 100644 --- a/resources/shaders/metal/demo_ground.vs.metal +++ b/resources/shaders/metal/demo_ground.vs.metal @@ -1,8 +1,15 @@ +// Automatically generated from files in pathfinder/shaders/. Do not edit! #include #include using namespace metal; +struct spvDescriptorSetBuffer0 +{ + constant int* uGridlineCount [[id(0)]]; + constant float4x4* uTransform [[id(1)]]; +}; + struct main0_out { float2 vTexCoord [[user(locn0)]]; @@ -11,14 +18,14 @@ struct main0_out struct main0_in { - float2 aPosition [[attribute(0)]]; + int2 aPosition [[attribute(0)]]; }; -vertex main0_out main0(main0_in in [[stage_in]], int uGridlineCount [[buffer(0)]], float4x4 uTransform [[buffer(1)]], uint gl_VertexID [[vertex_id]], uint gl_InstanceID [[instance_id]]) +vertex main0_out main0(main0_in in [[stage_in]], constant spvDescriptorSetBuffer0& spvDescriptorSet0 [[buffer(0)]]) { main0_out out = {}; - out.vTexCoord = in.aPosition * float(uGridlineCount); - out.gl_Position = uTransform * float4(in.aPosition.x, 0.0, in.aPosition.y, 1.0); + out.vTexCoord = float2(in.aPosition * int2((*spvDescriptorSet0.uGridlineCount))); + out.gl_Position = (*spvDescriptorSet0.uTransform) * float4(int4(in.aPosition.x, 0, in.aPosition.y, 1)); return out; } diff --git a/resources/shaders/metal/fill.fs.metal b/resources/shaders/metal/fill.fs.metal index d002bba6..bfa765e5 100644 --- a/resources/shaders/metal/fill.fs.metal +++ b/resources/shaders/metal/fill.fs.metal @@ -1,8 +1,15 @@ +// Automatically generated from files in pathfinder/shaders/. Do not edit! #include #include using namespace metal; +struct spvDescriptorSetBuffer0 +{ + texture2d uAreaLUT [[id(0)]]; + sampler uAreaLUTSmplr [[id(1)]]; +}; + struct main0_out { float4 oFragColor [[color(0)]]; @@ -14,7 +21,7 @@ struct main0_in float2 vTo [[user(locn1)]]; }; -fragment main0_out main0(main0_in in [[stage_in]], texture2d uAreaLUT [[texture(0)]], sampler uAreaLUTSmplr [[sampler(0)]]) +fragment main0_out main0(main0_in in [[stage_in]], constant spvDescriptorSetBuffer0& spvDescriptorSet0 [[buffer(0)]]) { main0_out out = {}; float2 from = in.vFrom; @@ -29,7 +36,7 @@ fragment main0_out main0(main0_in in [[stage_in]], texture2d uAreaLUT [[t float y = mix(left.y, right.y, t); float d = (right.y - left.y) / (right.x - left.x); float dX = window.x - window.y; - out.oFragColor = float4(uAreaLUT.sample(uAreaLUTSmplr, (float2(y + 8.0, abs(d * dX)) / float2(16.0))).x * dX); + out.oFragColor = float4(spvDescriptorSet0.uAreaLUT.sample(spvDescriptorSet0.uAreaLUTSmplr, (float2(y + 8.0, abs(d * dX)) / float2(16.0))).x * dX); return out; } diff --git a/resources/shaders/metal/fill.vs.metal b/resources/shaders/metal/fill.vs.metal index 1c545156..87f77d2a 100644 --- a/resources/shaders/metal/fill.vs.metal +++ b/resources/shaders/metal/fill.vs.metal @@ -1,3 +1,4 @@ +// Automatically generated from files in pathfinder/shaders/. Do not edit! #pragma clang diagnostic ignored "-Wmissing-prototypes" #include @@ -5,6 +6,12 @@ using namespace metal; +struct spvDescriptorSetBuffer0 +{ + constant float2* uTileSize [[id(0)]]; + constant float2* uFramebufferSize [[id(1)]]; +}; + struct main0_out { float2 vFrom [[user(locn0)]]; @@ -14,7 +21,7 @@ struct main0_out struct main0_in { - float2 aTessCoord [[attribute(0)]]; + uint2 aTessCoord [[attribute(0)]]; uint aFromPx [[attribute(1)]]; uint aToPx [[attribute(2)]]; float2 aFromSubpx [[attribute(3)]]; @@ -22,23 +29,23 @@ struct main0_in uint aTileIndex [[attribute(5)]]; }; -float2 computeTileOffset(thread const uint& tileIndex, thread const float& stencilTextureWidth, thread float2 uTileSize, thread uint& aTileIndex) +float2 computeTileOffset(thread const uint& tileIndex, thread const float& stencilTextureWidth, thread float2 uTileSize) { uint tilesPerRow = uint(stencilTextureWidth / uTileSize.x); - uint2 tileOffset = uint2(aTileIndex % tilesPerRow, aTileIndex / tilesPerRow); + uint2 tileOffset = uint2(tileIndex % tilesPerRow, tileIndex / tilesPerRow); return float2(tileOffset) * uTileSize; } -vertex main0_out main0(main0_in in [[stage_in]], float2 uTileSize [[buffer(0)]], float2 uFramebufferSize [[buffer(1)]], uint gl_VertexID [[vertex_id]], uint gl_InstanceID [[instance_id]]) +vertex main0_out main0(main0_in in [[stage_in]], constant spvDescriptorSetBuffer0& spvDescriptorSet0 [[buffer(0)]]) { main0_out out = {}; uint param = in.aTileIndex; - float param_1 = uFramebufferSize.x; - float2 tileOrigin = computeTileOffset(param, param_1, uTileSize, in.aTileIndex); + float param_1 = (*spvDescriptorSet0.uFramebufferSize).x; + float2 tileOrigin = computeTileOffset(param, param_1, (*spvDescriptorSet0.uTileSize)); float2 from = float2(float(in.aFromPx & 15u), float(in.aFromPx >> 4u)) + in.aFromSubpx; float2 to = float2(float(in.aToPx & 15u), float(in.aToPx >> 4u)) + in.aToSubpx; float2 position; - if (in.aTessCoord.x < 0.5) + if (in.aTessCoord.x == 0u) { position.x = floor(fast::min(from.x, to.x)); } @@ -46,17 +53,19 @@ vertex main0_out main0(main0_in in [[stage_in]], float2 uTileSize [[buffer(0)]], { position.x = ceil(fast::max(from.x, to.x)); } - if (in.aTessCoord.y < 0.5) + if (in.aTessCoord.y == 0u) { position.y = floor(fast::min(from.y, to.y)); } else { - position.y = uTileSize.y; + position.y = (*spvDescriptorSet0.uTileSize).y; } out.vFrom = from - position; out.vTo = to - position; - out.gl_Position = float4((((tileOrigin + position) / uFramebufferSize) * 2.0) - float2(1.0), 0.0, 1.0); + float2 globalPosition = (((tileOrigin + position) / (*spvDescriptorSet0.uFramebufferSize)) * 2.0) - float2(1.0); + globalPosition.y = -globalPosition.y; + out.gl_Position = float4(globalPosition, 0.0, 1.0); return out; } diff --git a/resources/shaders/metal/post.fs.metal b/resources/shaders/metal/post.fs.metal index 66ca87f8..989fd5d7 100644 --- a/resources/shaders/metal/post.fs.metal +++ b/resources/shaders/metal/post.fs.metal @@ -1,3 +1,4 @@ +// Automatically generated from files in pathfinder/shaders/. Do not edit! #pragma clang diagnostic ignored "-Wmissing-prototypes" #include @@ -5,6 +6,19 @@ using namespace metal; +struct spvDescriptorSetBuffer0 +{ + constant float4* uKernel [[id(0)]]; + texture2d uGammaLUT [[id(1)]]; + texture2d uSource [[id(2)]]; + constant float2* uSourceSize [[id(3)]]; + sampler uSourceSmplr [[id(4)]]; + sampler uGammaLUTSmplr [[id(5)]]; + constant int* uGammaCorrectionEnabled [[id(6)]]; + constant float4* uBGColor [[id(7)]]; + constant float4* uFGColor [[id(8)]]; +}; + struct main0_out { float4 oFragColor [[color(0)]]; @@ -78,42 +92,42 @@ float3 gammaCorrect(thread const float3& bgColor, thread const float3& fgColor, return float3(gammaCorrectChannel(param, param_1, uGammaLUT, uGammaLUTSmplr), gammaCorrectChannel(param_2, param_3, uGammaLUT, uGammaLUTSmplr), gammaCorrectChannel(param_4, param_5, uGammaLUT, uGammaLUTSmplr)); } -fragment main0_out main0(main0_in in [[stage_in]], int uGammaCorrectionEnabled [[buffer(2)]], float4 uKernel [[buffer(0)]], float2 uSourceSize [[buffer(1)]], float4 uBGColor [[buffer(3)]], float4 uFGColor [[buffer(4)]], texture2d uGammaLUT [[texture(0)]], texture2d uSource [[texture(0)]], sampler uGammaLUTSmplr [[sampler(0)]], sampler uSourceSmplr [[sampler(0)]]) +fragment main0_out main0(main0_in in [[stage_in]], constant spvDescriptorSetBuffer0& spvDescriptorSet0 [[buffer(0)]]) { main0_out out = {}; float3 alpha; - if (uKernel.w == 0.0) + if ((*spvDescriptorSet0.uKernel).w == 0.0) { - alpha = uSource.sample(uSourceSmplr, in.vTexCoord).xxx; + alpha = spvDescriptorSet0.uSource.sample(spvDescriptorSet0.uSourceSmplr, in.vTexCoord).xxx; } else { - float param_3 = 1.0 / uSourceSize.x; + float param_3 = 1.0 / (*spvDescriptorSet0.uSourceSize).x; float4 param; float param_1; float4 param_2; - sample9Tap(param, param_1, param_2, param_3, uKernel, uSource, uSourceSmplr, in.vTexCoord); + sample9Tap(param, param_1, param_2, param_3, (*spvDescriptorSet0.uKernel), spvDescriptorSet0.uSource, spvDescriptorSet0.uSourceSmplr, in.vTexCoord); float4 alphaLeft = param; float alphaCenter = param_1; float4 alphaRight = param_2; float4 param_4 = alphaLeft; float3 param_5 = float3(alphaCenter, alphaRight.xy); - float r = convolve7Tap(param_4, param_5, uKernel); + float r = convolve7Tap(param_4, param_5, (*spvDescriptorSet0.uKernel)); float4 param_6 = float4(alphaLeft.yzw, alphaCenter); float3 param_7 = alphaRight.xyz; - float g = convolve7Tap(param_6, param_7, uKernel); + float g = convolve7Tap(param_6, param_7, (*spvDescriptorSet0.uKernel)); float4 param_8 = float4(alphaLeft.zw, alphaCenter, alphaRight.x); float3 param_9 = alphaRight.yzw; - float b = convolve7Tap(param_8, param_9, uKernel); + float b = convolve7Tap(param_8, param_9, (*spvDescriptorSet0.uKernel)); alpha = float3(r, g, b); } - if (uGammaCorrectionEnabled != 0) + if ((*spvDescriptorSet0.uGammaCorrectionEnabled) != 0) { - float3 param_10 = uBGColor.xyz; + float3 param_10 = (*spvDescriptorSet0.uBGColor).xyz; float3 param_11 = alpha; - alpha = gammaCorrect(param_10, param_11, uGammaLUT, uGammaLUTSmplr); + alpha = gammaCorrect(param_10, param_11, spvDescriptorSet0.uGammaLUT, spvDescriptorSet0.uGammaLUTSmplr); } - out.oFragColor = float4(mix(uBGColor.xyz, uFGColor.xyz, alpha), 1.0); + out.oFragColor = float4(mix((*spvDescriptorSet0.uBGColor).xyz, (*spvDescriptorSet0.uFGColor).xyz, alpha), 1.0); return out; } diff --git a/resources/shaders/metal/post.vs.metal b/resources/shaders/metal/post.vs.metal index a960ca1b..0fcc0bf6 100644 --- a/resources/shaders/metal/post.vs.metal +++ b/resources/shaders/metal/post.vs.metal @@ -1,3 +1,4 @@ +// Automatically generated from files in pathfinder/shaders/. Do not edit! #include #include @@ -11,14 +12,14 @@ struct main0_out struct main0_in { - float2 aPosition [[attribute(0)]]; + int2 aPosition [[attribute(0)]]; }; -vertex main0_out main0(main0_in in [[stage_in]], uint gl_VertexID [[vertex_id]], uint gl_InstanceID [[instance_id]]) +vertex main0_out main0(main0_in in [[stage_in]]) { main0_out out = {}; - out.vTexCoord = in.aPosition; - out.gl_Position = float4((in.aPosition * 2.0) - float2(1.0), 0.0, 1.0); + out.vTexCoord = float2(in.aPosition); + out.gl_Position = float4((float2(in.aPosition) * 2.0) - float2(1.0), 0.0, 1.0); return out; } diff --git a/resources/shaders/metal/reproject.fs.metal b/resources/shaders/metal/reproject.fs.metal index 3e2a2039..be9ff4dd 100644 --- a/resources/shaders/metal/reproject.fs.metal +++ b/resources/shaders/metal/reproject.fs.metal @@ -1,8 +1,16 @@ +// Automatically generated from files in pathfinder/shaders/. Do not edit! #include #include using namespace metal; +struct spvDescriptorSetBuffer0 +{ + constant float4x4* uOldTransform [[id(0)]]; + texture2d uTexture [[id(1)]]; + sampler uTextureSmplr [[id(2)]]; +}; + struct main0_out { float4 oFragColor [[color(0)]]; @@ -13,12 +21,12 @@ struct main0_in float2 vTexCoord [[user(locn0)]]; }; -fragment main0_out main0(main0_in in [[stage_in]], float4x4 uOldTransform [[buffer(0)]], texture2d uTexture [[texture(0)]], sampler uTextureSmplr [[sampler(0)]]) +fragment main0_out main0(main0_in in [[stage_in]], constant spvDescriptorSetBuffer0& spvDescriptorSet0 [[buffer(0)]]) { main0_out out = {}; - float4 normTexCoord = uOldTransform * float4(in.vTexCoord, 0.0, 1.0); + float4 normTexCoord = (*spvDescriptorSet0.uOldTransform) * float4(in.vTexCoord, 0.0, 1.0); float2 texCoord = ((normTexCoord.xy / float2(normTexCoord.w)) + float2(1.0)) * 0.5; - out.oFragColor = uTexture.sample(uTextureSmplr, texCoord); + out.oFragColor = spvDescriptorSet0.uTexture.sample(spvDescriptorSet0.uTextureSmplr, texCoord); return out; } diff --git a/resources/shaders/metal/reproject.vs.metal b/resources/shaders/metal/reproject.vs.metal index d125c376..3bdc9034 100644 --- a/resources/shaders/metal/reproject.vs.metal +++ b/resources/shaders/metal/reproject.vs.metal @@ -1,8 +1,14 @@ +// Automatically generated from files in pathfinder/shaders/. Do not edit! #include #include using namespace metal; +struct spvDescriptorSetBuffer0 +{ + constant float4x4* uNewTransform [[id(0)]]; +}; + struct main0_out { float2 vTexCoord [[user(locn0)]]; @@ -11,14 +17,16 @@ struct main0_out struct main0_in { - float2 aPosition [[attribute(0)]]; + int2 aPosition [[attribute(0)]]; }; -vertex main0_out main0(main0_in in [[stage_in]], float4x4 uNewTransform [[buffer(0)]], uint gl_VertexID [[vertex_id]], uint gl_InstanceID [[instance_id]]) +vertex main0_out main0(main0_in in [[stage_in]], constant spvDescriptorSetBuffer0& spvDescriptorSet0 [[buffer(0)]]) { main0_out out = {}; - out.vTexCoord = in.aPosition; - out.gl_Position = uNewTransform * float4(in.aPosition, 0.0, 1.0); + float2 position = float2(in.aPosition); + out.vTexCoord = position; + position.y = 1.0 - position.y; + out.gl_Position = (*spvDescriptorSet0.uNewTransform) * float4(position, 0.0, 1.0); return out; } diff --git a/resources/shaders/metal/stencil.fs.metal b/resources/shaders/metal/stencil.fs.metal index 426311ef..999cc7e1 100644 --- a/resources/shaders/metal/stencil.fs.metal +++ b/resources/shaders/metal/stencil.fs.metal @@ -1,3 +1,4 @@ +// Automatically generated from files in pathfinder/shaders/. Do not edit! #include #include diff --git a/resources/shaders/metal/stencil.vs.metal b/resources/shaders/metal/stencil.vs.metal index 2dc23a5d..6b6182d4 100644 --- a/resources/shaders/metal/stencil.vs.metal +++ b/resources/shaders/metal/stencil.vs.metal @@ -1,3 +1,4 @@ +// Automatically generated from files in pathfinder/shaders/. Do not edit! #include #include @@ -13,7 +14,7 @@ struct main0_in float3 aPosition [[attribute(0)]]; }; -vertex main0_out main0(main0_in in [[stage_in]], uint gl_VertexID [[vertex_id]], uint gl_InstanceID [[instance_id]]) +vertex main0_out main0(main0_in in [[stage_in]]) { main0_out out = {}; out.gl_Position = float4(in.aPosition, 1.0); diff --git a/resources/shaders/metal/tile_alpha.fs.metal b/resources/shaders/metal/tile_alpha.fs.metal index 30afe4cd..2e72b19e 100644 --- a/resources/shaders/metal/tile_alpha.fs.metal +++ b/resources/shaders/metal/tile_alpha.fs.metal @@ -1,8 +1,15 @@ +// Automatically generated from files in pathfinder/shaders/. Do not edit! #include #include using namespace metal; +struct spvDescriptorSetBuffer0 +{ + texture2d uStencilTexture [[id(0)]]; + sampler uStencilTextureSmplr [[id(1)]]; +}; + struct main0_out { float4 oFragColor [[color(0)]]; @@ -15,10 +22,10 @@ struct main0_in float4 vColor [[user(locn2)]]; }; -fragment main0_out main0(main0_in in [[stage_in]], texture2d uStencilTexture [[texture(0)]], sampler uStencilTextureSmplr [[sampler(0)]]) +fragment main0_out main0(main0_in in [[stage_in]], constant spvDescriptorSetBuffer0& spvDescriptorSet0 [[buffer(0)]]) { main0_out out = {}; - float coverage = abs(uStencilTexture.sample(uStencilTextureSmplr, in.vTexCoord).x + in.vBackdrop); + float coverage = abs(spvDescriptorSet0.uStencilTexture.sample(spvDescriptorSet0.uStencilTextureSmplr, in.vTexCoord).x + in.vBackdrop); out.oFragColor = float4(in.vColor.xyz, in.vColor.w * coverage); return out; } diff --git a/resources/shaders/metal/tile_alpha_monochrome.vs.metal b/resources/shaders/metal/tile_alpha_monochrome.vs.metal index e92a3af0..9c9e1b56 100644 --- a/resources/shaders/metal/tile_alpha_monochrome.vs.metal +++ b/resources/shaders/metal/tile_alpha_monochrome.vs.metal @@ -1,3 +1,4 @@ +// Automatically generated from files in pathfinder/shaders/. Do not edit! #pragma clang diagnostic ignored "-Wmissing-prototypes" #include @@ -5,6 +6,15 @@ using namespace metal; +struct spvDescriptorSetBuffer0 +{ + constant float2* uTileSize [[id(0)]]; + constant float2* uViewBoxOrigin [[id(1)]]; + constant float2* uFramebufferSize [[id(2)]]; + constant float2* uStencilTextureSize [[id(3)]]; + constant float4* uColor [[id(4)]]; +}; + struct main0_out { float2 vTexCoord [[user(locn0)]]; @@ -15,10 +25,10 @@ struct main0_out struct main0_in { - float2 aTessCoord [[attribute(0)]]; + uint2 aTessCoord [[attribute(0)]]; uint3 aTileOrigin [[attribute(1)]]; int aBackdrop [[attribute(2)]]; - uint aTileIndex [[attribute(3)]]; + int aTileIndex [[attribute(3)]]; }; float2 computeTileOffset(thread const uint& tileIndex, thread const float& stencilTextureWidth, thread float2 uTileSize) @@ -33,25 +43,25 @@ float4 getColor(thread float4 uColor) return uColor; } -void computeVaryings(thread float2 uTileSize, thread uint3& aTileOrigin, thread float2& aTessCoord, thread float2 uViewBoxOrigin, thread float2 uFramebufferSize, thread uint& aTileIndex, thread float2 uStencilTextureSize, thread float2& vTexCoord, thread float& vBackdrop, thread int& aBackdrop, thread float4& vColor, thread float4& gl_Position, thread float4 uColor) +void computeVaryings(thread float2 uTileSize, thread uint3& aTileOrigin, thread uint2& aTessCoord, thread float2 uViewBoxOrigin, thread float2 uFramebufferSize, thread int& aTileIndex, thread float2 uStencilTextureSize, thread float2& vTexCoord, thread float& vBackdrop, thread int& aBackdrop, thread float4& vColor, thread float4& gl_Position, thread float4 uColor) { float2 origin = float2(aTileOrigin.xy) + (float2(float(aTileOrigin.z & 15u), float(aTileOrigin.z >> 4u)) * 256.0); - float2 pixelPosition = ((origin + aTessCoord) * uTileSize) + uViewBoxOrigin; + float2 pixelPosition = ((origin + float2(aTessCoord)) * uTileSize) + uViewBoxOrigin; float2 position = (((pixelPosition / uFramebufferSize) * 2.0) - float2(1.0)) * float2(1.0, -1.0); - uint param = aTileIndex; + uint param = uint(aTileIndex); float param_1 = uStencilTextureSize.x; float2 maskTexCoordOrigin = computeTileOffset(param, param_1, uTileSize); - float2 maskTexCoord = maskTexCoordOrigin + (aTessCoord * uTileSize); + float2 maskTexCoord = maskTexCoordOrigin + (float2(aTessCoord) * uTileSize); vTexCoord = maskTexCoord / uStencilTextureSize; vBackdrop = float(aBackdrop); vColor = getColor(uColor); gl_Position = float4(position, 0.0, 1.0); } -vertex main0_out main0(main0_in in [[stage_in]], float2 uTileSize [[buffer(0)]], float2 uViewBoxOrigin [[buffer(1)]], float2 uFramebufferSize [[buffer(2)]], float2 uStencilTextureSize [[buffer(3)]], float4 uColor [[buffer(4)]], uint gl_VertexID [[vertex_id]], uint gl_InstanceID [[instance_id]]) +vertex main0_out main0(main0_in in [[stage_in]], constant spvDescriptorSetBuffer0& spvDescriptorSet0 [[buffer(0)]]) { main0_out out = {}; - computeVaryings(uTileSize, in.aTileOrigin, in.aTessCoord, uViewBoxOrigin, uFramebufferSize, in.aTileIndex, uStencilTextureSize, out.vTexCoord, out.vBackdrop, in.aBackdrop, out.vColor, out.gl_Position, uColor); + computeVaryings((*spvDescriptorSet0.uTileSize), in.aTileOrigin, in.aTessCoord, (*spvDescriptorSet0.uViewBoxOrigin), (*spvDescriptorSet0.uFramebufferSize), in.aTileIndex, (*spvDescriptorSet0.uStencilTextureSize), out.vTexCoord, out.vBackdrop, in.aBackdrop, out.vColor, out.gl_Position, (*spvDescriptorSet0.uColor)); return out; } diff --git a/resources/shaders/metal/tile_alpha_multicolor.vs.metal b/resources/shaders/metal/tile_alpha_multicolor.vs.metal index 525d7fe3..bc25f729 100644 --- a/resources/shaders/metal/tile_alpha_multicolor.vs.metal +++ b/resources/shaders/metal/tile_alpha_multicolor.vs.metal @@ -1,3 +1,4 @@ +// Automatically generated from files in pathfinder/shaders/. Do not edit! #pragma clang diagnostic ignored "-Wmissing-prototypes" #include @@ -5,6 +6,16 @@ using namespace metal; +struct spvDescriptorSetBuffer0 +{ + constant float2* uTileSize [[id(0)]]; + texture2d uPaintTexture [[id(1)]]; + constant float2* uViewBoxOrigin [[id(2)]]; + sampler uPaintTextureSmplr [[id(3)]]; + constant float2* uFramebufferSize [[id(4)]]; + constant float2* uStencilTextureSize [[id(5)]]; +}; + struct main0_out { float2 vTexCoord [[user(locn0)]]; @@ -15,10 +26,10 @@ struct main0_out struct main0_in { - float2 aTessCoord [[attribute(0)]]; + uint2 aTessCoord [[attribute(0)]]; uint3 aTileOrigin [[attribute(1)]]; int aBackdrop [[attribute(2)]]; - uint aTileIndex [[attribute(3)]]; + int aTileIndex [[attribute(3)]]; float2 aColorTexCoord [[attribute(4)]]; }; @@ -34,25 +45,25 @@ float4 getColor(thread texture2d uPaintTexture, thread const sampler uPai return uPaintTexture.sample(uPaintTextureSmplr, aColorTexCoord, level(0.0)); } -void computeVaryings(thread float2 uTileSize, thread uint3& aTileOrigin, thread float2& aTessCoord, thread float2 uViewBoxOrigin, thread float2 uFramebufferSize, thread uint& aTileIndex, thread float2 uStencilTextureSize, thread float2& vTexCoord, thread float& vBackdrop, thread int& aBackdrop, thread float4& vColor, thread float4& gl_Position, thread texture2d uPaintTexture, thread const sampler uPaintTextureSmplr, thread float2& aColorTexCoord) +void computeVaryings(thread float2 uTileSize, thread uint3& aTileOrigin, thread uint2& aTessCoord, thread float2 uViewBoxOrigin, thread float2 uFramebufferSize, thread int& aTileIndex, thread float2 uStencilTextureSize, thread float2& vTexCoord, thread float& vBackdrop, thread int& aBackdrop, thread float4& vColor, thread float4& gl_Position, thread texture2d uPaintTexture, thread const sampler uPaintTextureSmplr, thread float2& aColorTexCoord) { float2 origin = float2(aTileOrigin.xy) + (float2(float(aTileOrigin.z & 15u), float(aTileOrigin.z >> 4u)) * 256.0); - float2 pixelPosition = ((origin + aTessCoord) * uTileSize) + uViewBoxOrigin; + float2 pixelPosition = ((origin + float2(aTessCoord)) * uTileSize) + uViewBoxOrigin; float2 position = (((pixelPosition / uFramebufferSize) * 2.0) - float2(1.0)) * float2(1.0, -1.0); - uint param = aTileIndex; + uint param = uint(aTileIndex); float param_1 = uStencilTextureSize.x; float2 maskTexCoordOrigin = computeTileOffset(param, param_1, uTileSize); - float2 maskTexCoord = maskTexCoordOrigin + (aTessCoord * uTileSize); + float2 maskTexCoord = maskTexCoordOrigin + (float2(aTessCoord) * uTileSize); vTexCoord = maskTexCoord / uStencilTextureSize; vBackdrop = float(aBackdrop); vColor = getColor(uPaintTexture, uPaintTextureSmplr, aColorTexCoord); gl_Position = float4(position, 0.0, 1.0); } -vertex main0_out main0(main0_in in [[stage_in]], float2 uTileSize [[buffer(0)]], float2 uViewBoxOrigin [[buffer(1)]], float2 uFramebufferSize [[buffer(2)]], float2 uStencilTextureSize [[buffer(3)]], texture2d uPaintTexture [[texture(0)]], sampler uPaintTextureSmplr [[sampler(0)]], uint gl_VertexID [[vertex_id]], uint gl_InstanceID [[instance_id]]) +vertex main0_out main0(main0_in in [[stage_in]], constant spvDescriptorSetBuffer0& spvDescriptorSet0 [[buffer(0)]]) { main0_out out = {}; - computeVaryings(uTileSize, in.aTileOrigin, in.aTessCoord, uViewBoxOrigin, uFramebufferSize, in.aTileIndex, uStencilTextureSize, out.vTexCoord, out.vBackdrop, in.aBackdrop, out.vColor, out.gl_Position, uPaintTexture, uPaintTextureSmplr, in.aColorTexCoord); + computeVaryings((*spvDescriptorSet0.uTileSize), in.aTileOrigin, in.aTessCoord, (*spvDescriptorSet0.uViewBoxOrigin), (*spvDescriptorSet0.uFramebufferSize), in.aTileIndex, (*spvDescriptorSet0.uStencilTextureSize), out.vTexCoord, out.vBackdrop, in.aBackdrop, out.vColor, out.gl_Position, spvDescriptorSet0.uPaintTexture, spvDescriptorSet0.uPaintTextureSmplr, in.aColorTexCoord); return out; } diff --git a/resources/shaders/metal/tile_solid.fs.metal b/resources/shaders/metal/tile_solid.fs.metal index fed4023d..ac500c97 100644 --- a/resources/shaders/metal/tile_solid.fs.metal +++ b/resources/shaders/metal/tile_solid.fs.metal @@ -1,3 +1,4 @@ +// Automatically generated from files in pathfinder/shaders/. Do not edit! #include #include diff --git a/resources/shaders/metal/tile_solid_monochrome.vs.metal b/resources/shaders/metal/tile_solid_monochrome.vs.metal index 83410055..46328863 100644 --- a/resources/shaders/metal/tile_solid_monochrome.vs.metal +++ b/resources/shaders/metal/tile_solid_monochrome.vs.metal @@ -1,3 +1,4 @@ +// Automatically generated from files in pathfinder/shaders/. Do not edit! #pragma clang diagnostic ignored "-Wmissing-prototypes" #include @@ -5,6 +6,14 @@ using namespace metal; +struct spvDescriptorSetBuffer0 +{ + constant float2* uTileSize [[id(0)]]; + constant float2* uViewBoxOrigin [[id(1)]]; + constant float2* uFramebufferSize [[id(2)]]; + constant float4* uColor [[id(3)]]; +}; + struct main0_out { float4 vColor [[user(locn0)]]; @@ -13,8 +22,8 @@ struct main0_out struct main0_in { - float2 aTessCoord [[attribute(0)]]; - float2 aTileOrigin [[attribute(1)]]; + uint2 aTessCoord [[attribute(0)]]; + int2 aTileOrigin [[attribute(1)]]; }; float4 getColor(thread float4 uColor) @@ -22,18 +31,18 @@ float4 getColor(thread float4 uColor) return uColor; } -void computeVaryings(thread float2& aTileOrigin, thread float2& aTessCoord, thread float2 uTileSize, thread float2 uViewBoxOrigin, thread float2 uFramebufferSize, thread float4& vColor, thread float4& gl_Position, thread float4 uColor) +void computeVaryings(thread int2& aTileOrigin, thread uint2& aTessCoord, thread float2 uTileSize, thread float2 uViewBoxOrigin, thread float2 uFramebufferSize, thread float4& vColor, thread float4& gl_Position, thread float4 uColor) { - float2 pixelPosition = ((aTileOrigin + aTessCoord) * uTileSize) + uViewBoxOrigin; + float2 pixelPosition = (float2(aTileOrigin + int2(aTessCoord)) * uTileSize) + uViewBoxOrigin; float2 position = (((pixelPosition / uFramebufferSize) * 2.0) - float2(1.0)) * float2(1.0, -1.0); vColor = getColor(uColor); gl_Position = float4(position, 0.0, 1.0); } -vertex main0_out main0(main0_in in [[stage_in]], float2 uTileSize [[buffer(0)]], float2 uViewBoxOrigin [[buffer(1)]], float2 uFramebufferSize [[buffer(2)]], float4 uColor [[buffer(3)]], uint gl_VertexID [[vertex_id]], uint gl_InstanceID [[instance_id]]) +vertex main0_out main0(main0_in in [[stage_in]], constant spvDescriptorSetBuffer0& spvDescriptorSet0 [[buffer(0)]]) { main0_out out = {}; - computeVaryings(in.aTileOrigin, in.aTessCoord, uTileSize, uViewBoxOrigin, uFramebufferSize, out.vColor, out.gl_Position, uColor); + computeVaryings(in.aTileOrigin, in.aTessCoord, (*spvDescriptorSet0.uTileSize), (*spvDescriptorSet0.uViewBoxOrigin), (*spvDescriptorSet0.uFramebufferSize), out.vColor, out.gl_Position, (*spvDescriptorSet0.uColor)); return out; } diff --git a/resources/shaders/metal/tile_solid_multicolor.vs.metal b/resources/shaders/metal/tile_solid_multicolor.vs.metal index 3f5d0c45..edfe17d0 100644 --- a/resources/shaders/metal/tile_solid_multicolor.vs.metal +++ b/resources/shaders/metal/tile_solid_multicolor.vs.metal @@ -1,3 +1,4 @@ +// Automatically generated from files in pathfinder/shaders/. Do not edit! #pragma clang diagnostic ignored "-Wmissing-prototypes" #include @@ -5,6 +6,15 @@ using namespace metal; +struct spvDescriptorSetBuffer0 +{ + constant float2* uTileSize [[id(0)]]; + texture2d uPaintTexture [[id(1)]]; + constant float2* uViewBoxOrigin [[id(2)]]; + sampler uPaintTextureSmplr [[id(3)]]; + constant float2* uFramebufferSize [[id(4)]]; +}; + struct main0_out { float4 vColor [[user(locn0)]]; @@ -13,8 +23,8 @@ struct main0_out struct main0_in { - float2 aTessCoord [[attribute(0)]]; - float2 aTileOrigin [[attribute(1)]]; + uint2 aTessCoord [[attribute(0)]]; + int2 aTileOrigin [[attribute(1)]]; float2 aColorTexCoord [[attribute(2)]]; }; @@ -23,18 +33,18 @@ float4 getColor(thread texture2d uPaintTexture, thread const sampler uPai return uPaintTexture.sample(uPaintTextureSmplr, aColorTexCoord, level(0.0)); } -void computeVaryings(thread float2& aTileOrigin, thread float2& aTessCoord, thread float2 uTileSize, thread float2 uViewBoxOrigin, thread float2 uFramebufferSize, thread float4& vColor, thread float4& gl_Position, thread texture2d uPaintTexture, thread const sampler uPaintTextureSmplr, thread float2& aColorTexCoord) +void computeVaryings(thread int2& aTileOrigin, thread uint2& aTessCoord, thread float2 uTileSize, thread float2 uViewBoxOrigin, thread float2 uFramebufferSize, thread float4& vColor, thread float4& gl_Position, thread texture2d uPaintTexture, thread const sampler uPaintTextureSmplr, thread float2& aColorTexCoord) { - float2 pixelPosition = ((aTileOrigin + aTessCoord) * uTileSize) + uViewBoxOrigin; + float2 pixelPosition = (float2(aTileOrigin + int2(aTessCoord)) * uTileSize) + uViewBoxOrigin; float2 position = (((pixelPosition / uFramebufferSize) * 2.0) - float2(1.0)) * float2(1.0, -1.0); vColor = getColor(uPaintTexture, uPaintTextureSmplr, aColorTexCoord); gl_Position = float4(position, 0.0, 1.0); } -vertex main0_out main0(main0_in in [[stage_in]], float2 uTileSize [[buffer(0)]], float2 uViewBoxOrigin [[buffer(1)]], float2 uFramebufferSize [[buffer(2)]], texture2d uPaintTexture [[texture(0)]], sampler uPaintTextureSmplr [[sampler(0)]], uint gl_VertexID [[vertex_id]], uint gl_InstanceID [[instance_id]]) +vertex main0_out main0(main0_in in [[stage_in]], constant spvDescriptorSetBuffer0& spvDescriptorSet0 [[buffer(0)]]) { main0_out out = {}; - computeVaryings(in.aTileOrigin, in.aTessCoord, uTileSize, uViewBoxOrigin, uFramebufferSize, out.vColor, out.gl_Position, uPaintTexture, uPaintTextureSmplr, in.aColorTexCoord); + computeVaryings(in.aTileOrigin, in.aTessCoord, (*spvDescriptorSet0.uTileSize), (*spvDescriptorSet0.uViewBoxOrigin), (*spvDescriptorSet0.uFramebufferSize), out.vColor, out.gl_Position, spvDescriptorSet0.uPaintTexture, spvDescriptorSet0.uPaintTextureSmplr, in.aColorTexCoord); return out; } diff --git a/resources/shaders/spirv/debug_solid.fs.spv b/resources/shaders/spirv/debug_solid.fs.spv deleted file mode 100644 index ae1e7b85c0fe2cea57566e63c24cfbb86f9bed24..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 644 zcmZ9J%}N775QM+|ne1vbKgJ~LL82ao;6X(Y6%hh=k+2;)lNWd zSa!Oqrn|Z)OLq!LC@9&WiZ&?;P^aeqXnZ#wzP{ZL_Yd}@XpmVbO_Lfq_O)7pd*491o%H=_!dP}jM^tf+_DFHZ%-j`$lYfATSfHC0;y^VH$OR$%g->r%{){dC8b8IDI wx_d+6c{_ejtQW7j&I$J1k3KYuylKa4-U)mXe19EWL-;9~_bTk0gd-Au07NDmivR!s diff --git a/resources/shaders/spirv/debug_solid.vs.spv b/resources/shaders/spirv/debug_solid.vs.spv deleted file mode 100644 index 0c94d0dfa07e41bf550045bc9e8cbd4649547308..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1252 zcmZ9LOKTKS5QV>fN27@`Ch-wtVthw~3l%|p;ovwSi-CaKVbsph(3ymp4u~5CH?I7> zZUi~ib%}a6Gw0N~Ri~$hi!R>OsGpye}tB`B{AKypCcaTTWqm`8U2AHz8Mu$?vEhys4|B zPBm?Yi(qk7OAw|9CSpi64~tl7;LtC#=rb&tOzGk-do zgHGVuy=Y@6oV-e>t#nE3t~k||N5wM7@+X`Fi^Qheunl4Vmq{$P4y=$;xK{brNtprT z#0#HxFT&3pE5H0He%AemxUhQH*&?-C3oU#V@S@>wFI9ip>+5|jk+NcW+ata3MX$F? z$|cu}Tk|=F9E!=)6`z&fj64hLy=s1{an)<62h|V`y9zb0xd-Lbtiqf^54Zk`-|^h? zA^kn~tGuc&tUak-z}l1W6Ed5<`qz=iU&OXgX|)f1fvW%9_jSg19Pqr){D*x-a1Kl( z{-<;2o!2h<&RwuKqIUw{om&FaD)xfJYKwbKW^>qZKbnu~>z(Ociw~Mj*JwvUa|4Y3 l>UVB}aeWG#+ilMyUbB@a<ADVp!(nCcM6(J;qP@&NC1uq&{6E_VXd+D{mx0fJ( zd(OnI4a1zZ&f5Fzz0Rr1jRp!D2HdBMc}fakhN<{(@9geuem&mbeDwICidm`zA=iVm8;)Z}oGz zcX{<AdMz3FqJMZ+D^Iqpc3a@-YeZJo5 zp`87A7iz`UbA2;ve1G|bI_9!hL(MNr>fDRo`j-4ZCxu7nAp8;Q!F-a>X>0Q&*^N|vac%;{EwV>6(U#u1y%GS*Xw-)_9u3J-;v(EWe{_3WUhZ- z-jVm%_jLbhN38l3OFEwIHPq!V`7{Fp<-Axfw*m|Jerr3mb|uxxY5LoEB{_M zCgykF{bcwy^xS*y@SXELqUusjs;H(ht*AUxs;VMsT&ewSY;JAV2g9BE%JauCCKMSF z&ZNfecPweIo%aBztX8@pX-U#kNzWujid2>Ku_7gkkJThftnTY}cCgy-7dwKJSoij^ zSgHw0qwVZqI4ZKO{9DFMxaTG9_Xqhf@7o^4*rDA#3?`~+n)>yky_bC+?e1p9VUJXc zk~-a1Gb=u2#V|Xdcj|EtxzH_D&G_hG@w_(-y+V%rcDk+AZoa>k4~FgDmrRKw(}ly1 z=+o)8%7GheN|c&joo;KRSJrH-NopuIjpnVg#HbHu2l8lh65lw&M~|cRXmJt;{s$#? zKTheg{>RGqQO*rK?h23B(NJWy#Mp~Fl1m)(9>A%+ldAC+?S;sG&nU9of}~l+syUZ_ z3yL-7bBMok%)4VY`P05z$b*^3-sI1^CLs?-I}Z6N$#Nl2J=#&vJosqGSypVjUMk_c zfUg+-@s|Cs`Tl$-(~3=V?#6+S2iLv-oMOwN4Y7ImA@rb*9r20#@@Cly%=bo&88?kr z?#vAEtrIhEJEq?qzcX{g9UdOZKl0w}0so2jrZ4ls_#89><1_e$67!DxbJ+2Zs`ehJ zMQ^@e^nUGrpK;Fuo^+3X*;g!`lZ-?BjUw}(Sm0lD&jOxt&qDpIWE|qZz2{|nZ!#~N z9=j@;m-zY9V{?*m$uXPViM>~1I^OmBpfB^$^qyq#z`5@nJPw>?$>QI==7D)3HB~d+ d>)wYr-mnw>@P>cR_>afz1cv`t6}?nN{{UeyW4izV diff --git a/resources/shaders/spirv/demo_ground.fs.spv b/resources/shaders/spirv/demo_ground.fs.spv deleted file mode 100644 index 8dc291cf6243e259735c00dfc7669a8d0318a52b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 908 zcmY+CNlF7z6h%+s-9J1!P{t&YB`T**Mhvze zI{kqH-S(?;66^DF>m&uIzWL>_bJxu8 z^P#wuRp7Zb?04_`gIZiS4zAJym{Ka_X3rmx3X_wf} znz#AiF7`;Q?*bSnevXia_g=JbF}HfJxNe=P-oo-jtHh-jnyt`SyoX~F)2KPMG|vwq ziP!2~=-#FC%zdf(`>Bx{KjFINiDG5mr00EmUESU#yt}?Buv+owM0Sq2vVP9b{vt8W zOXdUS%LlRfu?)tmM*7!WdxdO5|YPEVFimQj}G?VT~{4W6~1pEQm Ce>2qp diff --git a/resources/shaders/spirv/demo_ground.vs.spv b/resources/shaders/spirv/demo_ground.vs.spv deleted file mode 100644 index 0a0926a6f5d4eb63a7dd54289b2eec8f02bc7e27..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1328 zcmY+CU279z5QR^&`);b$)>`|a*4kRXtHBEuK~yAxSm{Ne#oG|f8Wy&@l5C}TW=Htw~QG2f=wbapqx~gqOZM7sVDzWe2@aV8RuO{8+FP_0zQe;Fp z%erX)v80o6Rsb$ou5?|}6G=}cMT*px^syxc#sBexg5`WWPS1K}IhzPh(4wUAu$*UA zR#G@9(Xyn|!7Q8PS&{b2)1s>V8U`Gr#$>qB_dH zr*%#pW7cUt>gCzjem1Yh#phH(k!ix1?-sKh&&I|4OF28KedwL$qk4#gzRisOX+AnA z>N*E~Ndv{EdE2Vh7`^8)TEWZ-AAHC89~Ay+BM)nQ_3i4s#)lqwTyCJqa`90Y9q0Rk zn?A(RL~d|CdccXKRkf|ou3cF6zplt)JCZgOtK(ey?I_lQ&w>B7W8Mt25$8prp^1a( zhi^@>E*r1L@RwXae(HhQ6-NJ6@6Q`0|C;Ax`;OPV-j-smJ0IV+@42Z#jGmi5FYk_? zVBR|#sL3ohtb??vST}7~vKh$V@)&;d!R#GtX1eVdKD$IeJ15R}&*KfgZ}`VM_>X)R z<_7P3ezPMmccmu%!Q2)6Qo(M;zA!ZXR@?6X#_xH_Zvv*~72kR3v#q%Ar-I$_s$@C% z-zu_u<0GFP@cz*MUct2PdVO{P2fe&W{0-->bGTE(xhI)_sE%oW;Cbwd7(4o57tyi diff --git a/resources/shaders/spirv/fill.fs.spv b/resources/shaders/spirv/fill.fs.spv deleted file mode 100644 index 4cb3b288627ff14dc30c22142e38799cca4cf7e0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2688 zcmZveX>(Ln5Qd-3%_Ko0i)tNTL`u2ng;*vk(o8P68>vX<1hJSNsQl z^KbdZD(mU#u3V_ORZ}zX+sk=RpYA!g=^Pt}5yqKdlfko_4kN&J#^QT+?#kTM`o`ka ziIXquv4bWY_1Vb;qY$543#+#^Y!4q;0Cv%YZ31X$=m3{Spv&kzG2(5&a=&-W9Afj_ zof!~a8Xg2TdfFOxXuH}Azg@uE((*>dJpuGrS8hs}=Q&_=_4Zs_YM8Kv9I1te_`c9Z>`rKa7)0Q>HgBf+_kIfm`(kU3lghY zY~8e5pSIl`_v53jc}&EkEGvO9D898dgE>M`G*%&msKba*&*JPPq!9mZ*YX%P2M;b<&4UwL28b=}7| zxexoyb-s;WB6xL*t)*RgkZpXI{_1W&g%8p2J%pe6JYyd@^NFpsPwBfkfYXJ0fq$Jo zMK|`PHXk+oONVaevhVHds4uKIxi@=2f6sMaoc)&1{@icd=Kuu%H{IxqgBd4Z>pqgX z3m?in^K_%19*eW~yx}j#Vn5D~ys`SL+1kpNW@p3mXzOvNsvKwHe!2IY-io<{-|0q~(N<)^V;? zNAu}F@EP29+DpSnL-KzN!I#hc5S^E!f41uW2}GQH#a$UvTQ5ub^0_vowx2@qRom+j zaq?B$8xU)1v$p={$yMIZhxFtZ5PbQ3Iix4Qg5YcIuOZ^(UB~}YIcx9zv7C2Doy7{o z|M73x1FI06_euHu0HL?=j}UqP$e1+@;>w4(O$Fb3z%zYFYYJbck*Ms z{4e+!!dKgMx^b8GQ@^&$x%Rs6QhB$PKHrtxcj>zW;U_=Oc;ve4`_O$K>*YPI?LS61 H%?SSkKmwEa diff --git a/resources/shaders/spirv/fill.vs.spv b/resources/shaders/spirv/fill.vs.spv deleted file mode 100644 index 1ae09e95694f83f3ec9e21e5ea9bf0c9d9adc656..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3908 zcmZvf>2nli5XPVE?(Bjfh+H0sARbt16y;Ln5+nps0$IU3F3D_I-DKh(5b**L1P{D# z{XhKd7yl%WDlO~R(=9`ase;VY{k+{h-Tl7(Zn?CsCJm^jdHO~9vqU8gNLrw({T(_u zdT_AYn;6`<=^+@4R5l`<#k#@XE0U%ft!cn&Nt-3@mh_~grzMR@dP~xKl0KC5lcb*| zl~qm_x2>GXK3T~B9w{Z4wUHPJg^d?JS59Z5S!vQs8oDyff$(bnnI?XGfO?lkws zw>99oGyFdgyiRM93?!;)5PSPNjj8l_zu8PXZq~l>K}j=>PGidaRJ36Z-Xy8n$xs`g zTsHP~vZ;|-^G99{kM@tx%)%*aFEL~}pPV=9*+`y?#PZ*$XU>L`SUno`wA6^*+SnhCmuf;(hO}58|r}H(#B78o7>64z5RFb{fgkxw0p_NW7x-2k7wgZU0HeGg`DfY}4!uupD_n7sie z-u+4}Upx!!|0^=|$cj9CBFkeb+uDeOoS}>FBwygFq@^kuZ>{abJoe?Pm~M^xU89O> zlKo@N3Y9faGCjKau0ys`6`?sNak9K&Dk@8RPX zj~^fCZ*}{~!MAySh!^|d$SwN&onQ1%y?KI9y~%OJv(?VKEBJA*E%tUfH|&Aw57vi0 z`XexU`lE>H4>0x)`#ax@fBx3<@OCa!NzWGIXcg9-_8y2h!1Nh?K^$QE3{0)gd9CQt zRjTL%$Jku$Js2Ex#CE~gv;VOPW{+Z%-nnSJ{9A|}d?}Cp|8My$$GhU&zA$`dXW*}$ zkH7ETHgSM|blcd)KbRhmT!QIw@Ma~}BYYnZG5)EN?FH7-2b|yZCYZmR&w=Sz&ga1J zIiHJ|^QMS7N5R{@j~SZu-VT+`Hh8xZ>*pOZKK6QRXGC6#FgCAAZYP!+pZyqB$ zIK+=U{B801`@5Zvtd+^=-x>Gun9E}g!<2si&DU(Ve8_q{*6c7J%<{xy*(sTwT%Pay zC%o^^I%kh$Jmkbm?vRDweSSxXScfE&6=U6R=jW9*!@eeBJs_Ek{TQ)6#hs!M>p?p| zWpaG8Kc4YD7_lCbjE9_9sVg#S#eO{E_n2a>MqU1^65EqUC6lpN|4>=adEfo5is_Cq zo4p5l$2L9og7;O?_KPkL&P$TTROGxYnS7z$;G|c)@9&aqJ^F>JT3?O1jvj*-c3+jO zXR*t7gW>+AlEu${A?Dy8zecR%lF5TJagA8HS0RsBn;y@4?s$^vBi2dRksEkn_r#o7 z!ElSQl5_af>@}|$=NWb9+h2Ei)U55YsF_`UB&!)Z?mj2IX1qr%ndhNsdqy&OaNh7d z6geHq<;{~ zuaEuwiDVq)!THqB+lwCKWyyHRFT3n>dza0qIP1QYY(_Ds;`_dmjEnBD66>vRB$M-m z>|2*Hk499pIrg1oTy)Gj>{172-48xbnVEby82&#R&{hrDOym6Gw-FC_xh*Q&%;C2X z@9Z0X1JMVI3$u;iJ~6AfGw~ZIW)*v5iLZ;kS>b(CJabms9Z;4-*4*UlkWcx{yV>Q$ zk54c);68S{&%?mnGvQqF*|XL;$b-W@oEaK;ov*pzYwq;BI&x~pJ&-dHTj+>`Z$*X; h^mqIBGc(BNJuX8J=3L@VdfxluUgseHS0%&L<3E+GK#TwY diff --git a/resources/shaders/spirv/post.fs.spv b/resources/shaders/spirv/post.fs.spv deleted file mode 100644 index b6d2fec3f1e906d766194ec03a93915a9384efaf..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6864 zcmZvg2b5%05r+Rx6Lyy*SyUJ?tfDIetIN0ovy8i=FuDu7fO%|YUhlT{bdNp31=Awg z98ft2b3O+n0xAYDXF&<(oO70-py#Vs)pPqD?m2z>{eRW1TeoiAdiUK*`N%=3q(Kd7 zuad0or?PlltpWR=oZ3FMZeekD-TFr!jl$llm>xR&Xi!zjeslF^8^N0;l}ggSsu({c zsiKO?l1?t6yGoN&)011bPEKu}o|&JYURXT4l})#r?QD9s+0AAao68w`Ly2CqJ=0p6 zO%-aY_KjQ9uvSajS)ZG$PjtE%n%Grux3kvT#^}bz=tfzeVM%B0oanSVUBjy+HF|hR z_bS*}yWBW-BR}Q+_bv3_udn~G4wJM{pPO%GV>{~eYnL1A8QcHN#()l%)LB~G)SBN_ zpUN7G#I2?Q9g^@9S$i?-=KP@ve_C_rE;`gy)4k!_*|z5Htd-js(h-toI_>37YdPBx z9wh$XPg0$MkIv_Fc;L}|tOxY`AEkFMZbvd!qp^@J=3_rZ($XZso;rPp$7X}1`FgiL z=lIbDd_n=ARKQyb_~ZgUjWJKjy6voGYd2kxHwyUK1w3EC3kCe#0)Bo0pIg8$E8xrV zZ+mB{JCoV^uosqhWV-+}z3$$S&L%{%*SRCQM$u31g$Z0Xj0tDBu_Nm|;n zVrNoS%WL*XP3qzMGf09*5=>5_Kj3n3s!vWJr(qvll&AK{nN*)O22*e84^I0NE9BH+ z`sv4B+M?6MUv-;0- z@CU1^y*ys{M4!D~4o{zbBzuPEN1p?{5A&qYf!+sxM1wlW{Ruw)v3FnZ3x~ZCRc%h; z*P$BLgIvd7gS{5`Fje$m$@Cb1t!uz-bWBa89i^(-ewd*>C*uDj+&*zVP*ojc^T-?e z;A0E;L|^xiPx>4g|5Vpy{)`VM_h`ts`!jP4f6j330F`xS!avRUJ=cfcjN$Pf-j(<3 zVd}fI=ep28JC~0Kexc#<9=;^kACEY(2Wa^DCZ8kmK@PSvgv;OJ@|Xv4y2A6B{@1## z=nrO((1`QjJkDY7?=FL9JTQBPhX3&YavX7G&(IhTL*#A59n2nr3w`zs?NO@PdXuv> zbZ%GKY74sLBJTtC2AKTheGr&`-UWe?^Bzbs^*%8F)ce5bQ||-wPrXku^*%8A)cnBs zN6in+KQ%uv`qcfv=u`It^H1Fmj6StLF#6Q~6jR4jOdSVrQq6MueV*s!!12D%-Y*${ zm1>sPACQbA-)~bzAM*I$sjA67DCrts3!bsVKE6`2+ys+PAMso~Q#D)ft6T?uD`#d& zS4+ktOWO&m*xDk$LuK=UwP)Oz%O^co+4nJ*Pf5mKY$rnL(~{K@cx-1?kk zXHN2fwP(H2!5%sKdC6q-CAYva))%}FGV%-@{l4h7kdbrX==WvM%h3Ib=jB!nTHL-W z83#{eJDlqC`I=;MT5w-?4!vy}u(*ChvT@Ky9%J3$dj!A8RWQ%wDSgH?V71~~zVFdN zh7P$7AGU6CTd|fmOUA+D3$>a(8}q)!=N*3EDp{X&F5hu3o%45{!`?Ox+PZvCvi|5J z$2LB)pOA%*KkUUe&$k~*#=+CVPx`X=kVg!D>@mP5GIZF#@L~U_y%^+c_cO^j_~QJ3 z?(-*q*^|F;-_rd3rSlP^UrA<@7Tm9$%hx-P$8RLlMaDST!C&eHvher!g?RiyG7dgs z!J5&R+JZdd@kfsbHj$x2eS(iQ{*z>R68O(v^8)|HYg**#UnT2<9x`lF)8W&7PYuEb z@0Wl2JLd|oSO0d7_YU>yc8iv*ULm{9YE}O3;2AsY?f=*qE4Apq&cV|n9{5CEMNVJp z*4_T@K}L-Q6DMT{ zeokTU^Q|B6Y5w`vPch&6Ddt;0#eD0hm~VY>)RyDihqShgNyf7lj1LZd?pE+K)qjln zo39=Ifuj~2@9TygWMOCA$K~uDYq3c(o^hEMIP@oc+*JRulJV#>Z*Yve*~i5Wvas_w zAD1(JjQe=Wc!;=K7(j~C}nWKZGl#$&;Atnbq$ zi_rzX$DbkDw-`KYNNnK7T>ebS?&si<6H7R1GGh{J#t9kzq%w43Z0=&{ADH_o)+>C; zxJQ(X#~$kf7rt=s!(AbK*k~4PJWH}~M|f=yPVdDjE13qlLs9G{ucBoOvitlmmuxQ*DMLpv#jA!17+?C@G_jQcP8SK@5 zzZUp49@|TO&%V}m;L+iId#T%sKCkmW@g4Gd$vAlGuOEqeHs9bj&^y=1xlFRLkWs_I zQNuZ3klQrw@}fR-r_X#I=)Q3-d82;=lPlc4yw$&f)B5)|=kXugZNe4JdqIM2MteL@!JnfFS@)0iumx&9yMd%Lj! diff --git a/resources/shaders/spirv/post.vs.spv b/resources/shaders/spirv/post.vs.spv deleted file mode 100644 index 6d35fb90ef6c4475e3c3396c437bdf31e41ca863..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1080 zcmY+C&1(};6vcnZ%p}!nYt^=X)Y@8I3B`qqAb!z6taK5nxDCM$VIU@w1Szfr_x`0gL*eJ=iYPgJ@34iwGX<`qRR>osAGdREnt;SeETP-Cx?sW+2P|Sk7TTo1yRmA z7vnz%K98!Y;6n7mHQ)fa4`gJtfp;w^$p7OP6w&kbLwSBQo6XOVQ?Lq*2D3%AtY!`_ z=&%8dC&NKG|5(nK<+=MhDQ{S7Iy!WNug=I<)8%RPt*m?MnwrLw;nAe}(yJEB(ezVE zK^EE#b$EvHWLPge?u8D|G@cBPr*+S959pJ}Id-G7#-5?UZz)2LVcuwRwcp;v-<;ay z>2{widd;~K~-st)$;G{7AXm5L|2T<7L7fh`iC{e1me;I-nb8 cyqmbz^uf7rD8h&ROA(@~Ep_)m0 zln~!w=j(wR7lC{6TLeD}6cluU_Z_Gx&*&>g7y}OKX0W|?vR2p4u65+k1IL^DyW7pq z!Qtn+83bQNk8eZbii!o`=*;;leAMrnoiA(ke%)BJ;-NLS_fC$En?3uiQ%0ZbajXCM z<`DKy!~5QE7+X_pCe{-VpBFD@y=l6U#d4%V{GX*@1Xu#*DCt39vt6Q$4CVahDLI$_ z+x_vZE&q}-u-Un+H<9&x1M5wuS9$ef@2LM(%IJM5&$oCw@b@>KpU?iDpP}SxdUvT8 zUyFA??PoUao!WZ0PwPj$yQx*9AF&xbX$y>TKmF@(c(r(uf(H;f{jH`*&U#|s!1bIe zaxgoWJ^s+8O0DziJhooEtFtA3mDyi_$X9FzQ<>j~m|D1;oU7$#lGF1Ry{I>vTKCM` zjDJ(b-W)_9HLoeclbk*EawUCk(hCoZ$;rFy^Oh>IzmZzs#PjW}$!}4`dFRvl^ZS{c zGi+V=THQ+e)a#Gb-O71)?^kknAb8(d|7Iv>f8XU%zDb*5KXd++_kWxkdCxl!a)0UY Hf)4)xUq?Rb diff --git a/resources/shaders/spirv/reproject.vs.spv b/resources/shaders/spirv/reproject.vs.spv deleted file mode 100644 index 9b39096ee1e45cf70d82df2665effa6796fd5f90..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1144 zcmZ9KU279z5QU#)cav(hwQ4`qT3f5$2*nE(K~$uLS}9U#@iqjzhJ`edBx>=>zu>?1 zMv!OrT}0<*_spD`IWzNS?d>kK=rYFxYFnaB3z(-9-~Gem!=35ubm#GtM=}=3f+%N^ zi}9ZWXZ>msSquFuwy{vQUn3@K|-tMsayjM+U{n5vg zf-JOa_FMzLyeq$*O!}kgr}5-0>2tQhuvZH?*bA<+4u-vhQC;g`57;M<`8J|rjh(H* zZzw{ireAA(^&Py>U!R)gd4+wl$kk^bwKjDdd^gn;tJ&Nl@zpEt#J$>4XDhBn{I8Hj zY!g@|r<=I;+azZ$>Cpc?VehXtQIpuWs3v<{Pd(IN5Aky9xkkedN5Rhq_`oKT_~QGp{+k!u;s6VxwDv6yExhKt+JxS31Tvrlyc5Ymy=CbTOJAf<%ieNX u@;*^)Rr}AgdtWR42IQK11~H~v8UI0&zxmj)eHT0l_#()|=KgVf;{EttH~45PYywC@Nwgru3mw=xYdd2@C61l6@#X`Dgng zlrwj>;=JU}nKLuzo}10m*CiyB3^*djE-4AHL1Dks^UL$`y8AwUcl=h2EixmDv&{oL z=fICe-70wmJO&Pdmq12F3Y;Yn$p7O83O0acGry=-SJkSkZZ)HDT%p>{y6)OG#4GXSe8-gvGTlfFZ89y(vxk>9JIq1uR?P1i0Rr=IJLbsz26@*SF~ z9m=r zC;6d}hCig{?+0?zF!cT3?8S8_c^#w2_8im99@}?JZ+Ss!`kr~e_^Rt3p9yw{=l*TT Pn~!9ci~pB|6B6zKMX@=L diff --git a/resources/shaders/spirv/tile_alpha.fs.spv b/resources/shaders/spirv/tile_alpha.fs.spv deleted file mode 100644 index 006cb101c9179314bb137408f2377daa8ff4a5dd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1140 zcmZ9K-Afc<6vltMGqby9X=Z9>ADVp|(nUoO1tlbeP@&NEvO9=mPHgMqZ5RE|-30MF z^Nwu2Fw8vXJaf)-p7&(!%`UX)(&GvBS)fe|n57f%-M#(2?H}Xe_Os_tWz3NUQO-Ow zU)Z*qk2E;AMRAg)u`^Pu1UhX-r!uFo#JFi$ztY^>Zy#2(^zDPUX8{tMBTPC9etjCkng?NmuGQ$kSxAmt_ zgV)Ho0Kr=)XEu?Hy-HXgJuBqQrF!a-KcBQ4moIik>&w5A_}=vrIaiZb&sM@qf$DlI z>0k9*Ppn7Qv)_%_1){Ebv7WhE<{K~VYhJ8}jUIinw*035X2LHhVlK6Mhk!tC! zyXgBhd3baQ!XL37ETs9rP=tm>2#)d3v6ZkKcUd3*tM96w^Jn5*PrTKr-wDoInnQi& z-;jkKVtRpmLj~poA`RrXt@UwZ}9yz_phYw0R+c*Gt)yj m-}@%^D8=mA#2%-Z8a~kt&07%v%QtU*XY*do{h`H6TKom8$2h$J diff --git a/resources/shaders/spirv/tile_alpha_monochrome.vs.spv b/resources/shaders/spirv/tile_alpha_monochrome.vs.spv deleted file mode 100644 index 782bc4f9579eed7822025c38862b31919b4defd8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3876 zcmZvfX>(Ln5Qg7m=FYGvhzPhKg1Dd{CCVzY1_;4u0*S$W940s6%48`gy1|+Rk#eRoJCq{R7 z^Xc7t_q~e58kI~CnYCJL-(^X2^{fThE9ossbxHG*79=f6`cl%jl75x+o1~IT8kBTy zKq_mMhDU3|V`Iakr)!P*`C2!>)=X>7td-WLvrgK`v&9s-6$QDh)o3nE7X=cPAFw6S zO0AL9XwS_r+Vb9^2J%_P3QKE+=oG~QX+G3$wmT5fztQz~$J5S*_En=jL2R&S zBD=6H`REbTF$#yCetO;UerbI z%|;I>@w|kti3b8|>hQ6_+4W9+&g?FWc=T~a*|M`D*3{Qx7~norZ;L1EjVsfgHhkhh zPU{cQ%2tnymL+5=xPf*0YbsA}@`fYGy79W2lNIw|t01#s}G12El;Jh-@@+!y7+MLsz$?kB%s{6-(RC{Hem`p6SF>?cRX{mhHN zXO&pIS*z`T-KVi18owcj4bXbNm27X=Ma-+0elZef&W`w!G%@#1{VR9((AV52p6W zN1T7Kp#PBbI5YTf+FjDeCpkB}@p^)`#d|Ai3?4df`hMmjI>FrE zp%Ytfxz7=|+m6})gMWujV0w)eKG16sLwusw!26Y0JyP#1&iq@0){}=+Hr_9i-NXNA zKnFEodx$spJ&T?_ppw-t_dDP86Zbm0c)4H)waxv^FPQpg9)OQ{{cZAnCzM$KY?iFY z=&O)hASI}^-)^0QqsI|D!GcHOgEKziO~poh#0%l5qJ zd+zui-XF+7A6H^M{gUf~haLC|4W0D-%kKZY&!(MDgHL>Sx$n2VH(s$C>(T$!py9{| zGljPjD{{Eb8-9e{4=KRfM=)0vkyoi=Q>FXNGKVh%0xIpTQ;JnHi__P;He4D^tB zXITx5NhSw9WX@a7_3gMInH+TNAlJ}Be$w+FcuKOlO+Vr9Mag8KhrjPTop~N{`Os%I zGyRtD{YWxdcu}`C$>_{>?4j16aX$UXdy*Lsk2(WK|IbJ^?~DCED;XVm>JWTL6|?=a z&n5K0Lxx(09{zqN87=S?&qLtmvY7K$Mh1H1ig!PH;Bf}^4=r?j?mZE><9(Ln5Qg7mmar&@2#6qpxS${<$||x32*GFu5(BQ|Fu4g=CNpv7CIs9-1i=Nh z%I)7+}n&aHqvHNolM(FJxk{k*(q_FeH<=eG zsd%41B`wtoN%hvu>|B->s`&{da z(bf|mJQ_={B`)`*%XOV(Z&AA>wc6=45k?m=uGvYt#FEN7O}x{Eq)};g(kyL}3}h`A z<4LD8*lM*Wp_Ns^?nIhgIo?`u6(&1|j^1`V=bOl$YS(6xi*r*`N!wjD-UpWV&gJoB z!L;Xfk$>~i14=wEqHFBFfSNkaSjTp)U7In#iy|I9TvocsR>Ybbn-2&4%+%cc@ml@z zWV;2QIFQrYeYB$0E$JY@}-JbhsFw3$V0f=6vn zH>!h;boNBr$!g7dqLK>M2VMWm`i_`XYH2g`5;K3x)+aUdt#>$L`14}Iy1aEO0@R@gcdGZG?`F?PIKRLv9@W~&zENQj+&5tcMIlHl1qoVOPyUooi zYCy6-_N-MwOC;mNTk1S$>ul=EzH`1UDw(ZiE`uyG54#L!#`bE-Xy|*??Xu^fW9Axb zyZiQ-W8^pZ_pp!O_=$b^#18+VgSm9T=*O3rT%O#(f7x>f9s6Kvmwbl({W<*yoQKWe zziM|`49NK_j-c1$$K+u3?4Rb_EdjLMOi5^fO1?ZaH4B zrTW@!;A4IT-k^fMkxUMI-?|Vq?1AZJ7MMKK%j^eJ_w;V?i3zv^5;JEoHL<3`DPmOc%c$0eiRQOW9rnZ-WnGoI5Ye3l(n!EA!rPrkQG=4ari z+^@TKD@jkg4D^tBX3?H!ea~&*!&?d&=oOW0Mm*=b;Nb^ng@#UM$n$>wS)X;=od%!y z?(nnU@?LwvYPL)NNBxE)AIzxki?^4v?U>t3fpXHk1`?tNB=vYazNUh%!m#)v^EvjvE}0DUka=TK4U9@A2R&rYTFv$RI47ALbo?OK&_aIP^B;IZvU`Aj z;=Jc2lYt)Reaq?G4-uDleD-rk-1NQgN+t_0>b5Ewox1{ms5NNVryqG6b7#P#&cMi1a7Yx|nhkmWuEGoQJeK9%fu9X#$f zaM=A)vUs2MS$SJB8Y^gDIgOsIXux#dkxUjIcNaM(C)}TR{l4Rl!zLK{{QZDm{MKag kCgUDh<9>0E-Sayv{QSZ1unTVgN0))lY{Lg;9&~2jzczM-OaK4? diff --git a/resources/shaders/spirv/tile_solid.fs.spv b/resources/shaders/spirv/tile_solid.fs.spv deleted file mode 100644 index cce9973509dfa21e87490918d21e784113db7874..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 376 zcmY+ATMI!!6otRJIqsJfZzAvVfRuPql)U)`N=e}q^4q;A?R`cvHO;KO*4}H)INMLa zkdUWBwi;LrP$H-2db`^W?vKM@G#-kgic_IzY9x5jec7L`LKL(Y>Nu_E0f)l^8v_CV zrw;_}NmsZ1ahaaeTc#-i&xqG})pW9miiQ8;CRXS7)Cs+}aO8k4(8iO1V#(XZ$6RQA s7O`ZP*9l)le&)vu7Eh^72e#xTY30Ue7e@dJ6wOVzPzZn zm#sQ>P4JR z7MIbLD>t>1P_N9&Sw%2cUxy{l<6bB?XNy?J8Ha$&IYv)o88)goiBpSluF=!5Sgg!u z)po->DQOqpllWWkJwGJ26~nI&XM6s+eg84FUY9YwpTK=ojdsE>yU(75%D1tz(ZlDa z7TgyDn3Tn4sJ22?hds{K_c)7O+P<%W@tKpwbS&^@G*8R{OEW?~TsHqb5AuK2*=XO*-fa`!>0zNA0?Jo^Ny4 zO@F|6^O(A}&sn<>&Dl<dD|iPai;;WBb7(oEOot>5B#VRJ^>e_x z?HDg}#)O#z82$ow>L zy2011;_GwXaLj(U{eRL7#uqH|4_qJnP!EhR(j36}0(?Wc&69bv(DaYG=AT>2EO+1i z^RGI(sm}g4c&hykUZ5Vn;B9MT-XHKC_t8;*uM>XH-|jzrPRAwV5Ko-<-5)QV^MTDs z7Ehdy+%svPQ1HV3_} zt={IN!Du!c%&S*L7!>&=40iJ}jH>))fVa}%<&#md*liLrrT>YasjH5p(R6RNsKU;$ ze3ehe^N-0bQ>G)5#-Uo97Sj@ArjCwDn&rz-^r!Q@%BK_pms*C~c@ehCe4J0rMs36G zFrTkYr{!+VJ1uDe?|J@H@HgMVwv&e+A5NEk-R{3jtb;I??|X0`m&3jA!{Wt@Q2H}g z8-09f*@8P_2;*YV59LlMtFWZ5j@vo-;`1GKjnAyio=>XycJwiiaWPmc^4WSmuZELR zP^QFY$06oj^6L-tNwpo8)uN0wGTWi$wjGxH{pjlP|M~lU$xI95Vo)c)v2O39jd3y9 znAGt%)+P0nTK~@rh1QtfgE{!=d(#hozu{*F_^A;-xap_w&G*1fKfRCsC(5js95lp< zwt8RcJfn@6@Yt4~61yAopr5>3`%=TrxcD!64DzPW%{u5Wn7zXfZr*3#h@H8g{({+y z6KY!?7i}Bs-kegR6-gH)omQ$tl40J5cUUqTzSrGHEfLi+Jda?{pLMEd}3kUB2mmegO>&Kxy+X6Udkl6P z4)#CXcFA|1J?^{hvg;JB{_3_5CFA0YIe#LV9bJ c+1-OYANc $@ + mkdir -p $(TARGET_DIR)/gl3 && echo $(GLSL_VERSION_HEADER) > $@ && echo $(HEADER) >> $@ && ( glslangValidator $(GLSLANGFLAGS) -S frag -E $< | sed $(GLSL_SED_ARGS) >> $@ ) || ( rm $@ && exit 1 ) -$(TARGET_DIR)/spirv/%.vs.spv: %.vs.glsl $(INCLUDES) - mkdir -p $(TARGET_DIR)/spirv && glslangValidator $(GLSLANGFLAGS) -G$(GLSL_VERSION) -S vert -o $@ $< +build/metal/%.vs.spv: %.vs.glsl $(INCLUDES) + mkdir -p build/metal && glslangValidator $(GLSLANGFLAGS_METAL) -G$(GLSL_VERSION) -S vert -o $@ $< $(TARGET_DIR)/gl3/%.vs.glsl: %.vs.glsl $(INCLUDES) - mkdir -p $(TARGET_DIR)/gl3 && glslangValidator $(GLSLANGFLAGS) -S vert -E $< | sed $(SED_ARGS) > $@ + mkdir -p $(TARGET_DIR)/gl3 && echo $(GLSL_VERSION_HEADER) > $@ && echo $(HEADER) >> $@ && ( glslangValidator $(GLSLANGFLAGS) -S vert -E $< | sed $(GLSL_SED_ARGS) >> $@ ) || ( rm $@ && exit 1 ) -$(TARGET_DIR)/metal/%.metal: $(TARGET_DIR)/spirv/%.spv - mkdir -p $(TARGET_DIR)/metal && spirv-cross $(SPIRVCROSSFLAGS) --output $@ $< +$(TARGET_DIR)/metal/%.metal: build/metal/%.spv + mkdir -p $(TARGET_DIR)/metal && echo $(HEADER) > $@ && ( $(SPIRVCROSS) $(SPIRVCROSSFLAGS) $< | sed $(METAL_SED_ARGS) >> $@ ) || ( rm $@ && exit 1 ) diff --git a/shaders/debug_solid.vs.glsl b/shaders/debug_solid.vs.glsl index 10b92ad8..8dd2f383 100644 --- a/shaders/debug_solid.vs.glsl +++ b/shaders/debug_solid.vs.glsl @@ -14,9 +14,9 @@ precision highp float; uniform vec2 uFramebufferSize; -in vec2 aPosition; +in ivec2 aPosition; void main() { - vec2 position = aPosition / uFramebufferSize * 2.0 - 1.0; + vec2 position = vec2(aPosition) / uFramebufferSize * 2.0 - 1.0; gl_Position = vec4(position.x, -position.y, 0.0, 1.0); } diff --git a/shaders/debug_texture.vs.glsl b/shaders/debug_texture.vs.glsl index 734916f1..7df2a288 100644 --- a/shaders/debug_texture.vs.glsl +++ b/shaders/debug_texture.vs.glsl @@ -15,13 +15,13 @@ precision highp float; uniform vec2 uFramebufferSize; uniform vec2 uTextureSize; -in vec2 aPosition; -in vec2 aTexCoord; +in ivec2 aPosition; +in ivec2 aTexCoord; out vec2 vTexCoord; void main() { - vTexCoord = aTexCoord / uTextureSize; - vec2 position = aPosition / uFramebufferSize * 2.0 - 1.0; + vTexCoord = vec2(aTexCoord) / uTextureSize; + vec2 position = vec2(aPosition) / uFramebufferSize * 2.0 - 1.0; gl_Position = vec4(position.x, -position.y, 0.0, 1.0); } diff --git a/shaders/demo_ground.vs.glsl b/shaders/demo_ground.vs.glsl index b145ce04..e2a618b6 100644 --- a/shaders/demo_ground.vs.glsl +++ b/shaders/demo_ground.vs.glsl @@ -15,11 +15,11 @@ precision highp float; uniform mat4 uTransform; uniform int uGridlineCount; -in vec2 aPosition; +in ivec2 aPosition; out vec2 vTexCoord; void main() { - vTexCoord = aPosition * float(uGridlineCount); - gl_Position = uTransform * vec4(aPosition.x, 0.0, aPosition.y, 1.0); + vTexCoord = vec2(aPosition * uGridlineCount); + gl_Position = uTransform * vec4(ivec4(aPosition.x, 0, aPosition.y, 1)); } diff --git a/shaders/fill.vs.glsl b/shaders/fill.vs.glsl index f5abbf7e..7b75578b 100644 --- a/shaders/fill.vs.glsl +++ b/shaders/fill.vs.glsl @@ -1,6 +1,6 @@ #version 330 -// pathfinder/resources/fill.vs.glsl +// pathfinder/shaders/fill.vs.glsl // // Copyright © 2019 The Pathfinder Project Developers. // @@ -15,7 +15,7 @@ precision highp float; uniform vec2 uFramebufferSize; uniform vec2 uTileSize; -in vec2 aTessCoord; +in uvec2 aTessCoord; in uint aFromPx; in uint aToPx; in vec2 aFromSubpx; @@ -27,7 +27,7 @@ out vec2 vTo; vec2 computeTileOffset(uint tileIndex, float stencilTextureWidth) { uint tilesPerRow = uint(stencilTextureWidth / uTileSize.x); - uvec2 tileOffset = uvec2(aTileIndex % tilesPerRow, aTileIndex / tilesPerRow); + uvec2 tileOffset = uvec2(tileIndex % tilesPerRow, tileIndex / tilesPerRow); return vec2(tileOffset) * uTileSize; } @@ -38,11 +38,11 @@ void main() { vec2 to = vec2(aToPx & 15u, aToPx >> 4u) + aToSubpx; vec2 position; - if (aTessCoord.x < 0.5) + if (aTessCoord.x == 0u) position.x = floor(min(from.x, to.x)); else position.x = ceil(max(from.x, to.x)); - if (aTessCoord.y < 0.5) + if (aTessCoord.y == 0u) position.y = floor(min(from.y, to.y)); else position.y = uTileSize.y; @@ -50,5 +50,9 @@ void main() { vFrom = from - position; vTo = to - position; - gl_Position = vec4((tileOrigin + position) / uFramebufferSize * 2.0 - 1.0, 0.0, 1.0); + vec2 globalPosition = (tileOrigin + position) / uFramebufferSize * 2.0 - 1.0; +#ifdef PF_ORIGIN_UPPER_LEFT + globalPosition.y = -globalPosition.y; +#endif + gl_Position = vec4(globalPosition, 0.0, 1.0); } diff --git a/shaders/post.vs.glsl b/shaders/post.vs.glsl index 2ee824a7..137cf388 100644 --- a/shaders/post.vs.glsl +++ b/shaders/post.vs.glsl @@ -12,11 +12,11 @@ precision highp float; -in vec2 aPosition; +in ivec2 aPosition; out vec2 vTexCoord; void main() { - vTexCoord = aPosition; - gl_Position = vec4(aPosition * 2.0 - 1.0, 0.0, 1.0); + vTexCoord = vec2(aPosition); + gl_Position = vec4(vec2(aPosition) * 2.0 - 1.0, 0.0, 1.0); } diff --git a/shaders/reproject.vs.glsl b/shaders/reproject.vs.glsl index 91d9f9a9..f10433b1 100644 --- a/shaders/reproject.vs.glsl +++ b/shaders/reproject.vs.glsl @@ -14,11 +14,17 @@ precision highp float; uniform mat4 uNewTransform; -in vec2 aPosition; +in ivec2 aPosition; out vec2 vTexCoord; void main() { - vTexCoord = aPosition; - gl_Position = uNewTransform * vec4(aPosition, 0.0, 1.0); + vec2 position = vec2(aPosition); + vTexCoord = position; + +#ifdef PF_ORIGIN_UPPER_LEFT + // FIXME(pcwalton): This is wrong. + position.y = 1.0 - position.y; +#endif + gl_Position = uNewTransform * vec4(position, 0.0, 1.0); } diff --git a/shaders/tile_alpha_vertex.inc.glsl b/shaders/tile_alpha_vertex.inc.glsl index 6993a13d..e5211809 100644 --- a/shaders/tile_alpha_vertex.inc.glsl +++ b/shaders/tile_alpha_vertex.inc.glsl @@ -13,10 +13,10 @@ uniform vec2 uTileSize; uniform vec2 uStencilTextureSize; uniform vec2 uViewBoxOrigin; -in vec2 aTessCoord; +in uvec2 aTessCoord; in uvec3 aTileOrigin; in int aBackdrop; -in uint aTileIndex; +in int aTileIndex; out vec2 vTexCoord; out float vBackdrop; @@ -32,9 +32,9 @@ vec2 computeTileOffset(uint tileIndex, float stencilTextureWidth) { void computeVaryings() { vec2 origin = vec2(aTileOrigin.xy) + vec2(aTileOrigin.z & 15u, aTileOrigin.z >> 4u) * 256.0; - vec2 pixelPosition = (origin + aTessCoord) * uTileSize + uViewBoxOrigin; + vec2 pixelPosition = (origin + vec2(aTessCoord)) * uTileSize + uViewBoxOrigin; vec2 position = (pixelPosition / uFramebufferSize * 2.0 - 1.0) * vec2(1.0, -1.0); - vec2 maskTexCoordOrigin = computeTileOffset(aTileIndex, uStencilTextureSize.x); + vec2 maskTexCoordOrigin = computeTileOffset(uint(aTileIndex), uStencilTextureSize.x); vec2 maskTexCoord = maskTexCoordOrigin + aTessCoord * uTileSize; vTexCoord = maskTexCoord / uStencilTextureSize; diff --git a/shaders/tile_solid_vertex.inc.glsl b/shaders/tile_solid_vertex.inc.glsl index 73f30cd0..fc7c8bc5 100644 --- a/shaders/tile_solid_vertex.inc.glsl +++ b/shaders/tile_solid_vertex.inc.glsl @@ -12,18 +12,17 @@ uniform vec2 uFramebufferSize; uniform vec2 uTileSize; uniform vec2 uViewBoxOrigin; -in vec2 aTessCoord; -in vec2 aTileOrigin; +in uvec2 aTessCoord; +in ivec2 aTileOrigin; out vec4 vColor; vec4 getColor(); void computeVaryings() { - vec2 pixelPosition = (aTileOrigin + aTessCoord) * uTileSize + uViewBoxOrigin; + vec2 pixelPosition = vec2(aTileOrigin + ivec2(aTessCoord)) * uTileSize + uViewBoxOrigin; vec2 position = (pixelPosition / uFramebufferSize * 2.0 - 1.0) * vec2(1.0, -1.0); vColor = getColor(); - //vColor = vec4(1.0, 0.0, 0.0, 1.0); gl_Position = vec4(position, 0.0, 1.0); } diff --git a/ui/src/lib.rs b/ui/src/lib.rs index 794e5839..18817224 100644 --- a/ui/src/lib.rs +++ b/ui/src/lib.rs @@ -22,7 +22,7 @@ use pathfinder_geometry::basic::rect::RectI; use pathfinder_geometry::color::ColorU; use pathfinder_gpu::resources::ResourceLoader; use pathfinder_gpu::{BlendState, BufferData, BufferTarget, BufferUploadMode, Device, Primitive}; -use pathfinder_gpu::{RenderState, UniformData, VertexAttrClass}; +use pathfinder_gpu::{RenderOptions, RenderState, RenderTarget, UniformData, VertexAttrClass}; use pathfinder_gpu::{VertexAttrDescriptor, VertexAttrType}; use pathfinder_simd::default::F32x4; use serde_json; @@ -131,7 +131,11 @@ impl UIPresenter where D: Device { self.draw_rect(device, rect, color, false); } - fn draw_rect(&self, device: &D, rect: RectI, color: ColorU, filled: bool) { + fn draw_rect(&self, + device: &D, + rect: RectI, + color: ColorU, + filled: bool) { let vertex_data = [ DebugSolidVertex::new(rect.origin()), DebugSolidVertex::new(rect.upper_right()), @@ -160,8 +164,6 @@ impl UIPresenter where D: Device { index_data: &[u32], color: ColorU, filled: bool) { - device.bind_vertex_array(&self.solid_vertex_array.vertex_array); - device.allocate_buffer(&self.solid_vertex_array.vertex_buffer, BufferData::Memory(vertex_data), BufferTarget::Vertex, @@ -171,15 +173,23 @@ impl UIPresenter where D: Device { BufferTarget::Index, BufferUploadMode::Dynamic); - device.use_program(&self.solid_program.program); - device.set_uniform(&self.solid_program.framebuffer_size_uniform, - UniformData::Vec2(self.framebuffer_size.0.to_f32x4())); - set_color_uniform(device, &self.solid_program.color_uniform, color); - let primitive = if filled { Primitive::Triangles } else { Primitive::Lines }; - device.draw_elements(primitive, index_data.len() as u32, &RenderState { - blend: BlendState::RGBOneAlphaOneMinusSrcAlpha, - ..RenderState::default() + device.draw_elements(index_data.len() as u32, &RenderState { + target: &RenderTarget::Default, + program: &self.solid_program.program, + vertex_array: &self.solid_vertex_array.vertex_array, + primitive, + uniforms: &[ + (&self.solid_program.framebuffer_size_uniform, + UniformData::Vec2(self.framebuffer_size.0.to_f32x4())), + (&self.solid_program.color_uniform, get_color_uniform(color)), + ], + textures: &[], + viewport: RectI::new(Vector2I::default(), self.framebuffer_size), + options: RenderOptions { + blend: BlendState::RGBOneAlphaOneMinusSrcAlpha, + ..RenderOptions::default() + }, }); } @@ -396,19 +406,25 @@ impl UIPresenter where D: Device { BufferTarget::Index, BufferUploadMode::Dynamic); - device.bind_vertex_array(&self.texture_vertex_array.vertex_array); - device.use_program(&self.texture_program.program); - device.set_uniform(&self.texture_program.framebuffer_size_uniform, - UniformData::Vec2(self.framebuffer_size.0.to_f32x4())); - device.set_uniform(&self.texture_program.texture_size_uniform, - UniformData::Vec2(device.texture_size(&texture).0.to_f32x4())); - set_color_uniform(device, &self.texture_program.color_uniform, color); - device.bind_texture(texture, 0); - device.set_uniform(&self.texture_program.texture_uniform, UniformData::TextureUnit(0)); - - device.draw_elements(Primitive::Triangles, index_data.len() as u32, &RenderState { - blend: BlendState::RGBOneAlphaOneMinusSrcAlpha, - ..RenderState::default() + device.draw_elements(index_data.len() as u32, &RenderState { + target: &RenderTarget::Default, + program: &self.texture_program.program, + vertex_array: &self.texture_vertex_array.vertex_array, + primitive: Primitive::Triangles, + textures: &[&texture], + uniforms: &[ + (&self.texture_program.framebuffer_size_uniform, + UniformData::Vec2(self.framebuffer_size.0.to_f32x4())), + (&self.texture_program.color_uniform, get_color_uniform(color)), + (&self.texture_program.texture_uniform, UniformData::TextureUnit(0)), + (&self.texture_program.texture_size_uniform, + UniformData::Vec2(device.texture_size(&texture).0.to_f32x4())) + ], + viewport: RectI::new(Vector2I::default(), self.framebuffer_size), + options: RenderOptions { + blend: BlendState::RGBOneAlphaOneMinusSrcAlpha, + ..RenderOptions::default() + }, }); } @@ -508,9 +524,9 @@ impl UIPresenter where D: Device { let highlight_size = Vector2I::new(SEGMENT_SIZE, BUTTON_HEIGHT); let x_offset = value as i32 * SEGMENT_SIZE + (value as i32 - 1); self.draw_solid_rounded_rect(device, - RectI::new(origin + Vector2I::new(x_offset, 0), + RectI::new(origin + Vector2I::new(x_offset, 0), highlight_size), - TEXT_COLOR); + TEXT_COLOR); } let mut segment_origin = origin + Vector2I::new(SEGMENT_SIZE + 1, 0); @@ -520,9 +536,9 @@ impl UIPresenter where D: Device { Some(value) if value == prev_segment_index || value == next_segment_index => {} _ => { self.draw_line(device, - segment_origin, - segment_origin + Vector2I::new(0, BUTTON_HEIGHT), - TEXT_COLOR); + segment_origin, + segment_origin + Vector2I::new(0, BUTTON_HEIGHT), + TEXT_COLOR); } } segment_origin = segment_origin + Vector2I::new(SEGMENT_SIZE + 1, 0); @@ -590,25 +606,25 @@ impl DebugTextureVertexArray where D: Device { let tex_coord_attr = device.get_vertex_attr(&debug_texture_program.program, "TexCoord") .unwrap(); - device.bind_vertex_array(&vertex_array); - device.use_program(&debug_texture_program.program); - device.bind_buffer(&vertex_buffer, BufferTarget::Vertex); - device.bind_buffer(&index_buffer, BufferTarget::Index); - device.configure_vertex_attr(&position_attr, &VertexAttrDescriptor { + device.bind_buffer(&vertex_array, &vertex_buffer, BufferTarget::Vertex); + device.bind_buffer(&vertex_array, &index_buffer, BufferTarget::Index); + device.configure_vertex_attr(&vertex_array, &position_attr, &VertexAttrDescriptor { size: 2, - class: VertexAttrClass::Float, - attr_type: VertexAttrType::U16, + class: VertexAttrClass::Int, + attr_type: VertexAttrType::I16, stride: DEBUG_TEXTURE_VERTEX_SIZE, offset: 0, divisor: 0, + buffer_index: 0, }); - device.configure_vertex_attr(&tex_coord_attr, &VertexAttrDescriptor { + device.configure_vertex_attr(&vertex_array, &tex_coord_attr, &VertexAttrDescriptor { size: 2, - class: VertexAttrClass::Float, - attr_type: VertexAttrType::U16, + class: VertexAttrClass::Int, + attr_type: VertexAttrType::I16, stride: DEBUG_TEXTURE_VERTEX_SIZE, offset: 4, divisor: 0, + buffer_index: 0, }); DebugTextureVertexArray { vertex_array, vertex_buffer, index_buffer } @@ -626,19 +642,18 @@ impl DebugSolidVertexArray where D: Device { let (vertex_buffer, index_buffer) = (device.create_buffer(), device.create_buffer()); let vertex_array = device.create_vertex_array(); - let position_attr = device.get_vertex_attr(&debug_solid_program.program, "Position") - .unwrap(); - device.bind_vertex_array(&vertex_array); - device.use_program(&debug_solid_program.program); - device.bind_buffer(&vertex_buffer, BufferTarget::Vertex); - device.bind_buffer(&index_buffer, BufferTarget::Index); - device.configure_vertex_attr(&position_attr, &VertexAttrDescriptor { + let position_attr = + device.get_vertex_attr(&debug_solid_program.program, "Position").unwrap(); + device.bind_buffer(&vertex_array, &vertex_buffer, BufferTarget::Vertex); + device.bind_buffer(&vertex_array, &index_buffer, BufferTarget::Index); + device.configure_vertex_attr(&vertex_array, &position_attr, &VertexAttrDescriptor { size: 2, - class: VertexAttrClass::Float, - attr_type: VertexAttrType::U16, + class: VertexAttrClass::Int, + attr_type: VertexAttrType::I16, stride: DEBUG_SOLID_VERTEX_SIZE, offset: 0, divisor: 0, + buffer_index: 0, }); DebugSolidVertexArray { vertex_array, vertex_buffer, index_buffer } @@ -714,9 +729,9 @@ impl CornerRects { } } -fn set_color_uniform(device: &D, uniform: &D::Uniform, color: ColorU) where D: Device { +fn get_color_uniform(color: ColorU) -> UniformData { let color = F32x4::new(color.r as f32, color.g as f32, color.b as f32, color.a as f32); - device.set_uniform(uniform, UniformData::Vec4(color * F32x4::splat(1.0 / 255.0))); + UniformData::Vec4(color * F32x4::splat(1.0 / 255.0)) } #[derive(Clone, Copy)] From 71623eaab312ee0c33ba8ffa70954e166b564dfb Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Thu, 20 Jun 2019 12:34:55 -0700 Subject: [PATCH 3/5] Make Metal dependencies in the demo Mac-only --- demo/common/Cargo.toml | 6 +++--- demo/native/Cargo.toml | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/demo/common/Cargo.toml b/demo/common/Cargo.toml index 3d2a88cb..c73270df 100644 --- a/demo/common/Cargo.toml +++ b/demo/common/Cargo.toml @@ -31,9 +31,6 @@ path = "../../gl" [dependencies.pathfinder_gpu] path = "../../gpu" -[dependencies.pathfinder_metal] -path = "../../metal" - [dependencies.pathfinder_renderer] path = "../../renderer" @@ -48,3 +45,6 @@ path = "../../ui" [target.'cfg(target_os = "macos")'.dependencies] metal = "0.14" + +[target.'cfg(target_os = "macos")'.dependencies.pathfinder_metal] +path = "../../metal" diff --git a/demo/native/Cargo.toml b/demo/native/Cargo.toml index 12515c04..05c33dd3 100644 --- a/demo/native/Cargo.toml +++ b/demo/native/Cargo.toml @@ -28,9 +28,6 @@ path = "../../gl" [dependencies.pathfinder_gpu] path = "../../gpu" -[dependencies.pathfinder_metal] -path = "../../metal" - [dependencies.pathfinder_simd] path = "../../simd" @@ -38,5 +35,8 @@ path = "../../simd" foreign-types = "0.3" metal = "0.14" +[target.'cfg(target_os = "macos")'.dependencies.pathfinder_metal] +path = "../../metal" + [target.'cfg(not(windows))'.dependencies] jemallocator = "0.1" From d2fbb23031f0eb2608d598bdec2cdd34cf1cb0c0 Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Thu, 20 Jun 2019 13:01:54 -0700 Subject: [PATCH 4/5] Expose more stroke features in the C API --- c/include/pathfinder/pathfinder.h | 11 ++++++++++ c/src/lib.rs | 35 ++++++++++++++++++++++++++++++- 2 files changed, 45 insertions(+), 1 deletion(-) diff --git a/c/include/pathfinder/pathfinder.h b/c/include/pathfinder/pathfinder.h index d924ce7b..b89404d4 100644 --- a/c/include/pathfinder/pathfinder.h +++ b/c/include/pathfinder/pathfinder.h @@ -25,6 +25,10 @@ extern "C" { #define PF_LINE_CAP_SQUARE 1 #define PF_LINE_CAP_ROUND 2 +#define PF_LINE_JOIN_MITER 0 +#define PF_LINE_JOIN_BEVEL 1 +#define PF_LINE_JOIN_ROUND 2 + // `gl` #define PF_GL_VERSION_GL3 0 @@ -45,6 +49,7 @@ typedef struct PFPath *PFPathRef; struct PFCanvasFontContext; typedef struct PFCanvasFontContext *PFCanvasFontContextRef; typedef uint8_t PFLineCap; +typedef uint8_t PFLineJoin; // `geometry` @@ -116,6 +121,12 @@ void PFCanvasFillRect(PFCanvasRef canvas, const PFRectF *rect); void PFCanvasStrokeRect(PFCanvasRef canvas, const PFRectF *rect); void PFCanvasSetLineWidth(PFCanvasRef canvas, float new_line_width); void PFCanvasSetLineCap(PFCanvasRef canvas, PFLineCap new_line_cap); +void PFCanvasSetLineJoin(PFCanvasRef canvas, PFLineJoin new_line_join); +void PFCanvasSetMiterLimit(PFCanvasRef canvas, float new_miter_limit); +void PFCanvasSetLineDash(PFCanvasRef canvas, + const float *new_line_dashes, + size_t new_line_dash_count); +void PFCanvasSetLineDashOffset(PFCanvasRef canvas, float offset); void PFCanvasFillPath(PFCanvasRef canvas, PFPathRef path); void PFCanvasStrokePath(PFCanvasRef canvas, PFPathRef path); PFPathRef PFPathCreate(); diff --git a/c/src/lib.rs b/c/src/lib.rs index 7454e90c..e9cb913d 100644 --- a/c/src/lib.rs +++ b/c/src/lib.rs @@ -11,7 +11,7 @@ //! C bindings to Pathfinder. use gl; -use pathfinder_canvas::{CanvasFontContext, CanvasRenderingContext2D, Path2D}; +use pathfinder_canvas::{CanvasFontContext, CanvasRenderingContext2D, LineJoin, Path2D}; use pathfinder_geometry::basic::vector::{Vector2F, Vector2I}; use pathfinder_geometry::basic::rect::{RectF, RectI}; use pathfinder_geometry::color::ColorF; @@ -27,14 +27,20 @@ use pathfinder_renderer::scene::Scene; use pathfinder_simd::default::F32x4; use std::ffi::CString; use std::os::raw::{c_char, c_void}; +use std::slice; // Constants // `canvas` + pub const PF_LINE_CAP_BUTT: u8 = 0; pub const PF_LINE_CAP_SQUARE: u8 = 1; pub const PF_LINE_CAP_ROUND: u8 = 2; +pub const PF_LINE_JOIN_MITER: u8 = 0; +pub const PF_LINE_JOIN_BEVEL: u8 = 1; +pub const PF_LINE_JOIN_ROUND: u8 = 2; + // `renderer` pub const PF_RENDERER_OPTIONS_FLAGS_HAS_BACKGROUND_COLOR: u8 = 0x1; @@ -45,6 +51,7 @@ pub type PFCanvasRef = *mut CanvasRenderingContext2D; pub type PFPathRef = *mut Path2D; pub type PFCanvasFontContextRef = *mut CanvasFontContext; pub type PFLineCap = u8; +pub type PFLineJoin = u8; // `geometry` #[repr(C)] @@ -164,6 +171,32 @@ pub unsafe extern "C" fn PFCanvasSetLineCap(canvas: PFCanvasRef, new_line_cap: P }); } +#[no_mangle] +pub unsafe extern "C" fn PFCanvasSetLineJoin(canvas: PFCanvasRef, new_line_join: PFLineJoin) { + (*canvas).set_line_join(match new_line_join { + PF_LINE_JOIN_BEVEL => LineJoin::Bevel, + PF_LINE_JOIN_ROUND => LineJoin::Round, + _ => LineJoin::Miter, + }); +} + +#[no_mangle] +pub unsafe extern "C" fn PFCanvasSetMiterLimit(canvas: PFCanvasRef, new_miter_limit: f32) { + (*canvas).set_miter_limit(new_miter_limit); +} + +#[no_mangle] +pub unsafe extern "C" fn PFCanvasSetLineDash(canvas: PFCanvasRef, + new_line_dashes: *const f32, + new_line_dash_count: usize) { + (*canvas).set_line_dash(slice::from_raw_parts(new_line_dashes, new_line_dash_count).to_vec()) +} + +#[no_mangle] +pub unsafe extern "C" fn PFCanvasSetLineDashOffset(canvas: PFCanvasRef, new_offset: f32) { + (*canvas).set_line_dash_offset(new_offset) +} + /// Consumes the path. #[no_mangle] pub unsafe extern "C" fn PFCanvasFillPath(canvas: PFCanvasRef, path: PFPathRef) { From 2129e4f2e128afd95b04aabfca48490ca7c51967 Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Thu, 20 Jun 2019 15:51:25 -0700 Subject: [PATCH 5/5] Add missing path methods to the C API --- c/include/pathfinder/pathfinder.h | 20 ++++++++++++++ c/src/lib.rs | 44 ++++++++++++++++++++++++++++++- 2 files changed, 63 insertions(+), 1 deletion(-) diff --git a/c/include/pathfinder/pathfinder.h b/c/include/pathfinder/pathfinder.h index b89404d4..6073bb51 100644 --- a/c/include/pathfinder/pathfinder.h +++ b/c/include/pathfinder/pathfinder.h @@ -29,6 +29,11 @@ extern "C" { #define PF_LINE_JOIN_BEVEL 1 #define PF_LINE_JOIN_ROUND 2 +// `geometry` + +#define PF_ARC_DIRECTION_CW 0 +#define PF_ARC_DIRECTION_CCW 1 + // `gl` #define PF_GL_VERSION_GL3 0 @@ -50,6 +55,7 @@ struct PFCanvasFontContext; typedef struct PFCanvasFontContext *PFCanvasFontContextRef; typedef uint8_t PFLineCap; typedef uint8_t PFLineJoin; +typedef uint8_t PFArcDirection; // `geometry` @@ -139,6 +145,20 @@ void PFPathBezierCurveTo(PFPathRef path, const PFVector2F *ctrl0, const PFVector2F *ctrl1, const PFVector2F *to); +void PFPathArc(PFPathRef path, + const PFVector2F *center, + float radius, + float start_angle, + float end_angle, + PFArcDirection direction); +void PFPathArcTo(PFPathRef path, const PFVector2F *ctrl, const PFVector2F *to, float radius); +void PFPathRect(PFPathRef path, const PFRectF *rect); +void PFPathEllipse(PFPathRef path, + const PFVector2F *center, + const PFVector2F *axes, + float rotation, + float start_angle, + float end_angle); void PFPathClosePath(PFPathRef path); // `gl` diff --git a/c/src/lib.rs b/c/src/lib.rs index e9cb913d..4fc204f2 100644 --- a/c/src/lib.rs +++ b/c/src/lib.rs @@ -12,9 +12,10 @@ use gl; use pathfinder_canvas::{CanvasFontContext, CanvasRenderingContext2D, LineJoin, Path2D}; -use pathfinder_geometry::basic::vector::{Vector2F, Vector2I}; use pathfinder_geometry::basic::rect::{RectF, RectI}; +use pathfinder_geometry::basic::vector::{Vector2F, Vector2I}; use pathfinder_geometry::color::ColorF; +use pathfinder_geometry::outline::ArcDirection; use pathfinder_geometry::stroke::LineCap; use pathfinder_gl::{GLDevice, GLVersion}; use pathfinder_gpu::resources::{FilesystemResourceLoader, ResourceLoader}; @@ -41,7 +42,13 @@ pub const PF_LINE_JOIN_MITER: u8 = 0; pub const PF_LINE_JOIN_BEVEL: u8 = 1; pub const PF_LINE_JOIN_ROUND: u8 = 2; +// `geometry` + +pub const PF_ARC_DIRECTION_CW: u8 = 0; +pub const PF_ARC_DIRECTION_CCW: u8 = 1; + // `renderer` + pub const PF_RENDERER_OPTIONS_FLAGS_HAS_BACKGROUND_COLOR: u8 = 0x1; // Types @@ -52,6 +59,7 @@ pub type PFPathRef = *mut Path2D; pub type PFCanvasFontContextRef = *mut CanvasFontContext; pub type PFLineCap = u8; pub type PFLineJoin = u8; +pub type PFArcDirection = u8; // `geometry` #[repr(C)] @@ -249,6 +257,40 @@ pub unsafe extern "C" fn PFPathBezierCurveTo(path: PFPathRef, (*path).bezier_curve_to((*ctrl0).to_rust(), (*ctrl1).to_rust(), (*to).to_rust()) } +#[no_mangle] +pub unsafe extern "C" fn PFPathArc(path: PFPathRef, + center: *const PFVector2F, + radius: f32, + start_angle: f32, + end_angle: f32, + direction: PFArcDirection) { + let direction = if direction == 0 { ArcDirection::CW } else { ArcDirection::CCW }; + (*path).arc((*center).to_rust(), radius, start_angle, end_angle, direction) +} + +#[no_mangle] +pub unsafe extern "C" fn PFPathArcTo(path: PFPathRef, + ctrl: *const PFVector2F, + to: *const PFVector2F, + radius: f32) { + (*path).arc_to((*ctrl).to_rust(), (*to).to_rust(), radius) +} + +#[no_mangle] +pub unsafe extern "C" fn PFPathRect(path: PFPathRef, rect: *const PFRectF) { + (*path).rect((*rect).to_rust()) +} + +#[no_mangle] +pub unsafe extern "C" fn PFPathEllipse(path: PFPathRef, + center: *const PFVector2F, + axes: *const PFVector2F, + rotation: f32, + start_angle: f32, + end_angle: f32) { + (*path).ellipse((*center).to_rust(), (*axes).to_rust(), rotation, start_angle, end_angle) +} + #[no_mangle] pub unsafe extern "C" fn PFPathClosePath(path: PFPathRef) { (*path).close_path()