From 83598f44a949c6598b886f8e2f12cbc241d306cc Mon Sep 17 00:00:00 2001 From: Faith Ekstrand Date: Mon, 30 Jan 2023 20:11:52 -0600 Subject: [PATCH] nvk: Graphics pipelines Part-of: --- src/nouveau/vulkan/meson.build | 1 + src/nouveau/vulkan/nvk_cmd_draw.c | 5 + src/nouveau/vulkan/nvk_graphics_pipeline.c | 321 +++++++++++++++++++++ src/nouveau/vulkan/nvk_pipeline.c | 10 - src/nouveau/vulkan/nvk_pipeline.h | 21 ++ 5 files changed, 348 insertions(+), 10 deletions(-) create mode 100644 src/nouveau/vulkan/nvk_graphics_pipeline.c diff --git a/src/nouveau/vulkan/meson.build b/src/nouveau/vulkan/meson.build index 1c0ef7a85a4..16f5d018c90 100644 --- a/src/nouveau/vulkan/meson.build +++ b/src/nouveau/vulkan/meson.build @@ -25,6 +25,7 @@ nvk_files = files( 'nvk_device_memory.h', 'nvk_format.c', 'nvk_format.h', + 'nvk_graphics_pipeline.c', 'nvk_image.c', 'nvk_image.h', 'nvk_image_view.c', diff --git a/src/nouveau/vulkan/nvk_cmd_draw.c b/src/nouveau/vulkan/nvk_cmd_draw.c index 734e16ace96..2460c873f2e 100644 --- a/src/nouveau/vulkan/nvk_cmd_draw.c +++ b/src/nouveau/vulkan/nvk_cmd_draw.c @@ -3,6 +3,7 @@ #include "nvk_image.h" #include "nvk_image_view.h" #include "nvk_physical_device.h" +#include "nvk_pipeline.h" #include "nil_format.h" #include "vulkan/runtime/vk_render_pass.h" @@ -558,7 +559,11 @@ void nvk_cmd_bind_graphics_pipeline(struct nvk_cmd_buffer *cmd, struct nvk_graphics_pipeline *pipeline) { + struct nouveau_ws_push *p = cmd->push; + cmd->state.gfx.pipeline = pipeline; + vk_cmd_set_dynamic_graphics_state(&cmd->vk, &pipeline->dynamic); + nouveau_ws_push_append(p, &pipeline->push); } #define VFMT(vk_fmt, widths, swap_rb, type) \ diff --git a/src/nouveau/vulkan/nvk_graphics_pipeline.c b/src/nouveau/vulkan/nvk_graphics_pipeline.c new file mode 100644 index 00000000000..56b6ce3321b --- /dev/null +++ b/src/nouveau/vulkan/nvk_graphics_pipeline.c @@ -0,0 +1,321 @@ +#include "nvk_pipeline.h" + +#include "nvk_device.h" +#include "nvk_pipeline_layout.h" +#include "nvk_shader.h" +#include "vk_nir.h" +#include "vk_pipeline.h" + +#include "nouveau_context.h" + +#include "nvk_cl9097.h" +#include "nvk_clc397.h" + +static void +emit_pipeline_ts_state(struct nvk_graphics_pipeline *pipeline, + const struct vk_tessellation_state *ts) +{ + assert(ts->domain_origin == VK_TESSELLATION_DOMAIN_ORIGIN_UPPER_LEFT); +} + +static void +emit_pipeline_vp_state(struct nvk_graphics_pipeline *pipeline, + const struct vk_viewport_state *vp) +{ + struct nouveau_ws_push *p = &pipeline->push; + + P_IMMD(p, NV9097, SET_VIEWPORT_Z_CLIP, vp->depth_clip_negative_one_to_one ? + RANGE_NEGATIVE_W_TO_POSITIVE_W : + RANGE_ZERO_TO_POSITIVE_W); +} + +static uint32_t +vk_to_nv9097_polygon_mode(VkPolygonMode vk_mode) +{ + ASSERTED uint16_t vk_to_nv9097[] = { + [VK_POLYGON_MODE_FILL] = NV9097_SET_FRONT_POLYGON_MODE_V_FILL, + [VK_POLYGON_MODE_LINE] = NV9097_SET_FRONT_POLYGON_MODE_V_LINE, + [VK_POLYGON_MODE_POINT] = NV9097_SET_FRONT_POLYGON_MODE_V_POINT, + }; + assert(vk_mode < ARRAY_SIZE(vk_to_nv9097)); + + uint32_t nv9097_mode = 0x1b00 | (2 - vk_mode); + assert(nv9097_mode == vk_to_nv9097[vk_mode]); + return nv9097_mode; +} + +static uint32_t +vk_to_nv9097_provoking_vertex(VkProvokingVertexModeEXT vk_mode) +{ + STATIC_ASSERT(VK_PROVOKING_VERTEX_MODE_FIRST_VERTEX_EXT == + NV9097_SET_PROVOKING_VERTEX_V_FIRST); + STATIC_ASSERT(VK_PROVOKING_VERTEX_MODE_LAST_VERTEX_EXT == + NV9097_SET_PROVOKING_VERTEX_V_LAST); + return vk_mode; +} + +static void +emit_pipeline_rs_state(struct nvk_graphics_pipeline *pipeline, + const struct vk_rasterization_state *rs) +{ + struct nouveau_ws_push *p = &pipeline->push; + + /* TODO: Depth clip/clamp? */ + P_IMMD(p, NV9097, SET_VIEWPORT_CLIP_CONTROL, { + .min_z_zero_max_z_one = MIN_Z_ZERO_MAX_Z_ONE_TRUE, + .pixel_min_z = PIXEL_MIN_Z_CLAMP, + .pixel_max_z = PIXEL_MAX_Z_CLIP, + .geometry_guardband = GEOMETRY_GUARDBAND_SCALE_256, + .line_point_cull_guardband = LINE_POINT_CULL_GUARDBAND_SCALE_256, + .geometry_clip = GEOMETRY_CLIP_WZERO_CLIP, + .geometry_guardband_z = GEOMETRY_GUARDBAND_Z_SAME_AS_XY_GUARDBAND, + }); + + const uint32_t polygon_mode = vk_to_nv9097_polygon_mode(rs->polygon_mode); + P_MTHD(p, NV9097, SET_FRONT_POLYGON_MODE); + P_NV9097_SET_FRONT_POLYGON_MODE(p, polygon_mode); + P_NV9097_SET_BACK_POLYGON_MODE(p, polygon_mode); + + P_IMMD(p, NV9097, SET_PROVOKING_VERTEX, + vk_to_nv9097_provoking_vertex(rs->provoking_vertex)); + + assert(rs->rasterization_stream == 0); + + assert(rs->line.mode == VK_LINE_RASTERIZATION_MODE_DEFAULT_EXT); + + P_IMMD(p, NV9097, SET_LINE_STIPPLE, rs->line.stipple.enable); +} + +static void +emit_pipeline_ms_state(struct nvk_graphics_pipeline *pipeline, + const struct vk_multisample_state *ms) +{ + struct nouveau_ws_push *p = &pipeline->push; + + P_IMMD(p, NV9097, SET_ANTI_ALIAS, ffs(ms->rasterization_samples) - 1); + P_IMMD(p, NV9097, SET_ANTI_ALIAS_ENABLE, ms->sample_shading_enable); + P_IMMD(p, NV9097, SET_ANTI_ALIAS_ALPHA_CONTROL, { + .alpha_to_coverage = ms->alpha_to_coverage_enable, + .alpha_to_one = ms->alpha_to_one_enable, + }); + + /* TODO */ + P_IMMD(p, NV9097, SET_ANTI_ALIASED_LINE, ENABLE_FALSE); +} + +static uint32_t +vk_to_nv9097_blend_op(VkBlendOp vk_op) +{ +#define OP(vk, nv) [VK_BLEND_OP_##vk] = NV9097_SET_BLEND_COLOR_OP_V_OGL_##nv + ASSERTED uint16_t vk_to_nv9097[] = { + OP(ADD, FUNC_ADD), + OP(SUBTRACT, FUNC_SUBTRACT), + OP(REVERSE_SUBTRACT, FUNC_REVERSE_SUBTRACT), + OP(MIN, MIN), + OP(MAX, MAX), + }; + assert(vk_op < ARRAY_SIZE(vk_to_nv9097)); +#undef OP + + return vk_to_nv9097[vk_op]; +} + +static uint32_t +vk_to_nv9097_blend_factor(VkBlendFactor vk_factor) +{ +#define FACTOR(vk, nv) [VK_BLEND_FACTOR_##vk] = \ + NV9097_SET_BLEND_COLOR_SOURCE_COEFF_V_##nv + ASSERTED uint16_t vk_to_nv9097[] = { + FACTOR(ZERO, OGL_ZERO), + FACTOR(ONE, OGL_ONE), + FACTOR(SRC_COLOR, OGL_SRC_COLOR), + FACTOR(ONE_MINUS_SRC_COLOR, OGL_ONE_MINUS_SRC_COLOR), + FACTOR(DST_COLOR, OGL_DST_COLOR), + FACTOR(ONE_MINUS_DST_COLOR, OGL_ONE_MINUS_DST_COLOR), + FACTOR(SRC_ALPHA, OGL_SRC_ALPHA), + FACTOR(ONE_MINUS_SRC_ALPHA, OGL_ONE_MINUS_SRC_ALPHA), + FACTOR(DST_ALPHA, OGL_DST_ALPHA), + FACTOR(ONE_MINUS_DST_ALPHA, OGL_ONE_MINUS_DST_ALPHA), + FACTOR(CONSTANT_COLOR, OGL_CONSTANT_COLOR), + FACTOR(ONE_MINUS_CONSTANT_COLOR, OGL_ONE_MINUS_CONSTANT_COLOR), + FACTOR(CONSTANT_ALPHA, OGL_CONSTANT_ALPHA), + FACTOR(ONE_MINUS_CONSTANT_ALPHA, OGL_ONE_MINUS_CONSTANT_ALPHA), + FACTOR(SRC_ALPHA_SATURATE, OGL_SRC_ALPHA_SATURATE), + FACTOR(SRC1_COLOR, OGL_SRC1COLOR), + FACTOR(ONE_MINUS_SRC1_COLOR, OGL_INVSRC1COLOR), + FACTOR(SRC1_ALPHA, OGL_SRC1ALPHA), + FACTOR(ONE_MINUS_SRC1_ALPHA, OGL_INVSRC1ALPHA), + }; + assert(vk_factor < ARRAY_SIZE(vk_to_nv9097)); +#undef FACTOR + + return vk_to_nv9097[vk_factor]; +} + +static void +emit_pipeline_cb_state(struct nvk_graphics_pipeline *pipeline, + const struct vk_color_blend_state *cb) +{ + struct nouveau_ws_push *p = &pipeline->push; + + P_IMMD(p, NV9097, SET_BLEND_STATE_PER_TARGET, ENABLE_TRUE); + + P_IMMD(p, NV9097, SET_LOGIC_OP, cb->logic_op_enable); + + for (uint32_t a = 0; a < cb->attachment_count; a++) { + const struct vk_color_blend_attachment_state *att = &cb->attachments[a]; + P_IMMD(p, NV9097, SET_BLEND(a), att->blend_enable); + + P_MTHD(p, NV9097, SET_BLEND_PER_TARGET_SEPARATE_FOR_ALPHA(a)); + P_NV9097_SET_BLEND_PER_TARGET_SEPARATE_FOR_ALPHA(p, a, ENABLE_TRUE); + P_NV9097_SET_BLEND_PER_TARGET_COLOR_OP(p, a, + vk_to_nv9097_blend_op(att->color_blend_op)); + P_NV9097_SET_BLEND_PER_TARGET_COLOR_SOURCE_COEFF(p, a, + vk_to_nv9097_blend_factor(att->src_color_blend_factor)); + P_NV9097_SET_BLEND_PER_TARGET_COLOR_DEST_COEFF(p, a, + vk_to_nv9097_blend_factor(att->dst_color_blend_factor)); + P_NV9097_SET_BLEND_PER_TARGET_ALPHA_OP(p, a, + vk_to_nv9097_blend_op(att->alpha_blend_op)); + P_NV9097_SET_BLEND_PER_TARGET_ALPHA_SOURCE_COEFF(p, a, + vk_to_nv9097_blend_factor(att->src_alpha_blend_factor)); + P_NV9097_SET_BLEND_PER_TARGET_ALPHA_DEST_COEFF(p, a, + vk_to_nv9097_blend_factor(att->dst_alpha_blend_factor)); + + P_IMMD(p, NV9097, SET_CT_WRITE(a), { + .r_enable = (att->write_mask & BITFIELD_BIT(0)) != 0, + .g_enable = (att->write_mask & BITFIELD_BIT(1)) != 0, + .b_enable = (att->write_mask & BITFIELD_BIT(2)) != 0, + .a_enable = (att->write_mask & BITFIELD_BIT(3)) != 0, + }); + } +} + +static const uint32_t mesa_to_nv9097_shader_type[] = { + [MESA_SHADER_VERTEX] = NV9097_SET_PIPELINE_SHADER_TYPE_VERTEX, + [MESA_SHADER_TESS_CTRL] = NV9097_SET_PIPELINE_SHADER_TYPE_TESSELLATION_INIT, + [MESA_SHADER_TESS_EVAL] = NV9097_SET_PIPELINE_SHADER_TYPE_TESSELLATION, + [MESA_SHADER_GEOMETRY] = NV9097_SET_PIPELINE_SHADER_TYPE_GEOMETRY, + [MESA_SHADER_FRAGMENT] = NV9097_SET_PIPELINE_SHADER_TYPE_PIXEL, +}; + +VkResult +nvk_graphics_pipeline_create(struct nvk_device *device, + struct vk_pipeline_cache *cache, + const VkGraphicsPipelineCreateInfo *pCreateInfo, + const VkAllocationCallbacks *pAllocator, + VkPipeline *pPipeline) +{ + VK_FROM_HANDLE(nvk_pipeline_layout, pipeline_layout, pCreateInfo->layout); + struct nvk_physical_device *pdevice = nvk_device_physical(device); + struct nvk_graphics_pipeline *pipeline; + VkResult result = VK_SUCCESS; + + pipeline = vk_object_zalloc(&device->vk, pAllocator, sizeof(*pipeline), + VK_OBJECT_TYPE_PIPELINE); + if (pipeline == NULL) + return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY); + + pipeline->base.type = NVK_PIPELINE_GRAPHICS; + + for (uint32_t i = 0; i < pCreateInfo->stageCount; i++) { + const VkPipelineShaderStageCreateInfo *sinfo = &pCreateInfo->pStages[i]; + gl_shader_stage stage = vk_to_mesa_shader_stage(sinfo->stage); + + const nir_shader_compiler_options *nir_options = + nvk_physical_device_nir_options(pdevice, stage); + const struct spirv_to_nir_options *spirv_options = + nvk_physical_device_spirv_options(pdevice); + + nir_shader *nir; + result = vk_pipeline_shader_stage_to_nir(&device->vk, sinfo, + spirv_options, nir_options, + NULL, &nir); + if (result != VK_SUCCESS) + goto fail; + + nvk_lower_nir(device, nir, pipeline_layout); + + result = nvk_compile_nir(pdevice, nir, &pipeline->base.shaders[stage]); + ralloc_free(nir); + if (result != VK_SUCCESS) + goto fail; + + nvk_shader_upload(device, &pipeline->base.shaders[stage]); + } + + nouveau_ws_push_init_cpu(&pipeline->push, &pipeline->push_data, + sizeof(pipeline->push_data)); + struct nouveau_ws_push *p = &pipeline->push; + + for (gl_shader_stage stage = 0; stage <= MESA_SHADER_FRAGMENT; stage++) { + struct nvk_shader *shader = &pipeline->base.shaders[stage]; + uint32_t idx = mesa_to_nv9097_shader_type[stage]; + + P_IMMD(p, NV9097, SET_PIPELINE_SHADER(idx), { + .enable = shader->bo != NULL, + .type = mesa_to_nv9097_shader_type[stage], + }); + + if (shader->bo == NULL) + continue; + + uint64_t addr = nvk_shader_address(shader); + assert(device->ctx->eng3d.cls >= VOLTA_A); + P_MTHD(p, NVC397, SET_PIPELINE_PROGRAM_ADDRESS_A(idx)); + P_NVC397_SET_PIPELINE_PROGRAM_ADDRESS_A(p, idx, addr >> 32 ); + P_NVC397_SET_PIPELINE_PROGRAM_ADDRESS_B(p, idx, addr); + + P_IMMD(p, NV9097, SET_PIPELINE_REGISTER_COUNT(idx), shader->num_gprs); + + switch (stage) { + case MESA_SHADER_VERTEX: + break; + + case MESA_SHADER_FRAGMENT: + P_IMMD(p, NV9097, SET_SUBTILING_PERF_KNOB_A, { + .fraction_of_spm_register_file_per_subtile = 0x10, + .fraction_of_spm_pixel_output_buffer_per_subtile = 0x40, + .fraction_of_spm_triangle_ram_per_subtile = 0x16, + .fraction_of_max_quads_per_subtile = 0x20, + }); + P_NV9097_SET_SUBTILING_PERF_KNOB_B(p, 0x20); + + P_MTHD(p, NV9097, SET_ZCULL_BOUNDS); + P_INLINE_DATA(p, shader->flags[0]); + break; + + default: + unreachable("Unsupported shader stage"); + } + } + + /* TODO: prog_selects_layer */ + P_IMMD(p, NV9097, SET_RT_LAYER, { + .v = 0, + .control = CONTROL_V_SELECTS_LAYER, + }); + + struct vk_graphics_pipeline_all_state all; + struct vk_graphics_pipeline_state state = {}; + result = vk_graphics_pipeline_state_fill(&device->vk, &state, pCreateInfo, + NULL, &all, NULL, 0, NULL); + assert(result == VK_SUCCESS); + + if (state.ts) emit_pipeline_ts_state(pipeline, state.ts); + if (state.vp) emit_pipeline_vp_state(pipeline, state.vp); + if (state.rs) emit_pipeline_rs_state(pipeline, state.rs); + if (state.ms) emit_pipeline_ms_state(pipeline, state.ms); + if (state.cb) emit_pipeline_cb_state(pipeline, state.cb); + + pipeline->dynamic.vi = &pipeline->_dynamic_vi; + pipeline->dynamic.ms.sample_locations = &pipeline->_dynamic_ms_sl; + vk_dynamic_graphics_state_fill(&pipeline->dynamic, &state); + + *pPipeline = nvk_pipeline_to_handle(&pipeline->base); + + return VK_SUCCESS; + +fail: + vk_object_free(&device->vk, pAllocator, pipeline); + return result; +} diff --git a/src/nouveau/vulkan/nvk_pipeline.c b/src/nouveau/vulkan/nvk_pipeline.c index e11af2ffd09..b59ea287018 100644 --- a/src/nouveau/vulkan/nvk_pipeline.c +++ b/src/nouveau/vulkan/nvk_pipeline.c @@ -37,16 +37,6 @@ nvk_pipeline_free(struct nvk_device *device, vk_object_free(&device->vk, pAllocator, pipeline); } -static VkResult -nvk_graphics_pipeline_create(struct nvk_device *device, - struct vk_pipeline_cache *cache, - const VkGraphicsPipelineCreateInfo *pCreateInfo, - const VkAllocationCallbacks *pAllocator, - VkPipeline *pPipeline) -{ - unreachable("Graphics pipelines not yet implemented"); -} - VKAPI_ATTR VkResult VKAPI_CALL nvk_CreateGraphicsPipelines(VkDevice _device, VkPipelineCache pipelineCache, diff --git a/src/nouveau/vulkan/nvk_pipeline.h b/src/nouveau/vulkan/nvk_pipeline.h index a1c6f5f2035..f1bc36d9331 100644 --- a/src/nouveau/vulkan/nvk_pipeline.h +++ b/src/nouveau/vulkan/nvk_pipeline.h @@ -4,6 +4,9 @@ #include "nvk_private.h" #include "nvk_shader.h" +#include "nouveau_push.h" + +#include "vk_graphics_state.h" #include "vk_object.h" struct vk_pipeline_cache; @@ -46,4 +49,22 @@ nvk_compute_pipeline_create(struct nvk_device *device, const VkAllocationCallbacks *pAllocator, VkPipeline *pPipeline); +struct nvk_graphics_pipeline { + struct nvk_pipeline base; + + struct nouveau_ws_push push; + uint32_t push_data[64]; + + struct vk_vertex_input_state _dynamic_vi; + struct vk_sample_locations_state _dynamic_ms_sl; + struct vk_dynamic_graphics_state dynamic; +}; + +VkResult +nvk_graphics_pipeline_create(struct nvk_device *device, + struct vk_pipeline_cache *cache, + const VkGraphicsPipelineCreateInfo *pCreateInfo, + const VkAllocationCallbacks *pAllocator, + VkPipeline *pPipeline); + #endif