2023-03-28 11:09:48 +00:00
|
|
|
|
|
|
|
#include<metal_stdlib>
|
|
|
|
#include<simd/simd.h>
|
|
|
|
#include<metal_simdgroup>
|
|
|
|
|
|
|
|
#include"mtl_renderer.h"
|
|
|
|
|
|
|
|
using namespace metal;
|
|
|
|
|
2023-03-28 13:10:05 +00:00
|
|
|
kernel void mtl_segment(constant int* elementCount [[buffer(0)]],
|
|
|
|
const device mg_mtl_path_elt* elementBuffer [[buffer(1)]],
|
|
|
|
device atomic_int* segmentCount [[buffer(2)]],
|
|
|
|
device mg_mtl_segment* segmentBuffer [[buffer(3)]],
|
|
|
|
uint eltIndex [[thread_position_in_grid]])
|
|
|
|
{
|
|
|
|
const device mg_mtl_path_elt* elt = &elementBuffer[eltIndex];
|
|
|
|
float2 p0 = elt->p[0];
|
|
|
|
float2 p3 = elt->p[3];
|
|
|
|
|
|
|
|
if(elt->kind == MG_MTL_LINE && p0.y != p3.y)
|
|
|
|
{
|
|
|
|
int segIndex = atomic_fetch_add_explicit(segmentCount, 1, memory_order_relaxed);
|
|
|
|
device mg_mtl_segment* seg = &segmentBuffer[segIndex];
|
|
|
|
|
|
|
|
seg->pathIndex = elt->pathIndex;
|
|
|
|
seg->box = (vector_float4){min(p0.x, p3.x),
|
|
|
|
min(p0.y, p3.y),
|
|
|
|
max(p0.x, p3.x),
|
|
|
|
max(p0.y, p3.y)};
|
|
|
|
|
|
|
|
if( (p3.x > p0.x && p3.y < p0.y)
|
|
|
|
||(p3.x <= p0.x && p3.y > p0.y))
|
|
|
|
{
|
|
|
|
seg->config = MG_MTL_TR;
|
|
|
|
}
|
|
|
|
else if( (p3.x > p0.x && p3.y > p0.y)
|
|
|
|
||(p3.x <= p0.x && p3.y < p0.y))
|
|
|
|
{
|
|
|
|
seg->config = MG_MTL_BR;
|
|
|
|
}
|
|
|
|
|
|
|
|
seg->windingIncrement = (p3.y > p0.y)? 1 : -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-03-28 11:09:48 +00:00
|
|
|
kernel void mtl_raster(constant int* pathCount [[buffer(0)]],
|
|
|
|
const device mg_mtl_path* pathBuffer [[buffer(1)]],
|
|
|
|
constant int* segCount [[buffer(2)]],
|
|
|
|
const device mg_mtl_segment* segmentBuffer [[buffer(3)]],
|
|
|
|
texture2d<float, access::write> outTexture [[texture(0)]],
|
|
|
|
uint2 threadCoord [[thread_position_in_grid]])
|
|
|
|
{
|
|
|
|
int2 pixelCoord = int2(threadCoord);
|
|
|
|
|
|
|
|
float4 color = float4(0, 0, 0, 0);
|
|
|
|
int currentPath = 0;
|
|
|
|
int winding = 0;
|
|
|
|
|
|
|
|
for(int segIndex = 0; segIndex < segCount[0]; segIndex++)
|
|
|
|
{
|
|
|
|
const device mg_mtl_segment* seg = &segmentBuffer[segIndex];
|
|
|
|
|
|
|
|
if(seg->pathIndex != currentPath)
|
|
|
|
{
|
|
|
|
//depending on winding number, update color
|
|
|
|
if(winding & 1)
|
|
|
|
{
|
|
|
|
float4 pathColor = pathBuffer[currentPath].color;
|
|
|
|
pathColor.rgb *= pathColor.a;
|
|
|
|
color = color*(1-pathColor.a) + pathColor;
|
|
|
|
}
|
|
|
|
currentPath = seg->pathIndex;
|
|
|
|
winding = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(pixelCoord.y >= seg->box.y && pixelCoord.y < seg->box.w)
|
|
|
|
{
|
|
|
|
if(pixelCoord.x < seg->box.x)
|
|
|
|
{
|
|
|
|
winding += seg->windingIncrement;
|
|
|
|
}
|
|
|
|
else if(pixelCoord.x < seg->box.z)
|
|
|
|
{
|
|
|
|
/*TODO: if pixel is on opposite size of diagonal as curve on the right, increment
|
|
|
|
otherwise if not on same size of diagonal as curve, do implicit test
|
|
|
|
*/
|
|
|
|
float alpha = (seg->box.w - seg->box.y)/(seg->box.z - seg->box.x);
|
|
|
|
float ofs = seg->box.w - seg->box.y;
|
|
|
|
float dx = pixelCoord.x - seg->box.x;
|
|
|
|
float dy = pixelCoord.y - seg->box.y;
|
|
|
|
|
|
|
|
if( (seg->config == MG_MTL_BR && dy > alpha*dx)
|
|
|
|
||(seg->config == MG_MTL_TR && dy < ofs - alpha*dx))
|
|
|
|
{
|
|
|
|
winding += seg->windingIncrement;
|
|
|
|
}
|
|
|
|
else if( !(seg->config == MG_MTL_TL && dy < alpha*dx)
|
|
|
|
&& !(seg->config == MG_MTL_BL && dy > ofs - alpha*dx))
|
|
|
|
{
|
|
|
|
//Need implicit test, but for lines, we only have config BR or TR, so the test is always negative for now
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if(winding & 1)
|
|
|
|
{
|
|
|
|
float4 pathColor = pathBuffer[currentPath].color;
|
|
|
|
pathColor.rgb *= pathColor.a;
|
|
|
|
color = color*(1-pathColor.a) + pathColor;
|
|
|
|
}
|
|
|
|
|
|
|
|
outTexture.write(color, uint2(pixelCoord));
|
|
|
|
}
|
|
|
|
|
|
|
|
//------------------------------------------------------------------------------------
|
|
|
|
// Blit shader
|
|
|
|
//------------------------------------------------------------------------------------
|
|
|
|
struct vs_out
|
|
|
|
{
|
|
|
|
float4 pos [[position]];
|
|
|
|
float2 uv;
|
|
|
|
};
|
|
|
|
|
|
|
|
vertex vs_out mtl_vertex_shader(ushort vid [[vertex_id]])
|
|
|
|
{
|
|
|
|
vs_out out;
|
|
|
|
out.uv = float2((vid << 1) & 2, vid & 2);
|
|
|
|
out.pos = float4(out.uv * float2(2, -2) + float2(-1, 1), 0, 1);
|
|
|
|
return(out);
|
|
|
|
}
|
|
|
|
|
|
|
|
fragment float4 mtl_fragment_shader(vs_out i [[stage_in]], texture2d<float> tex [[texture(0)]])
|
|
|
|
{
|
|
|
|
constexpr sampler smp(mip_filter::nearest, mag_filter::linear, min_filter::linear);
|
|
|
|
return(tex.sample(smp, i.uv));
|
|
|
|
}
|