1 /* 2 * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 #include <simd/simd.h> 27 #include <metal_stdlib> 28 #include "common.h" 29 30 using namespace metal; 31 32 struct VertexInput { 33 float2 position [[attribute(VertexAttributePosition)]]; 34 }; 35 36 struct TxtVertexInput { 37 float2 position [[attribute(VertexAttributePosition)]]; 38 float2 texCoords [[attribute(VertexAttributeTexPos)]]; 39 }; 40 41 struct ColShaderInOut { 42 float4 position [[position]]; 43 half4 color; 44 }; 45 46 struct StencilShaderInOut { 47 float4 position [[position]]; 48 char color; 49 }; 50 51 struct TxtShaderInOut { 52 float4 position [[position]]; 53 float2 texCoords; 54 float2 tpCoords; 55 }; 56 57 struct GradShaderInOut { 58 float4 position [[position]]; 59 float2 texCoords; 60 }; 61 62 vertex ColShaderInOut vert_col(VertexInput in [[stage_in]], 63 constant FrameUniforms& uniforms [[buffer(FrameUniformBuffer)]], 64 constant TransformMatrix& transform [[buffer(MatrixBuffer)]]) { 65 ColShaderInOut out; 66 float4 pos4 = float4(in.position, 0.0, 1.0); 67 out.position = transform.transformMatrix*pos4; 68 out.color = half4(uniforms.color.r, uniforms.color.g, uniforms.color.b, uniforms.color.a); 69 return out; 70 } 71 72 vertex StencilShaderInOut vert_stencil(VertexInput in [[stage_in]], 73 constant FrameUniforms& uniforms [[buffer(FrameUniformBuffer)]], 74 constant TransformMatrix& transform [[buffer(MatrixBuffer)]]) { 75 StencilShaderInOut out; 76 float4 pos4 = float4(in.position, 0.0, 1.0); 77 out.position = transform.transformMatrix * pos4; 78 out.color = 0xFF; 79 return out; 80 } 81 82 vertex GradShaderInOut vert_grad(VertexInput in [[stage_in]], constant TransformMatrix& transform [[buffer(MatrixBuffer)]]) { 83 GradShaderInOut out; 84 float4 pos4 = float4(in.position, 0.0, 1.0); 85 out.position = transform.transformMatrix*pos4; 86 return out; 87 } 88 89 vertex TxtShaderInOut vert_txt(TxtVertexInput in [[stage_in]], constant TransformMatrix& transform [[buffer(MatrixBuffer)]]) { 90 TxtShaderInOut out; 91 float4 pos4 = float4(in.position, 0.0, 1.0); 92 out.position = transform.transformMatrix*pos4; 93 out.texCoords = in.texCoords; 94 return out; 95 } 96 97 vertex TxtShaderInOut vert_txt_tp(TxtVertexInput in [[stage_in]], constant AnchorData& anchorData [[buffer(FrameUniformBuffer)]], constant TransformMatrix& transform [[buffer(MatrixBuffer)]]) 98 { 99 TxtShaderInOut out; 100 float4 pos4 = float4(in.position, 0.0, 1.0); 101 out.position = transform.transformMatrix * pos4; 102 103 // Compute texture coordinates here w.r.t. anchor rect of texture paint 104 out.tpCoords.x = (anchorData.xParams[0] * in.position.x) + 105 (anchorData.xParams[1] * in.position.y) + 106 (anchorData.xParams[2] * out.position.w); 107 out.tpCoords.y = (anchorData.yParams[0] * in.position.x) + 108 (anchorData.yParams[1] * in.position.y) + 109 (anchorData.yParams[2] * out.position.w); 110 out.texCoords = in.texCoords; 111 112 return out; 113 } 114 115 vertex GradShaderInOut vert_txt_grad(TxtVertexInput in [[stage_in]], 116 constant TransformMatrix& transform [[buffer(MatrixBuffer)]]) { 117 GradShaderInOut out; 118 float4 pos4 = float4(in.position, 0.0, 1.0); 119 out.position = transform.transformMatrix*pos4; 120 out.texCoords = in.texCoords; 121 return out; 122 } 123 124 fragment half4 frag_col(ColShaderInOut in [[stage_in]]) { 125 return in.color; 126 } 127 128 fragment unsigned int frag_stencil(StencilShaderInOut in [[stage_in]]) { 129 return in.color; 130 } 131 132 // NOTE: 133 // 1. consider to make shaders without IF-conditions 134 // 2. we can pass interpolation mode via uniforms and select corresponding sampler in shader 135 // but it can cause performance problems (something like getTextureSampler(hint) will be invoked 136 // for every pixel) 137 138 fragment half4 frag_txt( 139 TxtShaderInOut vert [[stage_in]], 140 texture2d<float, access::sample> renderTexture [[texture(0)]], 141 constant TxtFrameUniforms& uniforms [[buffer(1)]], 142 sampler textureSampler [[sampler(0)]] 143 ) { 144 float4 pixelColor = renderTexture.sample(textureSampler, vert.texCoords); 145 float srcA = uniforms.isSrcOpaque ? 1 : pixelColor.a; 146 if (uniforms.mode) { 147 float4 c = mix(pixelColor, uniforms.color, srcA); 148 return half4(c.r, c.g, c.b , c.a); 149 } 150 151 return half4(pixelColor.r, 152 pixelColor.g, 153 pixelColor.b, srcA*uniforms.extraAlpha); 154 } 155 156 fragment half4 frag_txt_tp(TxtShaderInOut vert [[stage_in]], 157 texture2d<float, access::sample> renderTexture [[texture(0)]], 158 texture2d<float, access::sample> paintTexture [[texture(1)]], 159 sampler textureSampler [[sampler(0)]] 160 ) { 161 float4 renderColor = renderTexture.sample(textureSampler, vert.texCoords); 162 float4 paintColor = paintTexture.sample(textureSampler, vert.tpCoords); 163 return half4(paintColor.r*renderColor.a, 164 paintColor.g*renderColor.a, 165 paintColor.b*renderColor.a, 166 renderColor.a); 167 } 168 169 fragment half4 frag_txt_grad(GradShaderInOut in [[stage_in]], 170 constant GradFrameUniforms& uniforms [[buffer(0)]], 171 texture2d<float, access::sample> renderTexture [[texture(0)]]) 172 { 173 constexpr sampler textureSampler (address::repeat, mag_filter::nearest, 174 min_filter::nearest); 175 176 float4 renderColor = renderTexture.sample(textureSampler, in.texCoords); 177 178 float3 v = float3(in.position.x, in.position.y, 1); 179 float a = (dot(v,uniforms.params)-0.25)*2.0; 180 float4 c = mix(uniforms.color1, uniforms.color2, a); 181 return half4(c.r*renderColor.a, 182 c.g*renderColor.a, 183 c.b*renderColor.a, 184 renderColor.a); 185 } 186 187 fragment half4 aa_frag_txt( 188 TxtShaderInOut vert [[stage_in]], 189 texture2d<float, access::sample> renderTexture [[texture(0)]], 190 constant TxtFrameUniforms& uniforms [[buffer(1)]], 191 sampler textureSampler [[sampler(0)]] 192 ) { 193 float4 pixelColor = renderTexture.sample(textureSampler, vert.texCoords); 194 return half4(pixelColor.r, pixelColor.g, pixelColor.b, pixelColor.a); 195 } 196 197 fragment half4 frag_grad(GradShaderInOut in [[stage_in]], 198 constant GradFrameUniforms& uniforms [[buffer(0)]]) { 199 float3 v = float3(in.position.x, in.position.y, 1); 200 float a = (dot(v,uniforms.params)-0.25)*2.0; 201 float4 c = mix(uniforms.color1, uniforms.color2, a); 202 return half4(c); 203 } 204 205 206 vertex TxtShaderInOut vert_tp(VertexInput in [[stage_in]], 207 constant AnchorData& anchorData [[buffer(FrameUniformBuffer)]], 208 constant TransformMatrix& transform [[buffer(MatrixBuffer)]]) 209 { 210 TxtShaderInOut out; 211 float4 pos4 = float4(in.position, 0.0, 1.0); 212 out.position = transform.transformMatrix * pos4; 213 214 // Compute texture coordinates here w.r.t. anchor rect of texture paint 215 out.texCoords.x = (anchorData.xParams[0] * in.position.x) + 216 (anchorData.xParams[1] * in.position.y) + 217 (anchorData.xParams[2] * out.position.w); 218 out.texCoords.y = (anchorData.yParams[0] * in.position.x) + 219 (anchorData.yParams[1] * in.position.y) + 220 (anchorData.yParams[2] * out.position.w); 221 222 return out; 223 } 224 225 fragment half4 frag_tp( 226 TxtShaderInOut vert [[stage_in]], 227 texture2d<float, access::sample> renderTexture [[texture(0)]]) 228 { 229 constexpr sampler textureSampler (address::repeat, 230 mag_filter::nearest, 231 min_filter::nearest); 232 233 float4 pixelColor = renderTexture.sample(textureSampler, vert.texCoords); 234 return half4(pixelColor.r, pixelColor.g, pixelColor.b, 1.0); 235 236 // This implementation defaults alpha to 1.0 as if source is opaque 237 //TODO : implement alpha component value if source is transparent 238 } 239 240 fragment half4 frag_tp_xorMode( 241 TxtShaderInOut vert [[stage_in]], 242 texture2d<float, access::sample> renderTexture [[texture(0)]], 243 constant int& xorColor[[buffer(0)]]) 244 { 245 constexpr sampler textureSampler (address::repeat, 246 mag_filter::nearest, 247 min_filter::nearest); 248 249 float4 pixelColor = renderTexture.sample(textureSampler, vert.texCoords); 250 251 pixelColor.r = float( (unsigned char)(pixelColor.r * 255.0) ^ ((xorColor >> 16) & 0xFF) ) / 255.0f; 252 pixelColor.g = float( (unsigned char)(pixelColor.g * 255.0) ^ ((xorColor >> 8) & 0xFF)) / 255.0f; 253 pixelColor.b = float( (unsigned char)(pixelColor.b * 255.0) ^ (xorColor & 0xFF)) / 255.0f; 254 pixelColor.a = 1.0; 255 256 return half4(pixelColor.r, pixelColor.g, pixelColor.b, 1.0); 257 258 // This implementation defaults alpha to 1.0 as if source is opaque 259 //TODO : implement alpha component value if source is transparent 260 } 261 262 /* The variables involved in the equation can be expressed as follows: 263 * 264 * Cs = Color component of the source (foreground color) [0.0, 1.0] 265 * Cd = Color component of the destination (background color) [0.0, 1.0] 266 * Cr = Color component to be written to the destination [0.0, 1.0] 267 * Ag = Glyph alpha (aka intensity or coverage) [0.0, 1.0] 268 * Ga = Gamma adjustment in the range [1.0, 2.5] 269 * (^ means raised to the power) 270 * 271 * And here is the theoretical equation approximated by this shader: 272 * 273 * Cr = (Ag*(Cs^Ga) + (1-Ag)*(Cd^Ga)) ^ (1/Ga) 274 */ 275 fragment float4 lcd_color( 276 TxtShaderInOut vert [[stage_in]], 277 texture2d<float, access::sample> glyphTexture [[texture(0)]], 278 texture2d<float, access::sample> dstTexture [[texture(1)]], 279 constant LCDFrameUniforms& uniforms [[buffer(1)]]) 280 { 281 float3 src_adj = uniforms.src_adj; 282 float3 gamma = uniforms.gamma; 283 float3 invgamma = uniforms.invgamma; 284 285 constexpr sampler glyphTextureSampler (mag_filter::linear, 286 min_filter::linear); 287 288 // load the RGB value from the glyph image at the current texcoord 289 float3 glyph_clr = float3(glyphTexture.sample(glyphTextureSampler, vert.texCoords)); 290 291 if (glyph_clr.r == 0.0f && glyph_clr.g == 0.0f && glyph_clr.b == 0.0f) { 292 // zero coverage, so skip this fragment 293 discard_fragment(); 294 } 295 constexpr sampler dstTextureSampler (mag_filter::linear, 296 min_filter::linear); 297 // load the RGB value from the corresponding destination pixel 298 float3 dst_clr = float3(dstTexture.sample(dstTextureSampler, vert.texCoords)); 299 300 // gamma adjust the dest color 301 float3 dst_adj = pow(dst_clr.rgb, gamma); 302 303 // linearly interpolate the three color values 304 float3 result = mix(dst_adj, src_adj, glyph_clr); 305 306 // gamma re-adjust the resulting color (alpha is always set to 1.0) 307 return float4(pow(result.rgb, invgamma), 1.0); 308 309 }