[mtl canvas] segment setup pass
This commit is contained in:
parent
f6a992e5f4
commit
c71bc5be98
|
@ -12,7 +12,7 @@
|
||||||
#include<simd/simd.h>
|
#include<simd/simd.h>
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
MG_MTL_LINE,
|
MG_MTL_LINE = 1,
|
||||||
} mg_mtl_seg_kind;
|
} mg_mtl_seg_kind;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
|
|
|
@ -18,17 +18,22 @@
|
||||||
|
|
||||||
#define LOG_SUBSYSTEM "Graphics"
|
#define LOG_SUBSYSTEM "Graphics"
|
||||||
|
|
||||||
|
const int MG_MTL_INPUT_BUFFERS_COUNT = 3;
|
||||||
|
|
||||||
typedef struct mg_mtl_canvas_backend
|
typedef struct mg_mtl_canvas_backend
|
||||||
{
|
{
|
||||||
mg_canvas_backend interface;
|
mg_canvas_backend interface;
|
||||||
mg_surface surface;
|
mg_surface surface;
|
||||||
|
|
||||||
|
id<MTLComputePipelineState> segmentPipeline;
|
||||||
id<MTLComputePipelineState> rasterPipeline;
|
id<MTLComputePipelineState> rasterPipeline;
|
||||||
id<MTLRenderPipelineState> blitPipeline;
|
id<MTLRenderPipelineState> blitPipeline;
|
||||||
|
|
||||||
id<MTLTexture> outTexture;
|
id<MTLTexture> outTexture;
|
||||||
|
|
||||||
id<MTLBuffer> pathBuffer;
|
id<MTLBuffer> pathBuffer;
|
||||||
|
id<MTLBuffer> elementBuffer;
|
||||||
|
id<MTLBuffer> segmentCountBuffer;
|
||||||
id<MTLBuffer> segmentBuffer;
|
id<MTLBuffer> segmentBuffer;
|
||||||
|
|
||||||
} mg_mtl_canvas_backend;
|
} mg_mtl_canvas_backend;
|
||||||
|
@ -51,12 +56,13 @@ void mg_mtl_canvas_render(mg_canvas_backend* interface,
|
||||||
mg_mtl_canvas_backend* backend = (mg_mtl_canvas_backend*)interface;
|
mg_mtl_canvas_backend* backend = (mg_mtl_canvas_backend*)interface;
|
||||||
|
|
||||||
//TODO: update rolling buffers
|
//TODO: update rolling buffers
|
||||||
mg_mtl_segment* segmentBufferData = (mg_mtl_segment*)[backend->segmentBuffer contents];
|
|
||||||
|
mg_mtl_path_elt* elementBufferData = (mg_mtl_path_elt*)[backend->elementBuffer contents];
|
||||||
mg_mtl_path* pathBufferData = (mg_mtl_path*)[backend->pathBuffer contents];
|
mg_mtl_path* pathBufferData = (mg_mtl_path*)[backend->pathBuffer contents];
|
||||||
|
|
||||||
//NOTE: fill renderer input buffers
|
//NOTE: fill renderer input buffers
|
||||||
int segCount = 0;
|
|
||||||
int pathCount = 0;
|
int pathCount = 0;
|
||||||
|
int mtlEltCount = 0;
|
||||||
vec2 currentPos = {0};
|
vec2 currentPos = {0};
|
||||||
|
|
||||||
for(int primitiveIndex = 0; primitiveIndex < primitiveCount; primitiveIndex++)
|
for(int primitiveIndex = 0; primitiveIndex < primitiveCount; primitiveIndex++)
|
||||||
|
@ -82,30 +88,13 @@ void mg_mtl_canvas_render(mg_canvas_backend* interface,
|
||||||
vec2 p3 = mg_mat2x3_mul(primitive->attributes.transform, elt->p[0]);
|
vec2 p3 = mg_mat2x3_mul(primitive->attributes.transform, elt->p[0]);
|
||||||
currentPos = elt->p[0];
|
currentPos = elt->p[0];
|
||||||
|
|
||||||
if(p0.y != p3.y)
|
mg_mtl_path_elt* mtlElt = &elementBufferData[mtlEltCount];
|
||||||
{
|
mtlEltCount++;
|
||||||
mg_mtl_segment* seg = &segmentBufferData[segCount];
|
|
||||||
segCount++;
|
|
||||||
|
|
||||||
seg->pathIndex = primitiveIndex;
|
mtlElt->pathIndex = primitiveIndex;
|
||||||
seg->box = (vector_float4){minimum(p0.x, p3.x),
|
mtlElt->kind = (mg_mtl_seg_kind)elt->type;
|
||||||
minimum(p0.y, p3.y),
|
mtlElt->p[0] = (vector_float2){p0.x, p0.y};
|
||||||
maximum(p0.x, p3.x),
|
mtlElt->p[3] = (vector_float2){p3.x, p3.y};
|
||||||
maximum(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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -140,6 +129,23 @@ void mg_mtl_canvas_render(mg_canvas_backend* interface,
|
||||||
{
|
{
|
||||||
mg_mtl_surface_acquire_command_buffer(surface);
|
mg_mtl_surface_acquire_command_buffer(surface);
|
||||||
|
|
||||||
|
//NOTE: segment setup pass
|
||||||
|
id<MTLComputeCommandEncoder> segmentEncoder = [surface->commandBuffer computeCommandEncoder];
|
||||||
|
segmentEncoder.label = @"segment pass";
|
||||||
|
[segmentEncoder setComputePipelineState: backend->segmentPipeline];
|
||||||
|
|
||||||
|
[segmentEncoder setBytes:&eltCount length:sizeof(int) atIndex:0];
|
||||||
|
[segmentEncoder setBuffer:backend->elementBuffer offset:0 atIndex:1];
|
||||||
|
[segmentEncoder setBuffer:backend->segmentCountBuffer offset:0 atIndex:2];
|
||||||
|
[segmentEncoder setBuffer:backend->segmentBuffer offset:0 atIndex:3];
|
||||||
|
|
||||||
|
MTLSize segmentGridSize = MTLSizeMake(mtlEltCount, 1, 1);
|
||||||
|
MTLSize segmentGroupSize = MTLSizeMake(64, 1, 1);
|
||||||
|
|
||||||
|
[segmentEncoder dispatchThreads: segmentGridSize threadsPerThreadgroup: segmentGroupSize];
|
||||||
|
|
||||||
|
[segmentEncoder endEncoding];
|
||||||
|
|
||||||
//NOTE: raster pass
|
//NOTE: raster pass
|
||||||
id<MTLComputeCommandEncoder> rasterEncoder = [surface->commandBuffer computeCommandEncoder];
|
id<MTLComputeCommandEncoder> rasterEncoder = [surface->commandBuffer computeCommandEncoder];
|
||||||
rasterEncoder.label = @"raster pass";
|
rasterEncoder.label = @"raster pass";
|
||||||
|
@ -147,7 +153,7 @@ void mg_mtl_canvas_render(mg_canvas_backend* interface,
|
||||||
|
|
||||||
[rasterEncoder setBytes:&pathCount length:sizeof(int) atIndex:0];
|
[rasterEncoder setBytes:&pathCount length:sizeof(int) atIndex:0];
|
||||||
[rasterEncoder setBuffer:backend->pathBuffer offset:0 atIndex:1];
|
[rasterEncoder setBuffer:backend->pathBuffer offset:0 atIndex:1];
|
||||||
[rasterEncoder setBytes:&segCount length:sizeof(int) atIndex:2];
|
[rasterEncoder setBuffer:backend->segmentCountBuffer offset:0 atIndex:2];
|
||||||
[rasterEncoder setBuffer:backend->segmentBuffer offset:0 atIndex:3];
|
[rasterEncoder setBuffer:backend->segmentBuffer offset:0 atIndex:3];
|
||||||
|
|
||||||
[rasterEncoder setTexture:backend->outTexture atIndex:0];
|
[rasterEncoder setTexture:backend->outTexture atIndex:0];
|
||||||
|
@ -190,6 +196,8 @@ void mg_mtl_canvas_destroy(mg_canvas_backend* interface)
|
||||||
@autoreleasepool
|
@autoreleasepool
|
||||||
{
|
{
|
||||||
[backend->pathBuffer release];
|
[backend->pathBuffer release];
|
||||||
|
[backend->elementBuffer release];
|
||||||
|
[backend->segmentCountBuffer release];
|
||||||
[backend->segmentBuffer release];
|
[backend->segmentBuffer release];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -197,6 +205,7 @@ void mg_mtl_canvas_destroy(mg_canvas_backend* interface)
|
||||||
}
|
}
|
||||||
|
|
||||||
const u32 MG_MTL_PATH_BUFFER_SIZE = (4<<20)*sizeof(mg_mtl_path),
|
const u32 MG_MTL_PATH_BUFFER_SIZE = (4<<20)*sizeof(mg_mtl_path),
|
||||||
|
MG_MTL_ELEMENT_BUFFER_SIZE = (4<<20)*sizeof(mg_mtl_path_elt),
|
||||||
MG_MTL_SEGMENT_BUFFER_SIZE = (4<<20)*sizeof(mg_mtl_segment);
|
MG_MTL_SEGMENT_BUFFER_SIZE = (4<<20)*sizeof(mg_mtl_segment);
|
||||||
|
|
||||||
mg_canvas_backend* mg_mtl_canvas_create(mg_surface surface)
|
mg_canvas_backend* mg_mtl_canvas_create(mg_surface surface)
|
||||||
|
@ -229,6 +238,7 @@ mg_canvas_backend* mg_mtl_canvas_create(mg_surface surface)
|
||||||
LOG_ERROR("error : %s\n", errStr);
|
LOG_ERROR("error : %s\n", errStr);
|
||||||
return(0);
|
return(0);
|
||||||
}
|
}
|
||||||
|
id<MTLFunction> segmentFunction = [library newFunctionWithName:@"mtl_segment"];
|
||||||
id<MTLFunction> rasterFunction = [library newFunctionWithName:@"mtl_raster"];
|
id<MTLFunction> rasterFunction = [library newFunctionWithName:@"mtl_raster"];
|
||||||
id<MTLFunction> vertexFunction = [library newFunctionWithName:@"mtl_vertex_shader"];
|
id<MTLFunction> vertexFunction = [library newFunctionWithName:@"mtl_vertex_shader"];
|
||||||
id<MTLFunction> fragmentFunction = [library newFunctionWithName:@"mtl_fragment_shader"];
|
id<MTLFunction> fragmentFunction = [library newFunctionWithName:@"mtl_fragment_shader"];
|
||||||
|
@ -238,6 +248,9 @@ mg_canvas_backend* mg_mtl_canvas_create(mg_surface surface)
|
||||||
backend->rasterPipeline = [metalSurface->device newComputePipelineStateWithFunction: rasterFunction
|
backend->rasterPipeline = [metalSurface->device newComputePipelineStateWithFunction: rasterFunction
|
||||||
error:&error];
|
error:&error];
|
||||||
|
|
||||||
|
backend->segmentPipeline = [metalSurface->device newComputePipelineStateWithFunction: segmentFunction
|
||||||
|
error:&error];
|
||||||
|
|
||||||
MTLRenderPipelineDescriptor *pipelineStateDescriptor = [[MTLRenderPipelineDescriptor alloc] init];
|
MTLRenderPipelineDescriptor *pipelineStateDescriptor = [[MTLRenderPipelineDescriptor alloc] init];
|
||||||
pipelineStateDescriptor.label = @"blit pipeline";
|
pipelineStateDescriptor.label = @"blit pipeline";
|
||||||
pipelineStateDescriptor.vertexFunction = vertexFunction;
|
pipelineStateDescriptor.vertexFunction = vertexFunction;
|
||||||
|
@ -274,8 +287,15 @@ mg_canvas_backend* mg_mtl_canvas_create(mg_surface surface)
|
||||||
backend->pathBuffer = [metalSurface->device newBufferWithLength: MG_MTL_PATH_BUFFER_SIZE
|
backend->pathBuffer = [metalSurface->device newBufferWithLength: MG_MTL_PATH_BUFFER_SIZE
|
||||||
options: bufferOptions];
|
options: bufferOptions];
|
||||||
|
|
||||||
|
backend->elementBuffer = [metalSurface->device newBufferWithLength: MG_MTL_ELEMENT_BUFFER_SIZE
|
||||||
|
options: bufferOptions];
|
||||||
|
|
||||||
|
bufferOptions = MTLResourceStorageModePrivate;
|
||||||
backend->segmentBuffer = [metalSurface->device newBufferWithLength: MG_MTL_SEGMENT_BUFFER_SIZE
|
backend->segmentBuffer = [metalSurface->device newBufferWithLength: MG_MTL_SEGMENT_BUFFER_SIZE
|
||||||
options: bufferOptions];
|
options: bufferOptions];
|
||||||
|
|
||||||
|
backend->segmentCountBuffer = [metalSurface->device newBufferWithLength: sizeof(int)
|
||||||
|
options: bufferOptions];
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,42 @@
|
||||||
|
|
||||||
using namespace metal;
|
using namespace metal;
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
kernel void mtl_raster(constant int* pathCount [[buffer(0)]],
|
kernel void mtl_raster(constant int* pathCount [[buffer(0)]],
|
||||||
const device mg_mtl_path* pathBuffer [[buffer(1)]],
|
const device mg_mtl_path* pathBuffer [[buffer(1)]],
|
||||||
constant int* segCount [[buffer(2)]],
|
constant int* segCount [[buffer(2)]],
|
||||||
|
|
Loading…
Reference in New Issue