[mtl renderer] fixed clipping
This commit is contained in:
		
							parent
							
								
									b7f5b84123
								
							
						
					
					
						commit
						f35e91a38c
					
				|  | @ -160,6 +160,11 @@ int main() | |||
| 			mg_set_color_rgba(0, 1, 1, 1); | ||||
| 			mg_clear(); | ||||
| 
 | ||||
| 			mg_set_color_rgba(1, 0, 0, 1); | ||||
| 			mg_set_width(2); | ||||
| 			mg_rectangle_stroke(304, 100, 300, 250); | ||||
| 
 | ||||
| 			mg_clip_push(304, 100, 300, 250); | ||||
| 			// head
 | ||||
| 			mg_set_color_rgba(1, 1, 0, 1); | ||||
| 
 | ||||
|  | @ -178,6 +183,8 @@ int main() | |||
| 			mg_ellipse_fill(x-70, y-50, 30, 50); | ||||
| 			mg_ellipse_fill(x+70, y-50, 30, 50); | ||||
| 
 | ||||
| 			mg_clip_pop(); | ||||
| 
 | ||||
| 			// text
 | ||||
| 			mg_set_color_rgba(0, 0, 1, 1); | ||||
| 			mg_set_font(font); | ||||
|  |  | |||
							
								
								
									
										148
									
								
								src/graphics.c
								
								
								
								
							
							
						
						
									
										148
									
								
								src/graphics.c
								
								
								
								
							|  | @ -638,6 +638,43 @@ void mg_matrix_stack_pop(mg_canvas_data* canvas) | |||
| 	} | ||||
| } | ||||
| 
 | ||||
| mp_rect mg_clip_stack_top(mg_canvas_data* canvas) | ||||
| { | ||||
| 	if(canvas->clipStackSize == 0) | ||||
| 	{ | ||||
| 		return((mp_rect){-FLT_MAX/2, -FLT_MAX/2, FLT_MAX, FLT_MAX}); | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		return(canvas->clipStack[canvas->clipStackSize-1]); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| void mg_clip_stack_push(mg_canvas_data* canvas, mp_rect clip) | ||||
| { | ||||
| 	if(canvas->clipStackSize >= MG_CLIP_STACK_MAX_DEPTH) | ||||
| 	{ | ||||
| 		LOG_ERROR("clip stack overflow\n"); | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		canvas->clipStack[canvas->clipStackSize] = clip; | ||||
| 		canvas->clipStackSize++; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| void mg_clip_stack_pop(mg_canvas_data* canvas) | ||||
| { | ||||
| 	if(canvas->clipStackSize == 0) | ||||
| 	{ | ||||
| 		LOG_ERROR("clip stack underflow\n"); | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		canvas->clipStackSize--; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| void mg_push_command(mg_canvas_data* canvas, mg_primitive primitive) | ||||
| { | ||||
| 	//NOTE(martin): push primitive and updates current stream, eventually patching a pending jump.
 | ||||
|  | @ -646,6 +683,7 @@ void mg_push_command(mg_canvas_data* canvas, mg_primitive primitive) | |||
| 	canvas->primitives[canvas->primitiveCount] = primitive; | ||||
| 	canvas->primitives[canvas->primitiveCount].attributes = canvas->attributes; | ||||
| 	canvas->primitives[canvas->primitiveCount].attributes.transform = mg_matrix_stack_top(canvas); | ||||
| 	canvas->primitives[canvas->primitiveCount].attributes.clip = mg_clip_stack_top(canvas); | ||||
| 	canvas->primitiveCount++; | ||||
| } | ||||
| 
 | ||||
|  | @ -725,6 +763,7 @@ u32 mg_next_shape(mg_canvas_data* canvas, mg_attributes* attributes) | |||
| { | ||||
| 	mg_finalize_shape(canvas); | ||||
| 
 | ||||
| 	canvas->clip = attributes->clip; | ||||
| 	canvas->transform = attributes->transform; | ||||
| 	canvas->srcRegion = attributes->srcRegion; | ||||
| 	canvas->shapeExtents = (vec4){FLT_MAX, FLT_MAX, -FLT_MAX, -FLT_MAX}; | ||||
|  | @ -2698,71 +2737,6 @@ vec2 mg_canvas_size(void) | |||
| } | ||||
| ////////////////////////////////////////////////////////////
 | ||||
| 
 | ||||
| 
 | ||||
| mp_rect mg_clip_stack_top(mg_canvas_data* canvas) | ||||
| { | ||||
| 	if(canvas->clipStackSize == 0) | ||||
| 	{ | ||||
| 		return((mp_rect){-FLT_MAX/2, -FLT_MAX/2, FLT_MAX, FLT_MAX}); | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		return(canvas->clipStack[canvas->clipStackSize-1]); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| void mg_clip_stack_push(mg_canvas_data* canvas, mp_rect clip) | ||||
| { | ||||
| 	if(canvas->clipStackSize >= MG_CLIP_STACK_MAX_DEPTH) | ||||
| 	{ | ||||
| 		LOG_ERROR("clip stack overflow\n"); | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		canvas->clipStack[canvas->clipStackSize] = clip; | ||||
| 		canvas->clipStackSize++; | ||||
| 		canvas->clip = clip; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| void mg_clip_stack_pop(mg_canvas_data* canvas) | ||||
| { | ||||
| 	if(canvas->clipStackSize == 0) | ||||
| 	{ | ||||
| 		LOG_ERROR("clip stack underflow\n"); | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		canvas->clipStackSize--; | ||||
| 		canvas->clip = mg_clip_stack_top(canvas); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| void mg_do_clip_push(mg_canvas_data* canvas, mp_rect clip) | ||||
| { | ||||
| 	//NOTE(martin): transform clip
 | ||||
| 	vec2 p0 = mg_mat2x3_mul(canvas->transform, (vec2){clip.x, clip.y}); | ||||
| 	vec2 p1 = mg_mat2x3_mul(canvas->transform, (vec2){clip.x + clip.w, clip.y}); | ||||
| 	vec2 p2 = mg_mat2x3_mul(canvas->transform, (vec2){clip.x + clip.w, clip.y + clip.h}); | ||||
| 	vec2 p3 = mg_mat2x3_mul(canvas->transform, (vec2){clip.x, clip.y + clip.h}); | ||||
| 
 | ||||
| 	f32 x0 = minimum(p0.x, minimum(p1.x, minimum(p2.x, p3.x))); | ||||
| 	f32 y0 = minimum(p0.y, minimum(p1.y, minimum(p2.y, p3.y))); | ||||
| 	f32 x1 = maximum(p0.x, maximum(p1.x, maximum(p2.x, p3.x))); | ||||
| 	f32 y1 = maximum(p0.y, maximum(p1.y, maximum(p2.y, p3.y))); | ||||
| 
 | ||||
| 	mp_rect current = mg_clip_stack_top(canvas); | ||||
| 
 | ||||
| 	//NOTE(martin): intersect with current clip
 | ||||
| 	x0 = maximum(current.x, x0); | ||||
| 	y0 = maximum(current.y, y0); | ||||
| 	x1 = minimum(current.x + current.w, x1); | ||||
| 	y1 = minimum(current.y + current.h, y1); | ||||
| 
 | ||||
| 	mp_rect r = {x0, y0, maximum(0, x1-x0), maximum(0, y1-y0)}; | ||||
| 	mg_clip_stack_push(canvas, r); | ||||
| } | ||||
| 
 | ||||
| void mg_draw_batch(mg_canvas_data* canvas, mg_image_data* image) | ||||
| { | ||||
| 	mg_finalize_shape(canvas); | ||||
|  | @ -2857,19 +2831,6 @@ void mg_flush_commands(int primitiveCount, mg_primitive* primitives, mg_path_elt | |||
| 					nextIndex = primitive->jump; | ||||
| 				} | ||||
| 			} break; | ||||
| 
 | ||||
| 			case MG_CMD_CLIP_PUSH: | ||||
| 			{ | ||||
| 				//TODO(martin): use only aligned rect and avoid this
 | ||||
| 				mp_rect r = {primitive->rect.x, primitive->rect.y, primitive->rect.w, primitive->rect.h}; | ||||
| 				mg_do_clip_push(canvas, r); | ||||
| 			} break; | ||||
| 
 | ||||
| 			case MG_CMD_CLIP_POP: | ||||
| 			{ | ||||
| 				mg_clip_stack_pop(canvas); | ||||
| 			} break; | ||||
| 
 | ||||
| 		} | ||||
| 	} | ||||
| 	exit_command_loop: ; | ||||
|  | @ -2941,8 +2902,32 @@ void mg_clip_push(f32 x, f32 y, f32 w, f32 h) | |||
| 	mg_canvas_data* canvas = __mgCurrentCanvas; | ||||
| 	if(canvas) | ||||
| 	{ | ||||
| 		mg_push_command(canvas, (mg_primitive){.cmd = MG_CMD_CLIP_PUSH, | ||||
| 	                                        .rect = (mp_rect){x, y, w, h}}); | ||||
| 		mp_rect clip = {x, y, w, h}; | ||||
| 
 | ||||
| 		//NOTE(martin): transform clip
 | ||||
| 		mg_mat2x3 transform = mg_matrix_stack_top(canvas); | ||||
| 		vec2 p0 = mg_mat2x3_mul(transform, (vec2){clip.x, clip.y}); | ||||
| 		vec2 p1 = mg_mat2x3_mul(transform, (vec2){clip.x + clip.w, clip.y}); | ||||
| 		vec2 p2 = mg_mat2x3_mul(transform, (vec2){clip.x + clip.w, clip.y + clip.h}); | ||||
| 		vec2 p3 = mg_mat2x3_mul(transform, (vec2){clip.x, clip.y + clip.h}); | ||||
| 
 | ||||
| 		f32 x0 = minimum(p0.x, minimum(p1.x, minimum(p2.x, p3.x))); | ||||
| 		f32 y0 = minimum(p0.y, minimum(p1.y, minimum(p2.y, p3.y))); | ||||
| 		f32 x1 = maximum(p0.x, maximum(p1.x, maximum(p2.x, p3.x))); | ||||
| 		f32 y1 = maximum(p0.y, maximum(p1.y, maximum(p2.y, p3.y))); | ||||
| 
 | ||||
| 		mp_rect current = mg_clip_stack_top(canvas); | ||||
| 
 | ||||
| 		//NOTE(martin): intersect with current clip
 | ||||
| 		x0 = maximum(current.x, x0); | ||||
| 		y0 = maximum(current.y, y0); | ||||
| 		x1 = minimum(current.x + current.w, x1); | ||||
| 		y1 = minimum(current.y + current.h, y1); | ||||
| 
 | ||||
| 		mp_rect r = {x0, y0, maximum(0, x1-x0), maximum(0, y1-y0)}; | ||||
| 		mg_clip_stack_push(canvas, r); | ||||
| 
 | ||||
| 		canvas->attributes.clip = r; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
|  | @ -2951,7 +2936,8 @@ void mg_clip_pop() | |||
| 	mg_canvas_data* canvas = __mgCurrentCanvas; | ||||
| 	if(canvas) | ||||
| 	{ | ||||
| 		mg_push_command(canvas, (mg_primitive){.cmd = MG_CMD_CLIP_POP}); | ||||
| 		mg_clip_stack_pop(canvas); | ||||
| 		canvas->attributes.clip = mg_clip_stack_top(canvas); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -178,9 +178,7 @@ typedef struct mg_rounded_rect | |||
| 
 | ||||
| typedef enum { MG_CMD_FILL, | ||||
| 	           MG_CMD_STROKE, | ||||
| 	           MG_CMD_JUMP, | ||||
| 	           MG_CMD_CLIP_PUSH, | ||||
| 	           MG_CMD_CLIP_POP, | ||||
| 	           MG_CMD_JUMP | ||||
| 	     } mg_primitive_cmd; | ||||
| 
 | ||||
| typedef struct mg_primitive | ||||
|  |  | |||
|  | @ -22,6 +22,7 @@ typedef struct mg_mtl_path | |||
| 	matrix_float3x3 uvTransform; | ||||
| 	vector_float4 color; | ||||
| 	vector_float4 box; | ||||
| 	vector_float4 clip; | ||||
| } mg_mtl_path; | ||||
| 
 | ||||
| typedef enum { | ||||
|  |  | |||
|  | @ -708,8 +708,10 @@ void mg_mtl_render_batch(mg_mtl_canvas_backend* backend, | |||
| 		[mergeEncoder setBuffer:backend->tileOpBuffer offset:0 atIndex:4]; | ||||
| 		[mergeEncoder setBuffer:backend->tileOpCountBuffer offset:0 atIndex:5]; | ||||
| 		[mergeEncoder setBuffer:backend->screenTilesBuffer offset:0 atIndex:6]; | ||||
| 		[mergeEncoder setBuffer:backend->logBuffer[backend->bufferIndex] offset:0 atIndex:7]; | ||||
| 		[mergeEncoder setBuffer:backend->logOffsetBuffer[backend->bufferIndex] offset:0 atIndex:8]; | ||||
| 		[mergeEncoder setBytes:&tileSize length:sizeof(int) atIndex:7]; | ||||
| 		[mergeEncoder setBytes:&scale length:sizeof(float) atIndex:8]; | ||||
| 		[mergeEncoder setBuffer:backend->logBuffer[backend->bufferIndex] offset:0 atIndex:9]; | ||||
| 		[mergeEncoder setBuffer:backend->logOffsetBuffer[backend->bufferIndex] offset:0 atIndex:10]; | ||||
| 
 | ||||
| 		MTLSize mergeGridSize = MTLSizeMake(nTilesX, nTilesY, 1); | ||||
| 		MTLSize mergeGroupSize = MTLSizeMake(16, 16, 1); | ||||
|  | @ -727,9 +729,10 @@ void mg_mtl_render_batch(mg_mtl_canvas_backend* backend, | |||
| 		[rasterEncoder setBuffer:backend->pathBuffer[backend->bufferIndex] offset:backend->pathBufferOffset atIndex:2]; | ||||
| 		[rasterEncoder setBuffer:backend->segmentBuffer offset:0 atIndex:3]; | ||||
| 		[rasterEncoder setBytes:&tileSize length:sizeof(int) atIndex:4]; | ||||
| 		[rasterEncoder setBytes:&backend->msaaCount length:sizeof(int) atIndex:5]; | ||||
| 		[rasterEncoder setBuffer:backend->logBuffer[backend->bufferIndex] offset:0 atIndex:6]; | ||||
| 		[rasterEncoder setBuffer:backend->logOffsetBuffer[backend->bufferIndex] offset:0 atIndex:7]; | ||||
| 		[rasterEncoder setBytes:&scale length:sizeof(float) atIndex:5]; | ||||
| 		[rasterEncoder setBytes:&backend->msaaCount length:sizeof(int) atIndex:6]; | ||||
| 		[rasterEncoder setBuffer:backend->logBuffer[backend->bufferIndex] offset:0 atIndex:7]; | ||||
| 		[rasterEncoder setBuffer:backend->logOffsetBuffer[backend->bufferIndex] offset:0 atIndex:8]; | ||||
| 
 | ||||
| 		[rasterEncoder setTexture:backend->outTexture atIndex:0]; | ||||
| 
 | ||||
|  | @ -740,8 +743,7 @@ void mg_mtl_render_batch(mg_mtl_canvas_backend* backend, | |||
| 			[rasterEncoder setTexture: mtlImage->texture atIndex: 1]; | ||||
| 			useTexture = 1; | ||||
| 		} | ||||
| 		[rasterEncoder setBytes: &useTexture length:sizeof(int) atIndex: 8]; | ||||
| 
 | ||||
| 		[rasterEncoder setBytes: &useTexture length:sizeof(int) atIndex: 9]; | ||||
| 
 | ||||
| 		MTLSize rasterGridSize = MTLSizeMake(viewportSize.x, viewportSize.y, 1); | ||||
| 		MTLSize rasterGroupSize = MTLSizeMake(16, 16, 1); | ||||
|  | @ -959,10 +961,16 @@ void mg_mtl_canvas_render(mg_canvas_backend* interface, | |||
| 			pathCount++; | ||||
| 
 | ||||
| 			path->cmd =	(mg_mtl_cmd)primitive->cmd; | ||||
| 			path->box = (vector_float4){maximum(primitive->attributes.clip.x, context.pathScreenExtents.x), | ||||
| 		                                maximum(primitive->attributes.clip.y, context.pathScreenExtents.y), | ||||
| 		                                minimum(primitive->attributes.clip.x + primitive->attributes.clip.w, context.pathScreenExtents.z), | ||||
| 		                                minimum(primitive->attributes.clip.y + primitive->attributes.clip.h, context.pathScreenExtents.w)}; | ||||
| 
 | ||||
| 			path->box = (vector_float4){context.pathScreenExtents.x, | ||||
| 		                                context.pathScreenExtents.y, | ||||
| 		                                context.pathScreenExtents.z, | ||||
| 		                                context.pathScreenExtents.w}; | ||||
| 
 | ||||
| 			path->clip = (vector_float4){primitive->attributes.clip.x, | ||||
| 			                             primitive->attributes.clip.y, | ||||
| 			                             primitive->attributes.clip.x + primitive->attributes.clip.w, | ||||
| 			                             primitive->attributes.clip.y + primitive->attributes.clip.h}; | ||||
| 
 | ||||
| 			path->color = (vector_float4){primitive->attributes.color.r, | ||||
| 			                              primitive->attributes.color.g, | ||||
|  |  | |||
|  | @ -237,10 +237,19 @@ kernel void mtl_path_setup(constant int* pathCount [[buffer(0)]], | |||
| { | ||||
| 	const device mg_mtl_path* path = &pathBuffer[pathIndex]; | ||||
| 
 | ||||
| 	int2 firstTile = int2(path->box.xy*scale[0])/tileSize[0]; | ||||
| 	int2 lastTile = max(firstTile, int2(path->box.zw*scale[0])/tileSize[0]); | ||||
| 	int nTilesX = lastTile.x - firstTile.x + 1; | ||||
| 	int nTilesY = lastTile.y - firstTile.y + 1; | ||||
| 
 | ||||
| 	//NOTE: we don't clip on the right, since we need those tiles to accurately compute
 | ||||
| 	//      the prefix sum of winding increments in the backprop pass.
 | ||||
| 	float4 clippedBox = {max(path->box.x, path->clip.x), | ||||
| 	                     max(path->box.y, path->clip.y), | ||||
| 	                     path->box.z, | ||||
| 	                     min(path->box.w, path->clip.w)}; | ||||
| 
 | ||||
| 	int2 firstTile = int2(clippedBox.xy*scale[0])/tileSize[0]; | ||||
| 	int2 lastTile = int2(clippedBox.zw*scale[0])/tileSize[0]; | ||||
| 
 | ||||
| 	int nTilesX = max(0, lastTile.x - firstTile.x + 1); | ||||
| 	int nTilesY = max(0, lastTile.y - firstTile.y + 1); | ||||
| 	int tileCount = nTilesX * nTilesY; | ||||
| 
 | ||||
| 	int tileQueuesIndex = atomic_fetch_add_explicit(tileQueueCount, tileCount, memory_order_relaxed); | ||||
|  | @ -1360,8 +1369,10 @@ kernel void mtl_merge(constant int* pathCount [[buffer(0)]], | |||
|                       device mg_mtl_tile_op* tileOpBuffer [[buffer(4)]], | ||||
|                       device atomic_int* tileOpCount [[buffer(5)]], | ||||
|                       device int* screenTilesBuffer [[buffer(6)]], | ||||
|                       device char* logBuffer [[buffer(7)]], | ||||
|                       device atomic_int* logOffsetBuffer [[buffer(8)]], | ||||
|                       constant int* tileSize [[buffer(7)]], | ||||
|                       constant float* scale [[buffer(8)]], | ||||
|                       device char* logBuffer [[buffer(9)]], | ||||
|                       device atomic_int* logOffsetBuffer [[buffer(10)]], | ||||
|                       uint2 threadCoord [[thread_position_in_grid]], | ||||
|                       uint2 gridSize [[threads_per_grid]]) | ||||
| { | ||||
|  | @ -1380,8 +1391,13 @@ kernel void mtl_merge(constant int* pathCount [[buffer(0)]], | |||
| 		const device mg_mtl_path_queue* pathQueue = &pathQueueBuffer[pathIndex]; | ||||
| 		int2 pathTileCoord = tileCoord - pathQueue->area.xy; | ||||
| 
 | ||||
| 		const device mg_mtl_path* path = &pathBuffer[pathIndex]; | ||||
| 		float xMax = min(path->box.z, path->clip.z); | ||||
| 		int tileMax = xMax * scale[0] / tileSize[0]; | ||||
| 		int pathTileMax = tileMax - pathQueue->area.x; | ||||
| 
 | ||||
| 		if(  pathTileCoord.x >= 0 | ||||
| 		  && pathTileCoord.x < pathQueue->area.z | ||||
| 		  && pathTileCoord.x <= pathTileMax | ||||
| 		  && pathTileCoord.y >= 0 | ||||
| 		  && pathTileCoord.y < pathQueue->area.w) | ||||
| 		{ | ||||
|  | @ -1396,7 +1412,7 @@ kernel void mtl_merge(constant int* pathCount [[buffer(0)]], | |||
| 				if(windingOffset & 1) | ||||
| 				{ | ||||
| 					//NOTE: tile is full covered. Add path start op (with winding offset).
 | ||||
| 					//      Additionally if color is opaque, trim tile list.
 | ||||
| 					//      Additionally if color is opaque and tile is fully inside clip, trim tile list.
 | ||||
| 					int pathOpIndex = atomic_fetch_add_explicit(tileOpCount, 1, memory_order_relaxed); | ||||
| 					device mg_mtl_tile_op* pathOp = &tileOpBuffer[pathOpIndex]; | ||||
| 					pathOp->kind = MG_MTL_OP_START; | ||||
|  | @ -1404,7 +1420,15 @@ kernel void mtl_merge(constant int* pathCount [[buffer(0)]], | |||
| 					pathOp->index = pathIndex; | ||||
| 					pathOp->windingOffset = windingOffset; | ||||
| 
 | ||||
| 					if(pathBuffer[pathIndex].color.a == 1) | ||||
| 					float4 clip = pathBuffer[pathIndex].clip * scale[0]; | ||||
| 					float4 tileBox = float4(tileCoord.x, tileCoord.y, tileCoord.x+1, tileCoord.y+1); | ||||
| 					tileBox *= tileSize[0]; | ||||
| 
 | ||||
| 					if(pathBuffer[pathIndex].color.a == 1 | ||||
| 					  && tileBox.x >= clip.x | ||||
| 					  && tileBox.z < clip.z | ||||
| 					  && tileBox.y >= clip.y | ||||
| 					  && tileBox.w < clip.w) | ||||
| 					{ | ||||
| 						screenTilesBuffer[tileIndex] = pathOpIndex; | ||||
| 					} | ||||
|  | @ -1444,10 +1468,11 @@ kernel void mtl_raster(const device int* screenTilesBuffer [[buffer(0)]], | |||
|                        const device mg_mtl_path* pathBuffer [[buffer(2)]], | ||||
|                        const device mg_mtl_segment* segmentBuffer [[buffer(3)]], | ||||
|                        constant int* tileSize [[buffer(4)]], | ||||
|                        constant int* sampleCountBuffer [[buffer(5)]], | ||||
|                        device char* logBuffer [[buffer(6)]], | ||||
|                        device atomic_int* logOffsetBuffer [[buffer(7)]], | ||||
|                        constant int* useTexture [[buffer(8)]], | ||||
|                        constant float* scale [[buffer(5)]], | ||||
|                        constant int* sampleCountBuffer [[buffer(6)]], | ||||
|                        device char* logBuffer [[buffer(7)]], | ||||
|                        device atomic_int* logOffsetBuffer [[buffer(8)]], | ||||
|                        constant int* useTexture [[buffer(9)]], | ||||
|                        texture2d<float, access::write> outTexture [[texture(0)]], | ||||
|                        texture2d<float> srcTexture [[texture(1)]], | ||||
|                        uint2 threadCoord [[thread_position_in_grid]], | ||||
|  | @ -1503,23 +1528,32 @@ kernel void mtl_raster(const device int* screenTilesBuffer [[buffer(0)]], | |||
| 
 | ||||
| 			for(int sampleIndex=0; sampleIndex<sampleCount; sampleIndex++) | ||||
| 			{ | ||||
| 				bool filled = (pathBuffer[pathIndex].cmd == MG_MTL_FILL && (winding[sampleIndex] & 1)) | ||||
| 			             	||(pathBuffer[pathIndex].cmd == MG_MTL_STROKE && (winding[sampleIndex] != 0)); | ||||
| 				if(filled) | ||||
| 				float2 sampleCoord = sampleCoords[sampleIndex]; | ||||
| 				float4 clip = pathBuffer[pathIndex].clip * scale[0]; | ||||
| 
 | ||||
| 				if(  sampleCoord.x >= clip.x | ||||
| 				  && sampleCoord.x < clip.z | ||||
| 				  && sampleCoord.y >= clip.y | ||||
| 				  && sampleCoord.y < clip.w) | ||||
| 				{ | ||||
| 					float4 nextColor = pathColor; | ||||
| 					if(useTexture[0]) | ||||
| 					bool filled = (pathBuffer[pathIndex].cmd == MG_MTL_FILL && (winding[sampleIndex] & 1)) | ||||
| 					            ||(pathBuffer[pathIndex].cmd == MG_MTL_STROKE && (winding[sampleIndex] != 0)); | ||||
| 					if(filled) | ||||
| 					{ | ||||
| 						float3 sampleCoord = float3(sampleCoords[sampleIndex].xy, 1); | ||||
| 						float2 uv = (pathBuffer[pathIndex].uvTransform * sampleCoord).xy; | ||||
| 						float4 nextColor = pathColor; | ||||
| 						if(useTexture[0]) | ||||
| 						{ | ||||
| 							float3 ph = float3(sampleCoords[sampleIndex].xy, 1); | ||||
| 							float2 uv = (pathBuffer[pathIndex].uvTransform * ph).xy; | ||||
| 
 | ||||
| 						constexpr sampler smp(mip_filter::nearest, mag_filter::linear, min_filter::linear); | ||||
| 						float4 texColor = srcTexture.sample(smp, uv); | ||||
| 						texColor.rgb *= texColor.a; | ||||
| 							constexpr sampler smp(mip_filter::nearest, mag_filter::linear, min_filter::linear); | ||||
| 							float4 texColor = srcTexture.sample(smp, uv); | ||||
| 							texColor.rgb *= texColor.a; | ||||
| 
 | ||||
| 						nextColor *= texColor; | ||||
| 							nextColor *= texColor; | ||||
| 						} | ||||
| 						color[sampleIndex] = color[sampleIndex]*(1-nextColor.a) + nextColor; | ||||
| 					} | ||||
| 					color[sampleIndex] = color[sampleIndex]*(1-nextColor.a) + nextColor; | ||||
| 				} | ||||
| 				winding[sampleIndex] = op->windingOffset; | ||||
| 			} | ||||
|  | @ -1533,6 +1567,7 @@ kernel void mtl_raster(const device int* screenTilesBuffer [[buffer(0)]], | |||
| 			{ | ||||
| 				float2 sampleCoord = sampleCoords[sampleIndex]; | ||||
| 
 | ||||
| 				//TODO: shouldn't this be redundant with mtl_side_of_segment()?
 | ||||
| 				if( (sampleCoord.y > seg->box.y) | ||||
| 				  &&(sampleCoord.y <= seg->box.w) | ||||
| 				  &&(mtl_side_of_segment(sampleCoord, seg) < 0)) | ||||
|  | @ -1564,23 +1599,32 @@ kernel void mtl_raster(const device int* screenTilesBuffer [[buffer(0)]], | |||
| 
 | ||||
| 	for(int sampleIndex=0; sampleIndex<sampleCount; sampleIndex++) | ||||
| 	{ | ||||
| 		bool filled = (pathBuffer[pathIndex].cmd == MG_MTL_FILL && (winding[sampleIndex] & 1)) | ||||
| 	            	||(pathBuffer[pathIndex].cmd == MG_MTL_STROKE && (winding[sampleIndex] != 0)); | ||||
| 		if(filled) | ||||
| 		float2 sampleCoord = sampleCoords[sampleIndex]; | ||||
| 		float4 clip = pathBuffer[pathIndex].clip * scale[0]; | ||||
| 
 | ||||
| 		if(  sampleCoord.x >= clip.x | ||||
| 		  && sampleCoord.x < clip.z | ||||
| 		  && sampleCoord.y >= clip.y | ||||
| 		  && sampleCoord.y < clip.w) | ||||
| 		{ | ||||
| 			float4 nextColor = pathColor; | ||||
| 			if(useTexture[0]) | ||||
| 			bool filled = (pathBuffer[pathIndex].cmd == MG_MTL_FILL && (winding[sampleIndex] & 1)) | ||||
| 			            ||(pathBuffer[pathIndex].cmd == MG_MTL_STROKE && (winding[sampleIndex] != 0)); | ||||
| 			if(filled) | ||||
| 			{ | ||||
| 				float3 sampleCoord = float3(sampleCoords[sampleIndex].xy, 1); | ||||
| 				float2 uv = (pathBuffer[pathIndex].uvTransform * sampleCoord).xy; | ||||
| 				float4 nextColor = pathColor; | ||||
| 				if(useTexture[0]) | ||||
| 				{ | ||||
| 					float3 sampleCoord = float3(sampleCoords[sampleIndex].xy, 1); | ||||
| 					float2 uv = (pathBuffer[pathIndex].uvTransform * sampleCoord).xy; | ||||
| 
 | ||||
| 				constexpr sampler smp(mip_filter::nearest, mag_filter::linear, min_filter::linear); | ||||
| 				float4 texColor = srcTexture.sample(smp, uv); | ||||
| 				texColor.rgb *= texColor.a; | ||||
| 					constexpr sampler smp(mip_filter::nearest, mag_filter::linear, min_filter::linear); | ||||
| 					float4 texColor = srcTexture.sample(smp, uv); | ||||
| 					texColor.rgb *= texColor.a; | ||||
| 
 | ||||
| 				nextColor *= texColor; | ||||
| 					nextColor *= texColor; | ||||
| 				} | ||||
| 				color[sampleIndex] = color[sampleIndex]*(1-nextColor.a) + nextColor; | ||||
| 			} | ||||
| 			color[sampleIndex] = color[sampleIndex]*(1-nextColor.a) + nextColor; | ||||
| 		} | ||||
| 		pixelColor += color[sampleIndex]; | ||||
| 	} | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue