From 520817e909e04b30a42da345c011bdd9b2938143 Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Thu, 7 May 2020 16:33:03 -0700 Subject: [PATCH] Add OpenGL 4.3 support to the GL backend, enabling compute shader on non-Metal platforms --- demo/native/src/main.rs | 7 +- gl/src/lib.rs | 70 ++- resources/shaders/gl4/blit.fs.glsl | 28 + resources/shaders/gl4/blit.vs.glsl | 30 + resources/shaders/gl4/debug_solid.fs.glsl | 25 + resources/shaders/gl4/debug_solid.vs.glsl | 26 + resources/shaders/gl4/debug_texture.fs.glsl | 29 + resources/shaders/gl4/debug_texture.vs.glsl | 31 + resources/shaders/gl4/demo_ground.fs.glsl | 29 + resources/shaders/gl4/demo_ground.vs.glsl | 29 + resources/shaders/gl4/fill.cs.glsl | 97 ++++ resources/shaders/gl4/fill.fs.glsl | 60 ++ resources/shaders/gl4/fill.vs.glsl | 68 +++ resources/shaders/gl4/reproject.fs.glsl | 30 + resources/shaders/gl4/reproject.vs.glsl | 34 ++ resources/shaders/gl4/stencil.fs.glsl | 24 + resources/shaders/gl4/stencil.vs.glsl | 23 + resources/shaders/gl4/tile.fs.glsl | 611 ++++++++++++++++++++ resources/shaders/gl4/tile.vs.glsl | 56 ++ resources/shaders/gl4/tile_clip.fs.glsl | 28 + resources/shaders/gl4/tile_clip.vs.glsl | 33 ++ resources/shaders/gl4/tile_copy.fs.glsl | 27 + resources/shaders/gl4/tile_copy.vs.glsl | 27 + resources/shaders/metal/tile.fs.metal | 2 - shaders/Makefile | 19 +- 25 files changed, 1414 insertions(+), 29 deletions(-) create mode 100644 resources/shaders/gl4/blit.fs.glsl create mode 100644 resources/shaders/gl4/blit.vs.glsl create mode 100644 resources/shaders/gl4/debug_solid.fs.glsl create mode 100644 resources/shaders/gl4/debug_solid.vs.glsl create mode 100644 resources/shaders/gl4/debug_texture.fs.glsl create mode 100644 resources/shaders/gl4/debug_texture.vs.glsl create mode 100644 resources/shaders/gl4/demo_ground.fs.glsl create mode 100644 resources/shaders/gl4/demo_ground.vs.glsl create mode 100644 resources/shaders/gl4/fill.cs.glsl create mode 100644 resources/shaders/gl4/fill.fs.glsl create mode 100644 resources/shaders/gl4/fill.vs.glsl create mode 100644 resources/shaders/gl4/reproject.fs.glsl create mode 100644 resources/shaders/gl4/reproject.vs.glsl create mode 100644 resources/shaders/gl4/stencil.fs.glsl create mode 100644 resources/shaders/gl4/stencil.vs.glsl create mode 100644 resources/shaders/gl4/tile.fs.glsl create mode 100644 resources/shaders/gl4/tile.vs.glsl create mode 100644 resources/shaders/gl4/tile_clip.fs.glsl create mode 100644 resources/shaders/gl4/tile_clip.vs.glsl create mode 100644 resources/shaders/gl4/tile_copy.fs.glsl create mode 100644 resources/shaders/gl4/tile_copy.vs.glsl diff --git a/demo/native/src/main.rs b/demo/native/src/main.rs index f42a81e2..872a76a2 100644 --- a/demo/native/src/main.rs +++ b/demo/native/src/main.rs @@ -143,7 +143,12 @@ enum CustomEvent { } impl Window for WindowImpl { - #[cfg(any(not(target_os = "macos"), feature = "pf-gl"))] + #[cfg(not(target_os = "macos"))] + fn gl_version(&self) -> GLVersion { + GLVersion::GL4 + } + + #[cfg(all(target_os = "macos", feature = "pf-gl"))] fn gl_version(&self) -> GLVersion { GLVersion::GL3 } diff --git a/gl/src/lib.rs b/gl/src/lib.rs index 1c3173ac..232e0ccc 100644 --- a/gl/src/lib.rs +++ b/gl/src/lib.rs @@ -18,10 +18,11 @@ use gl::types::{GLuint, GLvoid}; use half::f16; use pathfinder_geometry::rect::RectI; use pathfinder_geometry::vector::Vector2I; -use pathfinder_gpu::{BlendFactor, BlendOp, BufferData, BufferTarget, BufferUploadMode, ClearOps, ComputeDimensions, ComputeState}; -use pathfinder_gpu::{DepthFunc, Device, ImageAccess, ImageBinding, Primitive, ProgramKind, RenderOptions, RenderState, RenderTarget}; -use pathfinder_gpu::{ShaderKind, StencilFunc, TextureData, TextureDataRef, TextureFormat}; -use pathfinder_gpu::{TextureSamplingFlags, UniformData, VertexAttrClass}; +use pathfinder_gpu::{BlendFactor, BlendOp, BufferData, BufferTarget, BufferUploadMode, ClearOps}; +use pathfinder_gpu::{ComputeDimensions, ComputeState, DepthFunc, Device, ImageAccess}; +use pathfinder_gpu::{ImageBinding, Primitive, ProgramKind, RenderOptions, RenderState}; +use pathfinder_gpu::{RenderTarget, ShaderKind, StencilFunc, TextureData, TextureDataRef}; +use pathfinder_gpu::{TextureFormat, TextureSamplingFlags, UniformData, VertexAttrClass}; use pathfinder_gpu::{VertexAttrDescriptor, VertexAttrType}; use pathfinder_resources::ResourceLoader; use pathfinder_simd::default::F32x4; @@ -68,6 +69,7 @@ impl GLDevice { } render_state.uniforms.iter().for_each(|(uniform, data)| self.set_uniform(uniform, data)); + self.set_render_options(&render_state.options); } @@ -81,6 +83,10 @@ impl GLDevice { } compute_state.uniforms.iter().for_each(|(uniform, data)| self.set_uniform(uniform, data)); + + for &(storage_buffer, buffer) in compute_state.storage_buffers { + self.set_storage_buffer(storage_buffer, buffer); + } } fn set_render_options(&self, render_options: &RenderOptions) { @@ -196,6 +202,20 @@ impl GLDevice { } } + fn set_storage_buffer(&self, storage_buffer: &GLStorageBuffer, buffer: &GLBuffer) { + unsafe { + gl::BindBufferBase(gl::SHADER_STORAGE_BUFFER, + storage_buffer.location as GLuint, + buffer.gl_buffer); + } + } + + fn unset_storage_buffer(&self, storage_buffer: &GLStorageBuffer) { + unsafe { + gl::BindBufferBase(gl::SHADER_STORAGE_BUFFER, storage_buffer.location as GLuint, 0); + } + } + 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) { @@ -207,6 +227,9 @@ impl GLDevice { } fn reset_compute_state(&self, compute_state: &ComputeState) { + for &(storage_buffer, _) in compute_state.storage_buffers { + self.unset_storage_buffer(storage_buffer); + } for image_unit in 0..(compute_state.images.len() as u32) { self.unbind_image(image_unit); } @@ -372,12 +395,7 @@ impl Device for GLDevice { } } - match shaders { - ProgramKind::Raster { vertex: vertex_shader, fragment: fragment_shader } => { - GLProgram { gl_program, vertex_shader, fragment_shader } - } - ProgramKind::Compute(_) => unimplemented!(), - } + GLProgram { gl_program, shaders } } #[inline] @@ -774,18 +792,28 @@ impl Device for GLDevice { } #[inline] - fn create_shader( - &self, - resources: &dyn ResourceLoader, - name: &str, - kind: ShaderKind, - ) -> Self::Shader { + fn create_shader(&self, resources: &dyn ResourceLoader, name: &str, kind: ShaderKind) + -> Self::Shader { + match (self.version, kind) { + (GLVersion::GL3, ShaderKind::Compute) | (GLVersion::GLES3, ShaderKind::Compute) => { + panic!("Compute shaders are not supported on OpenGL versions prior to 4!") + } + (GLVersion::GL3, ShaderKind::Vertex) | + (GLVersion::GL3, ShaderKind::Fragment) | + (GLVersion::GLES3, ShaderKind::Vertex) | + (GLVersion::GLES3, ShaderKind::Fragment) | + (GLVersion::GL4, _) => {} + } + let directory = match self.version { + GLVersion::GL3 | GLVersion::GLES3 => "gl3", + GLVersion::GL4 => "gl4", + }; let suffix = match kind { ShaderKind::Vertex => 'v', ShaderKind::Fragment => 'f', ShaderKind::Compute => 'c', }; - let path = format!("shaders/gl3/{}.{}s.glsl", name, suffix); + let path = format!("shaders/{}/{}.{}s.glsl", directory, name, suffix); self.create_shader_from_source(name, &resources.slurp(&path).unwrap(), kind) } @@ -1087,9 +1115,7 @@ pub struct GLStorageBuffer { pub struct GLProgram { pub gl_program: GLuint, #[allow(dead_code)] - vertex_shader: GLShader, - #[allow(dead_code)] - fragment_shader: GLShader, + shaders: ProgramKind, } impl Drop for GLProgram { @@ -1329,7 +1355,7 @@ pub enum GLVersion { /// OpenGL ES 3.0+. GLES3 = 1, /// OpenGL 4.3+, core profile. - GL4_3 = 2, + GL4 = 2, } impl GLVersion { @@ -1337,7 +1363,7 @@ impl GLVersion { match *self { GLVersion::GL3 => "330", GLVersion::GLES3 => "300 es", - GLVersion::GL4_3 => "430", + GLVersion::GL4 => "430", } } } diff --git a/resources/shaders/gl4/blit.fs.glsl b/resources/shaders/gl4/blit.fs.glsl new file mode 100644 index 00000000..4d8cb41e --- /dev/null +++ b/resources/shaders/gl4/blit.fs.glsl @@ -0,0 +1,28 @@ +#version {{version}} +// Automatically generated from files in pathfinder/shaders/. Do not edit! + + + + + + + + + + + + +precision highp float; +precision highp sampler2D; + +uniform sampler2D uSrc; + +in vec2 vTexCoord; + +out vec4 oFragColor; + +void main(){ + vec4 color = texture(uSrc, vTexCoord); + oFragColor = vec4(color . rgb * color . a, color . a); +} + diff --git a/resources/shaders/gl4/blit.vs.glsl b/resources/shaders/gl4/blit.vs.glsl new file mode 100644 index 00000000..aefef251 --- /dev/null +++ b/resources/shaders/gl4/blit.vs.glsl @@ -0,0 +1,30 @@ +#version {{version}} +// Automatically generated from files in pathfinder/shaders/. Do not edit! + + + + + + + + + + + + +precision highp float; +precision highp sampler2D; + +in ivec2 aPosition; + +out vec2 vTexCoord; + +void main(){ + vec2 texCoord = vec2(aPosition); + + + + vTexCoord = texCoord; + gl_Position = vec4(mix(vec2(- 1.0), vec2(1.0), vec2(aPosition)), 0.0, 1.0); +} + diff --git a/resources/shaders/gl4/debug_solid.fs.glsl b/resources/shaders/gl4/debug_solid.fs.glsl new file mode 100644 index 00000000..056122ed --- /dev/null +++ b/resources/shaders/gl4/debug_solid.fs.glsl @@ -0,0 +1,25 @@ +#version {{version}} +// Automatically generated from files in pathfinder/shaders/. Do not edit! + + + + + + + + + + + + +precision highp float; +precision highp sampler2D; + +uniform vec4 uColor; + +out vec4 oFragColor; + +void main(){ + oFragColor = vec4(uColor . rgb, 1.0)* uColor . a; +} + diff --git a/resources/shaders/gl4/debug_solid.vs.glsl b/resources/shaders/gl4/debug_solid.vs.glsl new file mode 100644 index 00000000..68f4ec92 --- /dev/null +++ b/resources/shaders/gl4/debug_solid.vs.glsl @@ -0,0 +1,26 @@ +#version {{version}} +// Automatically generated from files in pathfinder/shaders/. Do not edit! + + + + + + + + + + + + +precision highp float; +precision highp sampler2D; + +uniform vec2 uFramebufferSize; + +in ivec2 aPosition; + +void main(){ + 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/gl4/debug_texture.fs.glsl b/resources/shaders/gl4/debug_texture.fs.glsl new file mode 100644 index 00000000..4dda9b43 --- /dev/null +++ b/resources/shaders/gl4/debug_texture.fs.glsl @@ -0,0 +1,29 @@ +#version {{version}} +// Automatically generated from files in pathfinder/shaders/. Do not edit! + + + + + + + + + + + + +precision highp float; +precision highp sampler2D; + +uniform sampler2D uTexture; +uniform vec4 uColor; + +in vec2 vTexCoord; + +out vec4 oFragColor; + +void main(){ + float alpha = texture(uTexture, vTexCoord). r * uColor . a; + oFragColor = alpha * vec4(uColor . rgb, 1.0); +} + diff --git a/resources/shaders/gl4/debug_texture.vs.glsl b/resources/shaders/gl4/debug_texture.vs.glsl new file mode 100644 index 00000000..4dc58ff4 --- /dev/null +++ b/resources/shaders/gl4/debug_texture.vs.glsl @@ -0,0 +1,31 @@ +#version {{version}} +// Automatically generated from files in pathfinder/shaders/. Do not edit! + + + + + + + + + + + + +precision highp float; +precision highp sampler2D; + +uniform vec2 uFramebufferSize; +uniform vec2 uTextureSize; + +in ivec2 aPosition; +in ivec2 aTexCoord; + +out vec2 vTexCoord; + +void main(){ + 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/gl4/demo_ground.fs.glsl b/resources/shaders/gl4/demo_ground.fs.glsl new file mode 100644 index 00000000..810a88a0 --- /dev/null +++ b/resources/shaders/gl4/demo_ground.fs.glsl @@ -0,0 +1,29 @@ +#version {{version}} +// Automatically generated from files in pathfinder/shaders/. Do not edit! + + + + + + + + + + + + +precision highp float; +precision highp sampler2D; + +uniform vec4 uGroundColor; +uniform vec4 uGridlineColor; + +in vec2 vTexCoord; + +out vec4 oFragColor; + +void main(){ + vec2 texCoordPx = fract(vTexCoord)/ fwidth(vTexCoord); + oFragColor = any(lessThanEqual(texCoordPx, vec2(1.0)))? uGridlineColor : uGroundColor; +} + diff --git a/resources/shaders/gl4/demo_ground.vs.glsl b/resources/shaders/gl4/demo_ground.vs.glsl new file mode 100644 index 00000000..f329f339 --- /dev/null +++ b/resources/shaders/gl4/demo_ground.vs.glsl @@ -0,0 +1,29 @@ +#version {{version}} +// Automatically generated from files in pathfinder/shaders/. Do not edit! + + + + + + + + + + + + +precision highp float; +precision highp sampler2D; + +uniform mat4 uTransform; +uniform int uGridlineCount; + +in ivec2 aPosition; + +out vec2 vTexCoord; + +void main(){ + vTexCoord = vec2(aPosition * uGridlineCount); + gl_Position = uTransform * vec4(ivec4(aPosition . x, 0, aPosition . y, 1)); +} + diff --git a/resources/shaders/gl4/fill.cs.glsl b/resources/shaders/gl4/fill.cs.glsl new file mode 100644 index 00000000..ae00de7f --- /dev/null +++ b/resources/shaders/gl4/fill.cs.glsl @@ -0,0 +1,97 @@ +#version {{version}} +// Automatically generated from files in pathfinder/shaders/. Do not edit! + + + + + + + + + + + + +#extension GL_GOOGLE_include_directive : enable + +precision highp float; +precision highp sampler2D; + + + + + + + + + + + + +vec4 computeCoverage(vec2 from, vec2 to, sampler2D areaLUT){ + + vec2 left = from . x < to . x ? from : to, right = from . x < to . x ? to : from; + + + vec2 window = clamp(vec2(from . x, to . x), - 0.5, 0.5); + float offset = mix(window . x, window . y, 0.5)- left . x; + float t = offset /(right . x - left . x); + + + float y = mix(left . y, right . y, t); + float d =(right . y - left . y)/(right . x - left . x); + + + float dX = window . x - window . y; + return texture(areaLUT, vec2(y + 8.0, abs(d * dX))/ 16.0)* dX; +} + + +layout(local_size_x = 16, local_size_y = 4)in; + +uniform writeonly image2D uDest; +uniform sampler2D uAreaLUT; +uniform int uFirstTileIndex; + +layout(std430, binding = 0)buffer bFills { + restrict readonly uvec2 iFills[]; +}; + +layout(std430, binding = 1)buffer bNextFills { + restrict readonly int iNextFills[]; +}; + +layout(std430, binding = 2)buffer bFillTileMap { + restrict readonly int iFillTileMap[]; +}; + +void main(){ + ivec2 tileSubCoord = ivec2(gl_LocalInvocationID . xy)* ivec2(1, 4); + uint tileIndexOffset = gl_WorkGroupID . z; + + uint tileIndex = tileIndexOffset + uint(uFirstTileIndex); + + int fillIndex = iFillTileMap[tileIndex]; + if(fillIndex < 0) + return; + + vec4 coverages = vec4(0.0); + do { + uvec2 fill = iFills[fillIndex]; + vec2 from = vec2(fill . y & 0xf,(fill . y >> 4u)& 0xf)+ + vec2(fill . x & 0xff,(fill . x >> 8u)& 0xff)/ 256.0; + vec2 to = vec2((fill . y >> 8u)& 0xf,(fill . y >> 12u)& 0xf)+ + vec2((fill . x >> 16u)& 0xff,(fill . x >> 24u)& 0xff)/ 256.0; + + coverages += computeCoverage(from -(vec2(tileSubCoord)+ vec2(0.5)), + to -(vec2(tileSubCoord)+ vec2(0.5)), + uAreaLUT); + + fillIndex = iNextFills[fillIndex]; + } while(fillIndex >= 0); + + ivec2 tileOrigin = ivec2(tileIndex & 0xff,(tileIndex >> 8u)& 0xff)* ivec2(16, 4); + ivec2 destCoord = tileOrigin + ivec2(gl_LocalInvocationID . xy); + imageStore(uDest, destCoord, coverages); +} + diff --git a/resources/shaders/gl4/fill.fs.glsl b/resources/shaders/gl4/fill.fs.glsl new file mode 100644 index 00000000..7541b242 --- /dev/null +++ b/resources/shaders/gl4/fill.fs.glsl @@ -0,0 +1,60 @@ +#version {{version}} +// Automatically generated from files in pathfinder/shaders/. Do not edit! + + + + + + + + + + + + +#extension GL_GOOGLE_include_directive : enable + +precision highp float; +precision highp sampler2D; + + + + + + + + + + + + +vec4 computeCoverage(vec2 from, vec2 to, sampler2D areaLUT){ + + vec2 left = from . x < to . x ? from : to, right = from . x < to . x ? to : from; + + + vec2 window = clamp(vec2(from . x, to . x), - 0.5, 0.5); + float offset = mix(window . x, window . y, 0.5)- left . x; + float t = offset /(right . x - left . x); + + + float y = mix(left . y, right . y, t); + float d =(right . y - left . y)/(right . x - left . x); + + + float dX = window . x - window . y; + return texture(areaLUT, vec2(y + 8.0, abs(d * dX))/ 16.0)* dX; +} + + +uniform sampler2D uAreaLUT; + +in vec2 vFrom; +in vec2 vTo; + +out vec4 oFragColor; + +void main(){ + oFragColor = computeCoverage(vFrom, vTo, uAreaLUT); +} + diff --git a/resources/shaders/gl4/fill.vs.glsl b/resources/shaders/gl4/fill.vs.glsl new file mode 100644 index 00000000..6f530e42 --- /dev/null +++ b/resources/shaders/gl4/fill.vs.glsl @@ -0,0 +1,68 @@ +#version {{version}} +// Automatically generated from files in pathfinder/shaders/. Do not edit! + + + + + + + + + + + + +precision highp float; +precision highp sampler2D; + +uniform vec2 uFramebufferSize; +uniform vec2 uTileSize; + +in uvec2 aTessCoord; +in uint aFromPx; +in uint aToPx; +in vec2 aFromSubpx; +in vec2 aToSubpx; +in uint aTileIndex; + +out vec2 vFrom; +out vec2 vTo; + +vec2 computeTileOffset(uint tileIndex, float stencilTextureWidth){ + uint tilesPerRow = uint(stencilTextureWidth / uTileSize . x); + uvec2 tileOffset = uvec2(tileIndex % tilesPerRow, tileIndex / tilesPerRow); + return vec2(tileOffset)* uTileSize * vec2(1.0, 0.25); +} + +void main(){ + vec2 tileOrigin = computeTileOffset(aTileIndex, uFramebufferSize . x); + + vec2 from = vec2(aFromPx & 15u, aFromPx >> 4u)+ aFromSubpx; + vec2 to = vec2(aToPx & 15u, aToPx >> 4u)+ aToSubpx; + + vec2 position; + if(aTessCoord . x == 0u) + position . x = floor(min(from . x, to . x)); + else + position . x = ceil(max(from . x, to . x)); + if(aTessCoord . y == 0u) + position . y = floor(min(from . y, to . y)); + else + position . y = uTileSize . y; + position . y = floor(position . y * 0.25); + + + + + + vec2 offset = vec2(0.0, 1.5)- position * vec2(1.0, 4.0); + vFrom = from + offset; + vTo = to + offset; + + vec2 globalPosition =(tileOrigin + position)/ uFramebufferSize * 2.0 - 1.0; + + + + gl_Position = vec4(globalPosition, 0.0, 1.0); +} + diff --git a/resources/shaders/gl4/reproject.fs.glsl b/resources/shaders/gl4/reproject.fs.glsl new file mode 100644 index 00000000..67556c40 --- /dev/null +++ b/resources/shaders/gl4/reproject.fs.glsl @@ -0,0 +1,30 @@ +#version {{version}} +// Automatically generated from files in pathfinder/shaders/. Do not edit! + + + + + + + + + + + + +precision highp float; +precision highp sampler2D; + +uniform mat4 uOldTransform; +uniform sampler2D uTexture; + +in vec2 vTexCoord; + +out vec4 oFragColor; + +void main(){ + vec4 normTexCoord = uOldTransform * vec4(vTexCoord, 0.0, 1.0); + vec2 texCoord =((normTexCoord . xy / normTexCoord . w)+ 1.0)* 0.5; + oFragColor = texture(uTexture, texCoord); +} + diff --git a/resources/shaders/gl4/reproject.vs.glsl b/resources/shaders/gl4/reproject.vs.glsl new file mode 100644 index 00000000..60317f1e --- /dev/null +++ b/resources/shaders/gl4/reproject.vs.glsl @@ -0,0 +1,34 @@ +#version {{version}} +// Automatically generated from files in pathfinder/shaders/. Do not edit! + + + + + + + + + + + + +precision highp float; +precision highp sampler2D; + +uniform mat4 uNewTransform; + +in ivec2 aPosition; + +out vec2 vTexCoord; + +void main(){ + vec2 position = vec2(aPosition); + vTexCoord = position; + + + + + + gl_Position = uNewTransform * vec4(position, 0.0, 1.0); +} + diff --git a/resources/shaders/gl4/stencil.fs.glsl b/resources/shaders/gl4/stencil.fs.glsl new file mode 100644 index 00000000..c18450e2 --- /dev/null +++ b/resources/shaders/gl4/stencil.fs.glsl @@ -0,0 +1,24 @@ +#version {{version}} +// Automatically generated from files in pathfinder/shaders/. Do not edit! + + + + + + + + + + + + +precision highp float; +precision highp sampler2D; + +out vec4 oFragColor; + +void main(){ + + oFragColor = vec4(1.0, 0.0, 0.0, 1.0); +} + diff --git a/resources/shaders/gl4/stencil.vs.glsl b/resources/shaders/gl4/stencil.vs.glsl new file mode 100644 index 00000000..6501b942 --- /dev/null +++ b/resources/shaders/gl4/stencil.vs.glsl @@ -0,0 +1,23 @@ +#version {{version}} +// Automatically generated from files in pathfinder/shaders/. Do not edit! + + + + + + + + + + + + +precision highp float; +precision highp sampler2D; + +in vec3 aPosition; + +void main(){ + gl_Position = vec4(aPosition, 1.0); +} + diff --git a/resources/shaders/gl4/tile.fs.glsl b/resources/shaders/gl4/tile.fs.glsl new file mode 100644 index 00000000..9cd13cf7 --- /dev/null +++ b/resources/shaders/gl4/tile.fs.glsl @@ -0,0 +1,611 @@ +#version {{version}} +// Automatically generated from files in pathfinder/shaders/. Do not edit! + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +#extension GL_GOOGLE_include_directive : enable + +precision highp float; +precision highp sampler2D; + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +uniform sampler2D uColorTexture0; +uniform sampler2D uMaskTexture0; +uniform sampler2D uDestTexture; +uniform sampler2D uGammaLUT; +uniform vec2 uColorTextureSize0; +uniform vec2 uMaskTextureSize0; +uniform vec4 uFilterParams0; +uniform vec4 uFilterParams1; +uniform vec4 uFilterParams2; +uniform vec2 uFramebufferSize; +uniform int uCtrl; + +in vec3 vMaskTexCoord0; +in vec2 vColorTexCoord0; +in vec4 vBaseColor; +in float vTileCtrl; + +out vec4 oFragColor; + + + +vec4 sampleColor(sampler2D colorTexture, vec2 colorTexCoord){ + return texture(colorTexture, colorTexCoord); +} + + + +vec4 combineColor0(vec4 destColor, vec4 srcColor, int op){ + switch(op){ + case 0x1 : + return vec4(srcColor . rgb, srcColor . a * destColor . a); + case 0x2 : + return vec4(destColor . rgb, srcColor . a * destColor . a); + } + return destColor; +} + + + +float filterTextSample1Tap(float offset, sampler2D colorTexture, vec2 colorTexCoord){ + return texture(colorTexture, colorTexCoord + vec2(offset, 0.0)). r; +} + + +void filterTextSample9Tap(out vec4 outAlphaLeft, + out float outAlphaCenter, + out vec4 outAlphaRight, + sampler2D colorTexture, + vec2 colorTexCoord, + vec4 kernel, + float onePixel){ + bool wide = kernel . x > 0.0; + outAlphaLeft = + vec4(wide ? filterTextSample1Tap(- 4.0 * onePixel, colorTexture, colorTexCoord): 0.0, + filterTextSample1Tap(- 3.0 * onePixel, colorTexture, colorTexCoord), + filterTextSample1Tap(- 2.0 * onePixel, colorTexture, colorTexCoord), + filterTextSample1Tap(- 1.0 * onePixel, colorTexture, colorTexCoord)); + outAlphaCenter = filterTextSample1Tap(0.0, colorTexture, colorTexCoord); + outAlphaRight = + vec4(filterTextSample1Tap(1.0 * onePixel, colorTexture, colorTexCoord), + filterTextSample1Tap(2.0 * onePixel, colorTexture, colorTexCoord), + filterTextSample1Tap(3.0 * onePixel, colorTexture, colorTexCoord), + wide ? filterTextSample1Tap(4.0 * onePixel, colorTexture, colorTexCoord): 0.0); +} + +float filterTextConvolve7Tap(vec4 alpha0, vec3 alpha1, vec4 kernel){ + return dot(alpha0, kernel)+ dot(alpha1, kernel . zyx); +} + +float filterTextGammaCorrectChannel(float bgColor, float fgColor, sampler2D gammaLUT){ + return texture(gammaLUT, vec2(fgColor, 1.0 - bgColor)). r; +} + + +vec3 filterTextGammaCorrect(vec3 bgColor, vec3 fgColor, sampler2D gammaLUT){ + return vec3(filterTextGammaCorrectChannel(bgColor . r, fgColor . r, gammaLUT), + filterTextGammaCorrectChannel(bgColor . g, fgColor . g, gammaLUT), + filterTextGammaCorrectChannel(bgColor . b, fgColor . b, gammaLUT)); +} + + + + + + +vec4 filterText(vec2 colorTexCoord, + sampler2D colorTexture, + sampler2D gammaLUT, + vec2 colorTextureSize, + vec4 filterParams0, + vec4 filterParams1, + vec4 filterParams2){ + + vec4 kernel = filterParams0; + vec3 bgColor = filterParams1 . rgb; + vec3 fgColor = filterParams2 . rgb; + bool gammaCorrectionEnabled = filterParams2 . a != 0.0; + + + vec3 alpha; + if(kernel . w == 0.0){ + alpha = texture(colorTexture, colorTexCoord). rrr; + } else { + vec4 alphaLeft, alphaRight; + float alphaCenter; + filterTextSample9Tap(alphaLeft, + alphaCenter, + alphaRight, + colorTexture, + colorTexCoord, + kernel, + 1.0 / colorTextureSize . x); + + float r = filterTextConvolve7Tap(alphaLeft, vec3(alphaCenter, alphaRight . xy), kernel); + float g = filterTextConvolve7Tap(vec4(alphaLeft . yzw, alphaCenter), alphaRight . xyz, kernel); + float b = filterTextConvolve7Tap(vec4(alphaLeft . zw, alphaCenter, alphaRight . x), + alphaRight . yzw, + kernel); + + alpha = vec3(r, g, b); + } + + + if(gammaCorrectionEnabled) + alpha = filterTextGammaCorrect(bgColor, alpha, gammaLUT); + + + return vec4(mix(bgColor, fgColor, alpha), 1.0); +} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +vec4 filterRadialGradient(vec2 colorTexCoord, + sampler2D colorTexture, + vec2 colorTextureSize, + vec2 fragCoord, + vec2 framebufferSize, + vec4 filterParams0, + vec4 filterParams1){ + vec2 lineFrom = filterParams0 . xy, lineVector = filterParams0 . zw; + vec2 radii = filterParams1 . xy, uvOrigin = filterParams1 . zw; + + vec2 dP = colorTexCoord - lineFrom, dC = lineVector; + float dR = radii . y - radii . x; + + float a = dot(dC, dC)- dR * dR; + float b = dot(dP, dC)+ radii . x * dR; + float c = dot(dP, dP)- radii . x * radii . x; + float discrim = b * b - a * c; + + vec4 color = vec4(0.0); + if(abs(discrim)>= 0.00001){ + vec2 ts = vec2(sqrt(discrim)* vec2(1.0, - 1.0)+ vec2(b))/ vec2(a); + if(ts . x > ts . y) + ts = ts . yx; + float t = ts . x >= 0.0 ? ts . x : ts . y; + color = texture(colorTexture, uvOrigin + vec2(clamp(t, 0.0, 1.0), 0.0)); + } + + return color; +} + + + + + + +vec4 filterBlur(vec2 colorTexCoord, + sampler2D colorTexture, + vec2 colorTextureSize, + vec4 filterParams0, + vec4 filterParams1){ + + vec2 srcOffsetScale = filterParams0 . xy / colorTextureSize; + int support = int(filterParams0 . z); + vec3 gaussCoeff = filterParams1 . xyz; + + + float gaussSum = gaussCoeff . x; + vec4 color = texture(colorTexture, colorTexCoord)* gaussCoeff . x; + gaussCoeff . xy *= gaussCoeff . yz; + + + + + + + + + + for(int i = 1;i <= support;i += 2){ + float gaussPartialSum = gaussCoeff . x; + gaussCoeff . xy *= gaussCoeff . yz; + gaussPartialSum += gaussCoeff . x; + + vec2 srcOffset = srcOffsetScale *(float(i)+ gaussCoeff . x / gaussPartialSum); + color +=(texture(colorTexture, colorTexCoord - srcOffset)+ + texture(colorTexture, colorTexCoord + srcOffset))* gaussPartialSum; + + gaussSum += 2.0 * gaussPartialSum; + gaussCoeff . xy *= gaussCoeff . yz; + } + + + return color / gaussSum; +} + +vec4 filterNone(vec2 colorTexCoord, sampler2D colorTexture){ + return sampleColor(colorTexture, colorTexCoord); +} + +vec4 filterColor(vec2 colorTexCoord, + sampler2D colorTexture, + sampler2D gammaLUT, + vec2 colorTextureSize, + vec2 fragCoord, + vec2 framebufferSize, + vec4 filterParams0, + vec4 filterParams1, + vec4 filterParams2, + int colorFilter){ + switch(colorFilter){ + case 0x1 : + return filterRadialGradient(colorTexCoord, + colorTexture, + colorTextureSize, + fragCoord, + framebufferSize, + filterParams0, + filterParams1); + case 0x3 : + return filterBlur(colorTexCoord, + colorTexture, + colorTextureSize, + filterParams0, + filterParams1); + case 0x2 : + return filterText(colorTexCoord, + colorTexture, + gammaLUT, + colorTextureSize, + filterParams0, + filterParams1, + filterParams2); + } + return filterNone(colorTexCoord, colorTexture); +} + + + +vec3 compositeSelect(bvec3 cond, vec3 ifTrue, vec3 ifFalse){ + return vec3(cond . x ? ifTrue . x : ifFalse . x, + cond . y ? ifTrue . y : ifFalse . y, + cond . z ? ifTrue . z : ifFalse . z); +} + +float compositeDivide(float num, float denom){ + return denom != 0.0 ? num / denom : 0.0; +} + +vec3 compositeColorDodge(vec3 destColor, vec3 srcColor){ + bvec3 destZero = equal(destColor, vec3(0.0)), srcOne = equal(srcColor, vec3(1.0)); + return compositeSelect(destZero, + vec3(0.0), + compositeSelect(srcOne, vec3(1.0), destColor /(vec3(1.0)- srcColor))); +} + + +vec3 compositeHSLToRGB(vec3 hsl){ + float a = hsl . y * min(hsl . z, 1.0 - hsl . z); + vec3 ks = mod(vec3(0.0, 8.0, 4.0)+ vec3(hsl . x * 1.9098593171027443), 12.0); + return hsl . zzz - clamp(min(ks - vec3(3.0), vec3(9.0)- ks), - 1.0, 1.0)* a; +} + + +vec3 compositeRGBToHSL(vec3 rgb){ + float v = max(max(rgb . r, rgb . g), rgb . b), xMin = min(min(rgb . r, rgb . g), rgb . b); + float c = v - xMin, l = mix(xMin, v, 0.5); + vec3 terms = rgb . r == v ? vec3(0.0, rgb . gb): + rgb . g == v ? vec3(2.0, rgb . br): + vec3(4.0, rgb . rg); + float h = 1.0471975511965976 * compositeDivide(terms . x * c + terms . y - terms . z, c); + float s = compositeDivide(c, v); + return vec3(h, s, l); +} + +vec3 compositeScreen(vec3 destColor, vec3 srcColor){ + return destColor + srcColor - destColor * srcColor; +} + +vec3 compositeHardLight(vec3 destColor, vec3 srcColor){ + return compositeSelect(lessThanEqual(srcColor, vec3(0.5)), + destColor * vec3(2.0)* srcColor, + compositeScreen(destColor, vec3(2.0)* srcColor - vec3(1.0))); +} + +vec3 compositeSoftLight(vec3 destColor, vec3 srcColor){ + vec3 darkenedDestColor = + compositeSelect(lessThanEqual(destColor, vec3(0.25)), + ((vec3(16.0)* destColor - 12.0)* destColor + 4.0)* destColor, + sqrt(destColor)); + vec3 factor = compositeSelect(lessThanEqual(srcColor, vec3(0.5)), + destColor *(vec3(1.0)- destColor), + darkenedDestColor - destColor); + return destColor +(srcColor * 2.0 - 1.0)* factor; +} + +vec3 compositeHSL(vec3 destColor, vec3 srcColor, int op){ + switch(op){ + case 0xc : + return vec3(srcColor . x, destColor . y, destColor . z); + case 0xd : + return vec3(destColor . x, srcColor . y, destColor . z); + case 0xe : + return vec3(srcColor . x, srcColor . y, destColor . z); + default : + return vec3(destColor . x, destColor . y, srcColor . z); + } +} + +vec3 compositeRGB(vec3 destColor, vec3 srcColor, int op){ + switch(op){ + case 0x1 : + return destColor * srcColor; + case 0x2 : + return compositeScreen(destColor, srcColor); + case 0x3 : + return compositeHardLight(srcColor, destColor); + case 0x4 : + return min(destColor, srcColor); + case 0x5 : + return max(destColor, srcColor); + case 0x6 : + return compositeColorDodge(destColor, srcColor); + case 0x7 : + return vec3(1.0)- compositeColorDodge(vec3(1.0)- destColor, vec3(1.0)- srcColor); + case 0x8 : + return compositeHardLight(destColor, srcColor); + case 0x9 : + return compositeSoftLight(destColor, srcColor); + case 0xa : + return abs(destColor - srcColor); + case 0xb : + return destColor + srcColor - vec3(2.0)* destColor * srcColor; + case 0xc : + case 0xd : + case 0xe : + case 0xf : + return compositeHSLToRGB(compositeHSL(compositeRGBToHSL(destColor), + compositeRGBToHSL(srcColor), + op)); + } + return srcColor; +} + +vec4 composite(vec4 srcColor, + sampler2D destTexture, + vec2 destTextureSize, + vec2 fragCoord, + int op){ + if(op == 0x0) + return srcColor; + + + vec2 destTexCoord = fragCoord / destTextureSize; + vec4 destColor = texture(destTexture, destTexCoord); + vec3 blendedRGB = compositeRGB(destColor . rgb, srcColor . rgb, op); + return vec4(srcColor . a *(1.0 - destColor . a)* srcColor . rgb + + srcColor . a * destColor . a * blendedRGB + + (1.0 - srcColor . a)* destColor . rgb, + 1.0); +} + + + +float sampleMask(float maskAlpha, + sampler2D maskTexture, + vec2 maskTextureSize, + vec3 maskTexCoord, + int maskCtrl){ + if(maskCtrl == 0) + return maskAlpha; + + ivec2 maskTexCoordI = ivec2(floor(maskTexCoord . xy)); + vec4 texel = texture(maskTexture,(vec2(maskTexCoordI / ivec2(1, 4))+ 0.5)/ maskTextureSize); + float coverage = texel[maskTexCoordI . y % 4]+ maskTexCoord . z; + + if((maskCtrl & 0x1)!= 0) + coverage = abs(coverage); + else + coverage = 1.0 - abs(1.0 - mod(coverage, 2.0)); + return min(maskAlpha, coverage); +} + + + +void calculateColor(int tileCtrl, int ctrl){ + + int maskCtrl0 =(tileCtrl >> 0)& 0x3; + float maskAlpha = 1.0; + maskAlpha = sampleMask(maskAlpha, uMaskTexture0, uMaskTextureSize0, vMaskTexCoord0, maskCtrl0); + + + vec4 color = vBaseColor; + int color0Combine =(ctrl >> 6)& + 0x3; + if(color0Combine != 0){ + int color0Filter =(ctrl >> 4)& 0x3; + vec4 color0 = filterColor(vColorTexCoord0, + uColorTexture0, + uGammaLUT, + uColorTextureSize0, + gl_FragCoord . xy, + uFramebufferSize, + uFilterParams0, + uFilterParams1, + uFilterParams2, + color0Filter); + color = combineColor0(color, color0, color0Combine); + } + + + color . a *= maskAlpha; + + + int compositeOp =(ctrl >> 8)& 0xf; + color = composite(color, uDestTexture, uFramebufferSize, gl_FragCoord . xy, compositeOp); + + + color . rgb *= color . a; + oFragColor = color; +} + + + + + +void main(){ + calculateColor(int(vTileCtrl), uCtrl); +} + diff --git a/resources/shaders/gl4/tile.vs.glsl b/resources/shaders/gl4/tile.vs.glsl new file mode 100644 index 00000000..029f364c --- /dev/null +++ b/resources/shaders/gl4/tile.vs.glsl @@ -0,0 +1,56 @@ +#version {{version}} +// Automatically generated from files in pathfinder/shaders/. Do not edit! + + + + + + + + + + + + +precision highp float; +precision highp sampler2D; + +uniform mat4 uTransform; +uniform vec2 uTileSize; +uniform sampler2D uTextureMetadata; +uniform ivec2 uTextureMetadataSize; + +in ivec2 aTileOffset; +in ivec2 aTileOrigin; +in uvec2 aMaskTexCoord0; +in ivec2 aMaskBackdrop; +in int aColor; +in int aTileCtrl; + +out vec3 vMaskTexCoord0; +out vec2 vColorTexCoord0; +out vec4 vBaseColor; +out float vTileCtrl; + +void main(){ + vec2 tileOrigin = vec2(aTileOrigin), tileOffset = vec2(aTileOffset); + vec2 position =(tileOrigin + tileOffset)* uTileSize; + + vec2 maskTexCoord0 =(vec2(aMaskTexCoord0)+ tileOffset)* uTileSize; + + vec2 textureMetadataScale = vec2(1.0)/ vec2(uTextureMetadataSize); + vec2 metadataEntryCoord = vec2(aColor % 128 * 4, aColor / 128); + vec2 colorTexMatrix0Coord =(metadataEntryCoord + vec2(0.5, 0.5))* textureMetadataScale; + vec2 colorTexOffsetsCoord =(metadataEntryCoord + vec2(1.5, 0.5))* textureMetadataScale; + vec2 baseColorCoord =(metadataEntryCoord + vec2(2.5, 0.5))* textureMetadataScale; + vec4 colorTexMatrix0 = texture(uTextureMetadata, colorTexMatrix0Coord); + vec4 colorTexOffsets = texture(uTextureMetadata, colorTexOffsetsCoord); + vec4 baseColor = texture(uTextureMetadata, baseColorCoord); + + vColorTexCoord0 = mat2(colorTexMatrix0)* position + colorTexOffsets . xy; + vMaskTexCoord0 = vec3(maskTexCoord0, float(aMaskBackdrop . x)); + vBaseColor = baseColor; + vTileCtrl = float(aTileCtrl); + gl_Position = uTransform * vec4(position, 0.0, 1.0); +} + diff --git a/resources/shaders/gl4/tile_clip.fs.glsl b/resources/shaders/gl4/tile_clip.fs.glsl new file mode 100644 index 00000000..93ffe55e --- /dev/null +++ b/resources/shaders/gl4/tile_clip.fs.glsl @@ -0,0 +1,28 @@ +#version {{version}} +// Automatically generated from files in pathfinder/shaders/. Do not edit! + + + + + + + + + + + + +precision highp float; +precision highp sampler2D; + +uniform sampler2D uSrc; + +in vec2 vTexCoord; +in float vBackdrop; + +out vec4 oFragColor; + +void main(){ + oFragColor = clamp(abs(texture(uSrc, vTexCoord)+ vBackdrop), 0.0, 1.0); +} + diff --git a/resources/shaders/gl4/tile_clip.vs.glsl b/resources/shaders/gl4/tile_clip.vs.glsl new file mode 100644 index 00000000..5867c3e5 --- /dev/null +++ b/resources/shaders/gl4/tile_clip.vs.glsl @@ -0,0 +1,33 @@ +#version {{version}} +// Automatically generated from files in pathfinder/shaders/. Do not edit! + + + + + + + + + + + + +precision highp float; +precision highp sampler2D; + +in ivec2 aTileOffset; +in ivec2 aDestTileOrigin; +in ivec2 aSrcTileOrigin; +in int aSrcBackdrop; + +out vec2 vTexCoord; +out float vBackdrop; + +void main(){ + vec2 destPosition = vec2(aDestTileOrigin + aTileOffset)/ vec2(256.0); + vec2 srcPosition = vec2(aSrcTileOrigin + aTileOffset)/ vec2(256.0); + vTexCoord = srcPosition; + vBackdrop = float(aSrcBackdrop); + gl_Position = vec4(mix(vec2(- 1.0), vec2(1.0), destPosition), 0.0, 1.0); +} + diff --git a/resources/shaders/gl4/tile_copy.fs.glsl b/resources/shaders/gl4/tile_copy.fs.glsl new file mode 100644 index 00000000..0a43eeb8 --- /dev/null +++ b/resources/shaders/gl4/tile_copy.fs.glsl @@ -0,0 +1,27 @@ +#version {{version}} +// Automatically generated from files in pathfinder/shaders/. Do not edit! + + + + + + + + + + + + +precision highp float; +precision highp sampler2D; + +uniform vec2 uFramebufferSize; +uniform sampler2D uSrc; + +out vec4 oFragColor; + +void main(){ + vec2 texCoord = gl_FragCoord . xy / uFramebufferSize; + oFragColor = texture(uSrc, texCoord); +} + diff --git a/resources/shaders/gl4/tile_copy.vs.glsl b/resources/shaders/gl4/tile_copy.vs.glsl new file mode 100644 index 00000000..b1c24b08 --- /dev/null +++ b/resources/shaders/gl4/tile_copy.vs.glsl @@ -0,0 +1,27 @@ +#version {{version}} +// Automatically generated from files in pathfinder/shaders/. Do not edit! + + + + + + + + + + + + +precision highp float; +precision highp sampler2D; + +uniform mat4 uTransform; +uniform vec2 uTileSize; + +in ivec2 aTilePosition; + +void main(){ + vec2 position = vec2(aTilePosition)* uTileSize; + gl_Position = uTransform * vec4(position, 0.0, 1.0); +} + diff --git a/resources/shaders/metal/tile.fs.metal b/resources/shaders/metal/tile.fs.metal index 1b2c7e9d..f60a0850 100644 --- a/resources/shaders/metal/tile.fs.metal +++ b/resources/shaders/metal/tile.fs.metal @@ -6,8 +6,6 @@ using namespace metal; -constant float3 _1042 = {}; - struct main0_out { float4 oFragColor [[color(0)]]; diff --git a/shaders/Makefile b/shaders/Makefile index 9002a03b..f8f1ba60 100644 --- a/shaders/Makefile +++ b/shaders/Makefile @@ -35,14 +35,16 @@ INCLUDES=\ OUT=\ $(SHADERS:%=$(TARGET_DIR)/gl3/%) \ + $(SHADERS:%=$(TARGET_DIR)/gl4/%) \ $(SHADERS:%.glsl=$(TARGET_DIR)/metal/%.metal) \ $(SHADERS:%.glsl=build/metal/%.spv) \ + $(COMPUTE_SHADERS:%=$(TARGET_DIR)/gl4/%) \ $(COMPUTE_SHADERS:%.glsl=$(TARGET_DIR)/metal/%.metal) \ $(COMPUTE_SHADERS:%.glsl=build/metal/%.spv) \ $(EMPTY) -GLSL_VERSION=330 -GLSL_COMPUTE_VERSION=430 +GLSL_3_VERSION=330 +GLSL_4_VERSION=430 GLSLANGFLAGS=--auto-map-locations -I. GLSLANGFLAGS_METAL=$(GLSLANGFLAGS) -DPF_ORIGIN_UPPER_LEFT=1 @@ -52,7 +54,7 @@ SPIRVCROSSFLAGS=--msl --msl-version 020100 GLSL_VERSION_HEADER="\#version {{version}}" HEADER="// Automatically generated from files in pathfinder/shaders/. Do not edit!" -GLSL_SED_ARGS=-e "s/\#version 330//" -e "s/\#line.*$$//" +GLSL_SED_ARGS=-e "s/\#version .*//" -e "s/\#line.*$$//" all: $(OUT) @@ -67,14 +69,23 @@ build/metal/%.fs.spv: %.fs.glsl $(INCLUDES) $(TARGET_DIR)/gl3/%.fs.glsl: %.fs.glsl $(INCLUDES) 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)/gl4/%.fs.glsl: %.fs.glsl $(INCLUDES) + mkdir -p $(TARGET_DIR)/gl4 && echo $(GLSL_VERSION_HEADER) > $@ && echo $(HEADER) >> $@ && ( glslangValidator $(GLSLANGFLAGS) -S frag -E $< | sed $(GLSL_SED_ARGS) >> $@ ) || ( rm $@ && exit 1 ) + 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 && echo $(GLSL_VERSION_HEADER) > $@ && echo $(HEADER) >> $@ && ( glslangValidator $(GLSLANGFLAGS) -S vert -E $< | sed $(GLSL_SED_ARGS) >> $@ ) || ( rm $@ && exit 1 ) +$(TARGET_DIR)/gl4/%.vs.glsl: %.vs.glsl $(INCLUDES) + mkdir -p $(TARGET_DIR)/gl3 && echo $(GLSL_VERSION_HEADER) > $@ && echo $(HEADER) >> $@ && ( glslangValidator $(GLSLANGFLAGS) -S vert -E $< | sed $(GLSL_SED_ARGS) >> $@ ) || ( rm $@ && exit 1 ) + build/metal/%.cs.spv: %.cs.glsl $(INCLUDES) mkdir -p build/metal && glslangValidator $(GLSLANGFLAGS_METAL) -G$(GLSL_COMPUTE_VERSION) -S comp -o $@ $< +$(TARGET_DIR)/gl4/%.cs.glsl: %.cs.glsl $(INCLUDES) + mkdir -p $(TARGET_DIR)/gl4 && echo $(GLSL_VERSION_HEADER) > $@ && echo $(HEADER) >> $@ && ( glslangValidator $(GLSLANGFLAGS) -S vert -E $< | sed $(GLSL_SED_ARGS) >> $@ ) || ( rm $@ && exit 1 ) + $(TARGET_DIR)/metal/%.metal: build/metal/%.spv - mkdir -p $(TARGET_DIR)/metal && echo $(HEADER) > $@ && ( $(SPIRVCROSS) $(SPIRVCROSSFLAGS) $< | sed $(METAL_SED_ARGS) >> $@ ) || ( rm $@ && exit 1 ) + mkdir -p $(TARGET_DIR)/metal && echo $(HEADER) > $@ && ( $(SPIRVCROSS) $(SPIRVCROSSFLAGS) $< >> $@ ) || ( rm $@ && exit 1 )