graphicsdriver/metal: Use template specialization

This commit is contained in:
Hajime Hoshi 2019-02-15 09:42:25 +09:00
parent b7c1d8db3c
commit fc329bd215

View File

@ -103,40 +103,43 @@ template<uint8_t address>
float2 AdjustTexelByAddress(float2 p, float4 tex_region); float2 AdjustTexelByAddress(float2 p, float4 tex_region);
template<> template<>
float2 AdjustTexelByAddress<ADDRESS_CLAMP_TO_ZERO>(float2 p, float4 tex_region) { inline float2 AdjustTexelByAddress<ADDRESS_CLAMP_TO_ZERO>(float2 p, float4 tex_region) {
return p; return p;
} }
template<> template<>
float2 AdjustTexelByAddress<ADDRESS_REPEAT>(float2 p, float4 tex_region) { inline float2 AdjustTexelByAddress<ADDRESS_REPEAT>(float2 p, float4 tex_region) {
float2 o = float2(tex_region[0], tex_region[1]); float2 o = float2(tex_region[0], tex_region[1]);
float2 size = float2(tex_region[2] - tex_region[0], tex_region[3] - tex_region[1]); float2 size = float2(tex_region[2] - tex_region[0], tex_region[3] - tex_region[1]);
return float2(FloorMod((p.x - o.x), size.x) + o.x, FloorMod((p.y - o.y), size.y) + o.y); return float2(FloorMod((p.x - o.x), size.x) + o.x, FloorMod((p.y - o.y), size.y) + o.y);
} }
template<uint8_t filter, uint8_t address> template<uint8_t filter, uint8_t address>
float4 FragmentShaderImpl( struct GetColorFromTexel;
VertexOut v,
texture2d<float> texture,
constant float2& source_size,
constant float4x4& color_matrix_body,
constant float4& color_matrix_translation,
constant float& scale) {
constexpr sampler texture_sampler(filter::nearest);
const float2 texel_size = 1 / source_size;
float4 c; template<uint8_t address>
struct GetColorFromTexel<FILTER_NEAREST, address> {
inline float4 Do(VertexOut v, texture2d<float> texture, constant float2& source_size, float scale) {
constexpr sampler texture_sampler(filter::nearest);
const float2 texel_size = 1 / source_size;
if (filter == FILTER_NEAREST) {
float2 p = AdjustTexelByAddress<address>(v.tex, v.tex_region); float2 p = AdjustTexelByAddress<address>(v.tex, v.tex_region);
c = texture.sample(texture_sampler, p);
if (p.x < v.tex_region[0] || if (p.x < v.tex_region[0] ||
p.y < v.tex_region[1] || p.y < v.tex_region[1] ||
(v.tex_region[2] - texel_size.x / 512.0) <= p.x || (v.tex_region[2] - texel_size.x / 512.0) <= p.x ||
(v.tex_region[3] - texel_size.y / 512.0) <= p.y) { (v.tex_region[3] - texel_size.y / 512.0) <= p.y) {
c = 0; return 0.0;
} }
} else if (filter == FILTER_LINEAR) { return texture.sample(texture_sampler, p);
}
};
template<uint8_t address>
struct GetColorFromTexel<FILTER_LINEAR, address> {
inline float4 Do(VertexOut v, texture2d<float> texture, constant float2& source_size, float scale) {
constexpr sampler texture_sampler(filter::nearest);
const float2 texel_size = 1 / source_size;
float2 p0 = v.tex - texel_size / 2.0; float2 p0 = v.tex - texel_size / 2.0;
float2 p1 = v.tex + texel_size / 2.0; float2 p1 = v.tex + texel_size / 2.0;
p1 = AdjustTexel(source_size, p0, p1); p1 = AdjustTexel(source_size, p0, p1);
@ -166,8 +169,16 @@ float4 FragmentShaderImpl(
} }
float2 rate = fract(p0 * source_size); float2 rate = fract(p0 * source_size);
c = mix(mix(c0, c1, rate.x), mix(c2, c3, rate.x), rate.y); return mix(mix(c0, c1, rate.x), mix(c2, c3, rate.x), rate.y);
} else if (filter == FILTER_SCREEN) { }
};
template<uint8_t address>
struct GetColorFromTexel<FILTER_SCREEN, address> {
inline float4 Do(VertexOut v, texture2d<float> texture, constant float2& source_size, float scale) {
constexpr sampler texture_sampler(filter::nearest);
const float2 texel_size = 1 / source_size;
float2 p0 = v.tex - texel_size / 2.0 / scale; float2 p0 = v.tex - texel_size / 2.0 / scale;
float2 p1 = v.tex + texel_size / 2.0 / scale; float2 p1 = v.tex + texel_size / 2.0 / scale;
p1 = AdjustTexel(source_size, p0, p1); p1 = AdjustTexel(source_size, p0, p1);
@ -179,13 +190,19 @@ float4 FragmentShaderImpl(
float2 rate_center = float2(1.0, 1.0) - texel_size / 2.0 / scale; float2 rate_center = float2(1.0, 1.0) - texel_size / 2.0 / scale;
float2 rate = clamp(((fract(p0 * source_size) - rate_center) * scale) + rate_center, 0.0, 1.0); float2 rate = clamp(((fract(p0 * source_size) - rate_center) * scale) + rate_center, 0.0, 1.0);
c = mix(mix(c0, c1, rate.x), mix(c2, c3, rate.x), rate.y); return mix(mix(c0, c1, rate.x), mix(c2, c3, rate.x), rate.y);
} else {
// Not reached.
discard_fragment();
return float4(0);
} }
};
template<uint8_t filter, uint8_t address>
float4 FragmentShaderImpl(
VertexOut v,
texture2d<float> texture,
constant float2& source_size,
constant float4x4& color_matrix_body,
constant float4& color_matrix_translation,
constant float& scale) {
float4 c = GetColorFromTexel<filter, address>().Do(v, texture, source_size, scale);
if (0 < c.a) { if (0 < c.a) {
c.rgb /= c.a; c.rgb /= c.a;
} }