{
	limits = {
		//FIXME this really needs to be an external variable as the C code
		//needs to agree on the size, so it might as well set maxSamplers
		//directly (and any other such variable)
		maxSamplers = "min (256u, $physDevLimits.maxPerStageDescriptorSamplers)";
	};
	samplers = {
		quakepic = {
			magFilter = nearest;
			minFilter = nearest;
			mipmapMode = nearest;
			addressModeU = clamp_to_edge;
			addressModeV = clamp_to_edge;
			addressModeW = clamp_to_edge;
			mipLodBias = 0;
			anisotropyEnable = false;
			maxAnisotropy = 0;
			compareEnable = false;
			compareOp = always;
			minLod = 0;
			maxLod = 0;
			borderColor = float_transparent_black;
			unnormalizedCoordinates = false;
		};
		quakebsp_sampler = {
			magFilter = linear;
			minFilter = linear;
			mipmapMode = linear;
			addressModeU = repeat;
			addressModeV = repeat;
			addressModeW = repeat;
			mipLodBias = 0;
			anisotropyEnable = false;
			maxAnisotropy = 0;
			compareEnable = false;
			compareOp = always;
			minLod = 0;
			maxLod = 4;
			borderColor = float_transparent_black;
			unnormalizedCoordinates = false;
		};
		alias_sampler = {
			magFilter = linear;
			minFilter = linear;
			mipmapMode = linear;
			addressModeU = clamp_to_edge;
			addressModeV = clamp_to_edge;
			addressModeW = clamp_to_edge;
			mipLodBias = 0;
			anisotropyEnable = false;
			maxAnisotropy = 0;
			compareEnable = false;
			compareOp = always;
			minLod = 0;
			maxLod = 1000;
			borderColor = float_transparent_black;
			unnormalizedCoordinates = false;
		};
		sprite_sampler = $properties.samplers.alias_sampler;
		shadow_sampler = {
			magFilter = linear;
			minFilter = linear;
			mipmapMode = linear;
			addressModeU = clamp_to_edge;
			addressModeV = clamp_to_edge;
			addressModeW = clamp_to_edge;
			mipLodBias = 0;
			anisotropyEnable = false;
			maxAnisotropy = 0;
			compareEnable = true;
			compareOp = greater_or_equal;
			minLod = 0;
			maxLod = 1000;
			borderColor = float_transparent_black;
			unnormalizedCoordinates = false;
		};
	};
	descriptorPools = {
		matrix_pool = {
			flags = 0;
			maxSets = $frames.size;
			bindings = (
				{
					type = uniform_buffer;
					descriptorCount = $frames.size;
				},
			);
		};
		twod_pool = {
			flags = 0;
			maxSets = $frames.size;
			bindings = (
				{
					type = combined_image_sampler;
					descriptorCount = $frames.size;
				},
			);
		};
		texture_pool = {
			flags = free_descriptor_set;
			maxSets = 512;
			bindings = (
				{
					type = combined_image_sampler;
					descriptorCount = $properties.descriptorPools.texture_pool.maxSets;
				},
			);
		};
		particle_pool = {
			flags = 0;
			maxSets = $frames.size;
			bindings = (
				{
					type = storage_buffer;
					descriptorCount = 3;
				},
			);
		};
		sprite_pool = {
			flags = free_descriptor_set;
			maxSets = 64;	//FIXME cvar?
			bindings = (
				{
					type = uniform_buffer;
					descriptorCount = $properties.descriptorPools.sprite_pool.maxSets;
				},
				{
					type = combined_image_sampler;
					descriptorCount = $properties.descriptorPools.sprite_pool.maxSets;
				},
			);
		};
		//FIXME probably should just share a larger pool
		alias_pool = $properties.descriptorPools.texture_pool;
		quakebsp_pool = $properties.descriptorPools.texture_pool;
		lighting_attach_pool = {
			flags = 0;
			maxSets = $frames.size;
			bindings = (
				{
					type = input_attachment;
					descriptorCount = "5z * $frames.size";
				},
			);
		};
		lighting_lights_pool = {
			flags = 0;
			maxSets = $frames.size;
			bindings = (
				{
					type = uniform_buffer;
					descriptorCount = $frames.size;
				},
			);
		};
		lighting_shadow_pool = {
			flags = 0;
			maxSets = $frames.size;
			bindings = (
				{
					type = combined_image_sampler;
					descriptorCount = "$frames.size * size_t($properties.limits.maxSamplers)";
				},
			);
		};
		compose_attach_pool = {
			flags = 0;
			maxSets = $frames.size;
			bindings = (
				{
					type = input_attachment;
					descriptorCount = "2z * $frames.size";
				},
			);
		};
	};
	setLayouts = {
		matrix_set = {
			bindings = (
				{
					binding = 0;
					descriptorType = uniform_buffer;
					descriptorCount = 1;
					stageFlags = vertex|geometry;
				},
			);
		};
		twod_set = {
			bindings = (
				{
					binding = 0;
					descriptorType = combined_image_sampler;
					descriptorCount = 1;
					stageFlags = fragment;
				},
			);
		};
		texture_set = {
			bindings = (
				{
					binding = 0;
					descriptorType = combined_image_sampler;
					descriptorCount = 1;
					stageFlags = fragment;
				},
			);
		};
		quakebsp_set = $properties.setLayouts.texture_set;
		alias_set = $properties.setLayouts.texture_set;
		sprite_set = {
			bindings = (
				{
					binding = 0;
					descriptorType = uniform_buffer;
					descriptorCount = 1;
					stageFlags = vertex;
				},
				{
					binding = 1;
					descriptorType = combined_image_sampler;
					descriptorCount = 1;
					stageFlags = fragment;
				},
			);
		};
		lighting_attach = {
			bindings = (
				{
					binding = 0;
					descriptorType = input_attachment;
					descriptorCount = 1;
					stageFlags = fragment;
				},
				{
					binding = 1;
					descriptorType = input_attachment;
					descriptorCount = 1;
					stageFlags = fragment;
				},
				{
					binding = 2;
					descriptorType = input_attachment;
					descriptorCount = 1;
					stageFlags = fragment;
				},
				{
					binding = 3;
					descriptorType = input_attachment;
					descriptorCount = 1;
					stageFlags = fragment;
				},
				{
					binding = 4;
					descriptorType = input_attachment;
					descriptorCount = 1;
					stageFlags = fragment;
				},
			);
		};
		lighting_lights = {
			bindings = (
				{
					binding = 0;
					descriptorType = uniform_buffer;
					descriptorCount = 1;
					stageFlags = fragment;
				},
			);
		};
		lighting_shadow = {
			bindings = (
				{
					binding = 0;
					descriptorType = combined_image_sampler;
					descriptorCount = $properties.limits.maxSamplers;
					stageFlags = fragment;
				},
			);
		};
		compose_attach = {
			bindings = (
				{
					binding = 0;
					descriptorType = input_attachment;
					descriptorCount = 1;
					stageFlags = fragment;
				},
				{
					binding = 1;
					descriptorType = input_attachment;
					descriptorCount = 1;
					stageFlags = fragment;
				},
			);
		};
		particle_set = {
			bindings = (
				{
					binding = 0;
					descriptorType = storage_buffer;
					descriptorCount = 1;
					stageFlags = compute;
				},
				{
					binding = 1;
					descriptorType = storage_buffer;
					descriptorCount = 1;
					stageFlags = compute;
				},
				{
					binding = 2;
					descriptorType = storage_buffer;
					descriptorCount = 1;
					stageFlags = compute;
				},
			);
		};
	};
	pipelineLayouts = {
		twod_layout = {
			setLayouts = (matrix_set, twod_set);
		};
		quakebsp_layout = {
			setLayouts = (matrix_set, texture_set, texture_set);
			pushConstantRanges = (
				{
					stageFlags = vertex;
					offset = 0;
					size = "16 * 4";
				},
				{
					stageFlags = fragment;
					offset = 64;
					size = "4 * 4 + 4";
				},
			);
		};
		alias_layout = {
			setLayouts = (matrix_set, alias_set);
			pushConstantRanges = (
				{
					stageFlags = vertex;
					offset = 0;
					size = "16 * 4 + 4";
				},
				{
					stageFlags = fragment;
					offset = 68;
					size = "3 * 4 + 2 * 4 * 4 + 4";
				},
			);
		};
		sprite_layout = {
			setLayouts = (matrix_set, sprite_set);
			pushConstantRanges = (
				{
					stageFlags = vertex;
					offset = 0;
					size = "16 * 4 + 4";
				},
				{
					stageFlags = fragment;
					offset = 64;
					size = "2 * 4 + 2 * 4 + 4 * 4";
				},
			);
		};
		lighting_layout = {
			setLayouts = (lighting_attach, lighting_lights, lighting_shadow);
		};
		compose_layout = {
			setLayouts = (compose_attach);
		};
		partphysics_layout = {
			setLayouts = (particle_set);
			pushConstantRanges = (
				{
					stageFlags = compute;
					offset = 0;
					size = "16 * 4 + 4";
				},
			);
		};
		partupdate_layout = {
			setLayouts = (particle_set, particle_set, particle_set);
		};
		partdraw_layout = {
			setLayouts = (matrix_set);
			pushConstantRanges = (
				{
					stageFlags = vertex;
					offset = 0;
					size = "16 * 4";
				},
			);
		};
	};

	depthStencil = {
		test_and_write = {
			depthTestEnable = true;
			depthWriteEnable = true;
			depthCompareOp = less_or_equal;
			depthBoundsTestEnable = false;
			stencilTestEnable = false;
		};
		test_only = {
			depthTestEnable = true;
			depthWriteEnable = false;
			depthCompareOp = less_or_equal;
			depthBoundsTestEnable = false;
			stencilTestEnable = false;
		};
		disable = {
			depthTestEnable = false;
			depthWriteEnable = false;
			depthCompareOp = less_or_equal;
			depthBoundsTestEnable = false;
			stencilTestEnable = false;
		};
	};

	inputAssembly = {
		alias = {
			topology = triangle_list;
			primitiveRestartEnable = false;
		};
		brush = {
			topology = triangle_fan;
			primitiveRestartEnable = true;
		};
		twod = {
			topology = triangle_strip;
			primitiveRestartEnable = true;
		};
		sprite = {
			topology = triangle_strip;
			primitiveRestartEnable = true;
		};
	};

	vertexInput = {
		index_only = {
			bindings = ();
			attributes = ();
		};
		alias = {
			bindings = (
				{ binding = 0; stride = "2 * 4 * 4"; inputRate = vertex; },
				{ binding = 1; stride = "2 * 4 * 4"; inputRate = vertex; },
				{ binding = 2; stride = "2 * 4";     inputRate = vertex; },
			);
			attributes = (
				{ location = 0; binding = 0; format = r32g32b32a32_sfloat; offset = 0;  },
				{ location = 1; binding = 0; format = r32g32b32a32_sfloat; offset = 16; },
				{ location = 2; binding = 1; format = r32g32b32a32_sfloat; offset = 0;  },
				{ location = 3; binding = 1; format = r32g32b32a32_sfloat; offset = 16; },
				{ location = 4; binding = 2; format = r32g32_sfloat;       offset = 0;  },
			);
		};
		brush = {
			bindings = (
				{ binding = 0; stride = "2 * 4 * 4"; inputRate = vertex; },
			);
			attributes = (
				{ location = 0; binding = 0; format = r32g32b32a32_sfloat; offset = 0;  },
				{ location = 1; binding = 0; format = r32g32b32a32_sfloat; offset = 16; },
			);
		};
		particle = {
			bindings = (
				{ binding = 0; stride = "4 * 4 * 4"; inputRate = vertex; },
			);
			attributes = (
				{ location = 0; binding = 0; format = r32g32b32a32_sfloat; offset = 0;  },
				{ location = 1; binding = 0; format = r32g32b32a32_sfloat; offset = 16; },
				{ location = 2; binding = 0; format = r32g32b32a32_sfloat; offset = 16; },
				{ location = 3; binding = 0; format = r32g32b32a32_sfloat; offset = 16; },
			);
		};
		twod = {
			bindings = (
				{ binding = 0; stride = "2 * 4 * 4"; inputRate = vertex; },
			);
			attributes = (
				{ location = 0; binding = 0; format = r32g32_sfloat;       offset = 0;  },
				{ location = 1; binding = 0; format = r32g32_sfloat;       offset = 8;  },
				{ location = 2; binding = 0; format = r32g32b32a32_sfloat; offset = 16; },
			);
		};
	};

	rasterization = {
		cw_cull_back = {
			depthClampEnable = false;
			rasterizerDiscardEnable = false;
			polygonMode = fill;
			cullMode = back;
			frontFace = clockwise;
			depthBiasEnable = false;
			lineWidth = 1;
		};
		counter_cw_cull_back = {
			depthClampEnable = false;
			rasterizerDiscardEnable = false;
			polygonMode = fill;
			cullMode = back;
			frontFace = counter_clockwise;
			depthBiasEnable = false;
			lineWidth = 1;
		};
	};

	multisample = {
		rasterizationSamples = $msaaSamples;
		sampleShadingEnable = false;
		minSampleShading = 0.5f;
		alphaToCoverageEnable = false;
		alphaToOneEnable = false;
	};

	viewport = {
		viewports = (
			{
				x = 0; y = 0;
				width = 640; height = 480;
				minDepth = 0; maxDepth = 1;
			}
		);
		scissors = (
			{
				offset = { x = 0; y = 0 };
				extent = { width = 640; height = 480; };
			},
		);
	};

	attachmentBlendOp = {
		disabled = {
			blendEnable = false;
			srcColorBlendFactor = src_alpha;
			dstColorBlendFactor = one_minus_src_alpha;
			colorBlendOp = add;
			srcAlphaBlendFactor = src_alpha;
			dstAlphaBlendFactor = one_minus_src_alpha;
			alphaBlendOp = add;
			colorWriteMask = r|g|b|a;
		};
		alpha_blend = {
			blendEnable = true;
			srcColorBlendFactor = src_alpha;
			dstColorBlendFactor = one_minus_src_alpha;
			colorBlendOp = add;
			srcAlphaBlendFactor = src_alpha;
			dstAlphaBlendFactor = one_minus_src_alpha;
			alphaBlendOp = add;
			colorWriteMask = r|g|b|a;
		};
	};

	fsquad = {
		vertexInput = {
			bindings = (
				{ binding = 0; stride = "4 * 4"; inputRate = vertex; },
			);
			attributes = (
				{ location = 0; binding = 0; format = r32g32b32a32_sfloat; offset = 0; },
			);
		};
		inputAssembly = {
			topology = triangle_strip;
			primitiveRestartEnable = false;
		};
		colorBlend = {
			logicOpEnable = false;
			attachments = ($properties.attachmentBlendOp.disabled);
		};
	};

	pipelines = {
		alias_shadow = {
			subpass = 0;
			stages = (
				{
					stage = vertex;
					name = main;
					module = $builtin/alias_shadow.vert;
				},
			);
			vertexInput = {
				bindings = (
					"$properties.vertexInput.alias.bindings[0]",
					"$properties.vertexInput.alias.bindings[1]",
				);
				attributes = (
					"$properties.vertexInput.alias.attributes[0]",
					"$properties.vertexInput.alias.attributes[1]",
					"$properties.vertexInput.alias.attributes[2]",
					"$properties.vertexInput.alias.attributes[3]",
				);
			};
			inputAssembly = $properties.inputAssembly.alias;
			viewport      = $properties.viewport;
			rasterization = $properties.rasterization.cw_cull_back;
			multisample   = $properties.multisample;
			depthStencil  = $properties.depthStencil.test_and_write;
			colorBlend    = $properties.pipelines.alias_gbuf.colorBlend;
			dynamic = {
				dynamicState = ( viewport, scissor );
			};
			layout = alias_layout;
		};
		bsp_shadow = {
			subpass = 0;
			stages = (
				{
					stage = vertex;
					name = main;
					module = $builtin/bsp_shadow.vert;
				},
			);
			vertexInput = {
				bindings = (
					"$properties.vertexInput.brush.bindings[0]",
				);
				attributes = (
					"$properties.vertexInput.brush.attributes[0]",
				);
			};
			inputAssembly = $properties.inputAssembly.brush;
			viewport      = $properties.viewport;
			rasterization = $properties.rasterization.cw_cull_back;
			multisample   = $properties.multisample;
			depthStencil  = $properties.depthStencil.test_and_write;
			colorBlend    = $properties.pipelines.bsp_gbuf.colorBlend;
			dynamic = {
				dynamicState = ( viewport, scissor );
			};
			layout = quakebsp_layout;
			renderPass = renderpass;
		};
		alias_depth = {
			subpass = 0;
			stages = (
				{
					stage = vertex;
					name = main;
					module = $builtin/alias_depth.vert;
				},
			);
			vertexInput = {
				// depth pass doesn't use UVs
				bindings = (
					"$properties.vertexInput.alias.bindings[0]",
					"$properties.vertexInput.alias.bindings[1]",
				);
				attributes = (
					"$properties.vertexInput.alias.attributes[0]",
					"$properties.vertexInput.alias.attributes[1]",
					"$properties.vertexInput.alias.attributes[2]",
					"$properties.vertexInput.alias.attributes[3]",
				);
			};
			inputAssembly = $properties.inputAssembly.alias;
			viewport      = $properties.viewport;
			rasterization = $properties.rasterization.cw_cull_back;
			multisample   = $properties.multisample;
			depthStencil  = $properties.depthStencil.test_and_write;
			colorBlend    = $properties.pipelines.alias_gbuf.colorBlend;
			dynamic = {
				dynamicState = ( viewport, scissor );
			};
			layout = alias_layout;
			renderPass = renderpass;
		};
		alias_gbuf = {
			subpass = 2;
			stages = (
				{
					stage = vertex;
					name = main;
					module = $builtin/alias.vert;
				},
				{
					stage = fragment;
					name = main;
					module = $builtin/alias_gbuf.frag;
				},
			);
			vertexInput   = $properties.vertexInput.alias;
			inputAssembly = $properties.inputAssembly.alias;
			viewport      = $properties.viewport;
			rasterization = $properties.rasterization.cw_cull_back;
			multisample   = $properties.multisample;
			depthStencil  = $properties.depthStencil.test_only;
			colorBlend = {
				logicOpEnable = false;
				attachments = (
					$properties.attachmentBlendOp.disabled,
					$properties.attachmentBlendOp.disabled,
					$properties.attachmentBlendOp.disabled,
					$properties.attachmentBlendOp.disabled,
				);
			};
			dynamic = {
				dynamicState = ( viewport, scissor, blend_constants );
			};
			layout = alias_layout;
			renderPass = renderpass;
		};
		bsp_depth = {
			subpass = 0;
			stages = (
				{
					stage = vertex;
					name = main;
					module = $builtin/bsp_depth.vert;
				},
			);
			vertexInput = {
				bindings = (
					"$properties.vertexInput.brush.bindings[0]",
				);
				attributes = (
					"$properties.vertexInput.brush.attributes[0]",
				);
			};
			inputAssembly = $properties.inputAssembly.brush;
			viewport      = $properties.viewport;
			rasterization = $properties.rasterization.cw_cull_back;
			multisample   = $properties.multisample;
			depthStencil  = $properties.depthStencil.test_and_write;
			colorBlend    = $properties.pipelines.bsp_gbuf.colorBlend;
			dynamic = {
				dynamicState = ( viewport, scissor );
			};
			layout = quakebsp_layout;
			renderPass = renderpass;
		};
		bsp_gbuf = {
			subpass = 2;
			stages = (
				{
					stage = vertex;
					name = main;
					module = $builtin/bsp_gbuf.vert;
				},
				{
					stage = geometry;
					name = main;
					module = $builtin/bsp_gbuf.geom;
				},
				{
					stage = fragment;
					name = main;
					module = $builtin/bsp_gbuf.frag;
				},
			);
			vertexInput   = $properties.vertexInput.brush;
			inputAssembly = $properties.inputAssembly.brush;
			viewport      = $properties.viewport;
			rasterization = $properties.rasterization.cw_cull_back;
			multisample   = $properties.multisample;
			depthStencil   = $properties.depthStencil.test_only;
			colorBlend = {
				logicOpEnable = false;
				attachments = (
					$properties.attachmentBlendOp.disabled,
					$properties.attachmentBlendOp.disabled,
					$properties.attachmentBlendOp.disabled,
					$properties.attachmentBlendOp.disabled,
				);
			};
			dynamic = {
				dynamicState = ( viewport, scissor, blend_constants );
			};
			layout = quakebsp_layout;
			renderPass = renderpass;
		};
		bsp_skybox = {
			subpass = 1;
			stages = (
				{
					stage = vertex;
					name = main;
					module = $builtin/quakebsp.vert;
				},
				{
					stage = fragment;
					name = main;
					module = $builtin/bsp_sky.frag;
					specializationInfo = {
						mapEntries = (
							// doSkyBox
							{ size = 4; offset = 0; constantID = 0; },
							// doSkySheet
							{ size = 4; offset = 4; constantID = 1; },
						);
						data = "array(1, 0)";
					};
				},
			);
			vertexInput   = $properties.vertexInput.brush;
			inputAssembly = $properties.inputAssembly.brush;
			viewport      = $properties.viewport;
			rasterization = $properties.rasterization.cw_cull_back;
			multisample   = $properties.multisample;
			depthStencil  = $properties.depthStencil.test_only;
			colorBlend = {
				logicOpEnable = false;
				attachments = ($properties.attachmentBlendOp.disabled);
			};
			dynamic = {
				dynamicState = ( viewport, scissor );
			};
			layout = quakebsp_layout;
			renderPass = renderpass;
		};
		bsp_skysheet = {
			subpass = 1;
			stages = (
				{
					stage = vertex;
					name = main;
					module = $builtin/quakebsp.vert;
				},
				{
					stage = fragment;
					name = main;
					module = $builtin/bsp_sky.frag;
					specializationInfo = {
						mapEntries = (
							// doSkyBox
							{ size = 4; offset = 0; constantID = 0; },
							// doSkySheet
							{ size = 4; offset = 4; constantID = 1; },
						);
						data = "array(0, 1)";
					};
				},
			);
			vertexInput   = $properties.vertexInput.brush;
			inputAssembly = $properties.inputAssembly.brush;
			viewport      = $properties.viewport;
			rasterization = $properties.rasterization.cw_cull_back;
			multisample   = $properties.multisample;
			depthStencil  = $properties.depthStencil.test_only;
			colorBlend = {
				logicOpEnable = false;
				attachments = ($properties.attachmentBlendOp.disabled);
			};
			dynamic = {
				dynamicState = ( viewport, scissor );
			};
			layout = quakebsp_layout;
			renderPass = renderpass;
		};
		bsp_turb = {
			subpass = 1;
			stages = (
				{
					stage = vertex;
					name = main;
					module = $builtin/quakebsp.vert;
				},
				{
					stage = fragment;
					name = main;
					module = $builtin/bsp_turb.frag;
				},
			);
			vertexInput   = $properties.vertexInput.brush;
			inputAssembly = $properties.inputAssembly.brush;
			viewport      = $properties.viewport;
			rasterization = $properties.rasterization.cw_cull_back;
			multisample   = $properties.multisample;
			depthStencil  = $properties.depthStencil.test_only;
			colorBlend = {
				logicOpEnable = false;
				attachments = ($properties.attachmentBlendOp.disabled);
			};
			dynamic = {
				dynamicState = ( viewport, scissor );
			};
			layout = quakebsp_layout;
			renderPass = renderpass;
		};
		partdraw = {
			subpass = 1;
			stages = (
				{
					stage = vertex;
					name = main;
					module = $builtin/particle.vert;
				},
				{
					stage = geometry;
					name = main;
					module = $builtin/particle.geom;
				},
				{
					stage = fragment;
					name = main;
					module = $builtin/particle.frag;
				},
			);
			vertexInput   = $properties.vertexInput.particle;
			inputAssembly = $properties.inputAssembly.sprite;
			viewport      = $properties.viewport;
			rasterization = $properties.rasterization.cw_cull_back;
			multisample   = $properties.multisample;
			depthStencil  = $properties.depthStencil.test_only;
			colorBlend    = $properties.pipelines.bsp_turb.colorBlend;
			dynamic = {
				dynamicState = ( viewport, scissor, blend_constants );
			};
			layout = partdraw_layout;
			renderPass = renderpass;
		};
		sprite_gbuf = {
			subpass = 2;
			stages = (
				{
					stage = vertex;
					name = main;
					module = $builtin/sprite_gbuf.vert;
				},
				{
					stage = fragment;
					name = main;
					module = $builtin/sprite_gbuf.frag;
				},
			);
			vertexInput   = $properties.vertexInput.index_only;
			inputAssembly = $properties.inputAssembly.sprite;
			viewport      = $properties.viewport;
			rasterization = $properties.rasterization.cw_cull_back;
			multisample   = $properties.multisample;
			depthStencil  = $properties.depthStencil.test_only;
			colorBlend    = $properties.pipelines.alias_gbuf.colorBlend;
			dynamic = {
				dynamicState = ( viewport, scissor, blend_constants );
			};
			layout = sprite_layout;
			renderPass = renderpass;
		};
		sprite_depth = {
			subpass = 0;
			stages = (
				{
					stage = vertex;
					name = main;
					module = $builtin/sprite_depth.vert;
				},
				{
					stage = fragment;
					name = main;
					module = $builtin/sprite_depth.frag;
				},
			);
			vertexInput   = $properties.vertexInput.index_only;
			inputAssembly = $properties.inputAssembly.alias;
			viewport      = $properties.viewport;
			rasterization = $properties.rasterization.cw_cull_back;
			multisample   = $properties.multisample;
			depthStencil  = $properties.depthStencil.test_and_write;
			colorBlend    = $properties.pipelines.alias_gbuf.colorBlend;
			dynamic = {
				dynamicState = ( viewport, scissor );
			};
			layout = sprite_layout;
			renderPass = renderpass;
		};
		twod = {
			subpass = 1;
			stages = (
				{
					stage = vertex;
					name = main;
					module = $builtin/twod.vert;
				},
				{
					stage = fragment;
					name = main;
					module = $builtin/twod.frag;
				},
			);
			vertexInput   = $properties.vertexInput.twod;
			inputAssembly = $properties.inputAssembly.twod;
			viewport      = $properties.viewport;
			rasterization = $properties.rasterization.counter_cw_cull_back;
			multisample   = $properties.multisample;
			depthStencil  = $properties.depthStencil.test_only;
			colorBlend = {
				logicOpEnable = false;
				attachments = ($properties.attachmentBlendOp.alpha_blend);
			};
			dynamic = {
				dynamicState = ( viewport, scissor );
			};
			layout = twod_layout;
			renderPass = renderpass;
		};
		lighting = {
			subpass = 3;
			stages = (
				{
					stage = vertex;
					name = main;
					module = $builtin/passthrough.vert;
				},
				{
					stage = fragment;
					name = main;
					module = $builtin/lighting.frag;
					specializationInfo = {
						mapEntries = (
							{ size = 4; offset = 0; constantID = 0; },
						);
						data = "array(uint($properties.limits.maxSamplers))";
					};
				},
			);
			vertexInput   = $properties.fsquad.vertexInput;
			inputAssembly = $properties.fsquad.inputAssembly;
			viewport      = $properties.viewport;
			rasterization = $properties.rasterization.counter_cw_cull_back;
			multisample   = $properties.multisample;
			depthStencil  = $properties.depthStencil.disable;
			colorBlend    = $properties.fsquad.colorBlend;
			dynamic = {
				dynamicState = ( viewport, scissor );
			};
			layout = lighting_layout;
			renderPass = renderpass;
		};
		compose = {
			subpass = 4;
			stages = (
				{
					stage = vertex;
					name = main;
					module = $builtin/passthrough.vert;
				},
				{
					stage = fragment;
					name = main;
					module = $builtin/compose.frag;
				},
			);
			vertexInput   = $properties.fsquad.vertexInput;
			inputAssembly = $properties.fsquad.inputAssembly;
			viewport      = $properties.viewport;
			rasterization = $properties.rasterization.counter_cw_cull_back;
			multisample   = $properties.multisample;
			depthStencil  = $properties.depthStencil.disable;
			colorBlend    = $properties.fsquad.colorBlend;
			dynamic = {
				dynamicState = ( viewport, scissor );
			};
			layout = compose_layout;
			renderPass = renderpass;
		};
		partphysics = {
			stage = {
				stage = compute;
				name = main;
				module = $builtin/partphysics.comp;
			};
			layout = partphysics_layout;
		};
		partupdate = {
			stage = {
				stage = compute;
				name = main;
				module = $builtin/partupdate.comp;
			};
			layout = partupdate_layout;
		};
	};
}
