{ 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; }, ); }; 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, texture_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; }; }; fstriangle = { vertexInput = { bindings = (); attributes = (); }; inputAssembly = { topology = triangle_list; 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/fstriangle.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.fstriangle.vertexInput; inputAssembly = $properties.fstriangle.inputAssembly; viewport = $properties.viewport; rasterization = $properties.rasterization.counter_cw_cull_back; multisample = $properties.multisample; depthStencil = $properties.depthStencil.disable; colorBlend = $properties.fstriangle.colorBlend; dynamic = { dynamicState = ( viewport, scissor ); }; layout = lighting_layout; renderPass = renderpass; }; compose = { subpass = 4; stages = ( { stage = vertex; name = main; module = $builtin/fstriangle.vert; }, { stage = fragment; name = main; module = $builtin/compose.frag; }, ); vertexInput = $properties.fstriangle.vertexInput; inputAssembly = $properties.fstriangle.inputAssembly; viewport = $properties.viewport; rasterization = $properties.rasterization.counter_cw_cull_back; multisample = $properties.multisample; depthStencil = $properties.depthStencil.disable; colorBlend = $properties.fstriangle.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; }; }; }