diff options
author | quou <quou@disroot.org> | 2025-03-10 13:18:03 +1100 |
---|---|---|
committer | quou <quou@disroot.org> | 2025-03-10 13:18:03 +1100 |
commit | a7ef36bc519dff1700048ba8f21658daa138a81a (patch) | |
tree | 8778d112afdf21be6c1856fc062b8969f5ee3739 | |
parent | 0bc95e2084b970819d15306f7e3ab8b81a108dcd (diff) |
msaa
-rw-r--r-- | c2.cpp | 52 | ||||
-rw-r--r-- | model.cpp | 2 | ||||
-rw-r--r-- | pipeline.cpp | 11 | ||||
-rw-r--r-- | renderer.cpp | 6 | ||||
-rw-r--r-- | renderer.hpp | 1 | ||||
-rw-r--r-- | video.cpp | 115 | ||||
-rw-r--r-- | video.hpp | 15 |
7 files changed, 172 insertions, 30 deletions
@@ -24,6 +24,8 @@ extern "C" { #define scene_arena_size (1024 * 4) #define per_frame_memory_size (1024 * 1024) +#define MSAA_SAMPLES 4 + static float verts[] = { 0.5f, 0.5f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, -0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, @@ -653,7 +655,7 @@ struct C2 : public App { Tonemap tonemap; Buffer_Id vbo, cbuf; Sampler_Id clamped_linear; - Texture_Id hdr_target; + Texture_Id hdr_target, hdr_resolved, ms_depth; Texture_Id ui_texture; Buffer_Id ui_buffer; Line_Renderer lr; @@ -876,7 +878,7 @@ struct C2 : public App { pb.begin_rp(); pb.rp_target(hdr_target, Clear_Mode::restore); - pb.rp_depth_target(dev->get_depth_target(), Clear_Mode::restore); + pb.rp_depth_target(ms_depth, Clear_Mode::restore); Render_Pass& sky_pass = pb.build_rp(); pb.begin_rp(); @@ -903,6 +905,7 @@ struct C2 : public App { dev, &frame_arena, hdr_target, + ms_depth, &lighting ); ctx.debug_pop(); @@ -919,6 +922,8 @@ struct C2 : public App { ); ctx.debug_pop(); + ctx.resolve(hdr_resolved, hdr_target); + tonemap.update(dev, 0.2f); ctx.debug_push("TONEMAP"); @@ -927,7 +932,7 @@ struct C2 : public App { &frame_arena, quad, tonemap_pass, - hdr_target, + hdr_resolved, clamped_linear ); ctx.debug_pop(); @@ -1014,6 +1019,8 @@ struct C2 : public App { assets.destroy(); dev->destroy_texture(default_texture); dev->destroy_texture(hdr_target); + dev->destroy_texture(hdr_resolved); + dev->destroy_texture(ms_depth); dev->destroy_texture(ui_texture); dev->destroy_buffer(ui_buffer); dev->destroy_sampler(clamped_linear); @@ -1025,7 +1032,9 @@ struct C2 : public App { void on_resize() override { ui->layout(w, h); dev->on_resize(); + dev->destroy_texture(ms_depth); dev->destroy_texture(hdr_target); + dev->destroy_texture(hdr_resolved); dev->destroy_texture(ui_texture); dev->destroy_buffer(ui_buffer); make_hdr_target(); @@ -1033,16 +1042,43 @@ struct C2 : public App { } void make_hdr_target() { + int sw = dev->swap_w(); + int sh = dev->swap_h(); hdr_target = dev->create_texture( - "HDR target", + "MS HDR target", texture_format_rgba16f, - Texture_Flags::sampleable | Texture_Flags::colour_target, - dev->swap_w(), - dev->swap_h(), + Texture_Flags::copy_src | Texture_Flags::colour_target, + sw, + sh, 1, 1, 1, - Buffer_Id(0) + Buffer_Id(0), + MSAA_SAMPLES + ); + hdr_resolved = dev->create_texture( + "Resolved HDR", + texture_format_rgba16f, + Texture_Flags::sampleable | Texture_Flags::copy_dst, + sw, + sh, + 1, + 1, + 1, + Buffer_Id(0), + 1 + ); + ms_depth = dev->create_texture( + "MS depth", + texture_format_d24s8, + Texture_Flags::sampleable | Texture_Flags::depth_stencil_target, + sw, + sh, + 1, + 1, + 1, + 0, + MSAA_SAMPLES ); } @@ -384,7 +384,7 @@ void Model_Instance::render( res.vp ); } else { - pb.depth(true, false, Depth_Mode::equal); + pb.depth(true, true, Depth_Mode::less); pb.shader(mesh.shader); pb.sbuffer(mesh.light_binding, lighting->lights.gpuonly); pb.sbuffer(mesh.casters_binding, lighting->casters.gpuonly); diff --git a/pipeline.cpp b/pipeline.cpp index 0636a1c..374dad8 100644 --- a/pipeline.cpp +++ b/pipeline.cpp @@ -23,6 +23,7 @@ Pipeline_Builder& Pipeline_Builder::rp_target(Texture_Id id, Colour clear) { Render_Pass::Target t{ .id = id, .fmt = texture.fmt, + .samples = texture.samples, .mode = Clear_Mode::clear, .clear = { .colour = clear } }; @@ -37,6 +38,7 @@ Pipeline_Builder& Pipeline_Builder::rp_target(Texture_Id id, Clear_Mode clear) { Render_Pass::Target t{ .id = id, .fmt = texture.fmt, + .samples = texture.samples, .mode = clear, .clear = { .depth = 0.0f } }; @@ -51,6 +53,7 @@ Pipeline_Builder& Pipeline_Builder::rp_depth_target(Texture_Id id, float clear) Render_Pass::Target t{ .id = id, .fmt = texture.fmt, + .samples = texture.samples, .mode = Clear_Mode::clear, .clear = { .depth = clear } }; @@ -63,6 +66,7 @@ Pipeline_Builder& Pipeline_Builder::rp_depth_target(Texture_Id id, Clear_Mode mo Render_Pass::Target t{ .id = id, .fmt = texture.fmt, + .samples = texture.samples, .mode = mode, .clear = { .depth = 0.0f } }; @@ -73,7 +77,7 @@ Pipeline_Builder& Pipeline_Builder::rp_depth_target(Texture_Id id, Clear_Mode mo void Pipeline_Builder::validate_rp() { int i, c = pass->colour_count; - int w, h; + int w, h, s; assert(c || pass->depth.id); if (c) { Texture& tex = dev->get_texture(pass->colours[0].id); @@ -81,7 +85,8 @@ void Pipeline_Builder::validate_rp() { assert(pass->colours[0].fmt == tex.fmt); w = tex.w; h = tex.h; - assert(w && h); + s = tex.samples; + assert(w && h && s); } for (i = 1; i < c; i++) { Texture& tex = dev->get_texture(pass->colours[i].id); @@ -89,6 +94,7 @@ void Pipeline_Builder::validate_rp() { assert(pass->colours[i].fmt == tex.fmt); assert(tex.w == w); assert(tex.h == h); + assert(tex.samples == s); } if (pass->depth.id) { Texture& d = dev->get_texture(pass->depth.id); @@ -101,6 +107,7 @@ void Pipeline_Builder::validate_rp() { if (c) { assert(d.w == w); assert(d.h == h); + assert(d.samples == s); } } } diff --git a/renderer.cpp b/renderer.cpp index d8c4895..c7040ec 100644 --- a/renderer.cpp +++ b/renderer.cpp @@ -108,7 +108,9 @@ void Renderer::update_globals( void Renderer::render( Device* dev, - Arena* a, Texture_Id hdr_target, + Arena* a, + Texture_Id hdr_target, + Texture_Id depth_target, const Lighting* l ) { int i, j; @@ -124,7 +126,7 @@ void Renderer::render( Render_Pass& forward_pass = pb .begin_rp() .rp_target(hdr_target, Clear_Mode::restore) - .rp_depth_target(dev->get_depth_target(), Clear_Mode::restore) + .rp_depth_target(depth_target, 1.0f) .build_rp(); Render_Pass* shadow_passes[Lighting::max_shadows]; for (i = 0; i < Lighting::max_shadows; i++) { diff --git a/renderer.hpp b/renderer.hpp index c49c804..6bfe551 100644 --- a/renderer.hpp +++ b/renderer.hpp @@ -50,6 +50,7 @@ struct Renderer { Device* dev, Arena* a, Texture_Id hdr_target, + Texture_Id depth_target, const Lighting* l ); @@ -561,7 +561,8 @@ struct Texture_Vk : public Texture, public Late_Terminated { int array_size, int start_mip, int start_array, - bool alias + bool alias, + int samples ); void destroy(Device_Vk*) override; void set_name(Device_Vk* dev, const char* name); @@ -732,7 +733,8 @@ struct Pipeline_Vk { Arena& scope, Device_Vk* dev, VkGraphicsPipelineCreateInfo& info, - const Pipeline& desc + const Pipeline& desc, + const Render_Pass& rpo ); void init_depthstencil( Arena& scope, @@ -934,6 +936,7 @@ struct Device_Vk : public Device { VkPhysicalDevice phys_dev; VkSurfaceKHR surf; uint32_t backbuffer_index; + VkSampleCountFlagBits max_samples; Texture_Id backbuffer_id; Swap_Cap swap_cap; VkPhysicalDeviceMemoryProperties mem_props; @@ -1021,6 +1024,9 @@ struct Device_Vk : public Device { void create_terminators(); void create_depth(int w, int h); + VkSampleCountFlagBits get_max_samples(); + VkSampleCountFlagBits get_samples(int); + int find_memory_type( uint32_t filter, VkMemoryPropertyFlags flags @@ -1114,6 +1120,37 @@ void Device_Vk::init_validation() { #endif +VkSampleCountFlagBits Device_Vk::get_max_samples() { + VkPhysicalDeviceProperties p; + VkSampleCountFlagBits + i = VK_SAMPLE_COUNT_64_BIT, + e = VK_SAMPLE_COUNT_1_BIT; + VkSampleCountFlags c; + vkGetPhysicalDeviceProperties(phys_dev, &p); + c = + p.limits.framebufferColorSampleCounts & + p.limits.framebufferDepthSampleCounts; + for (; i >= e; i = (VkSampleCountFlagBits)(i >> 1)) + if (c & i) return i; + return VK_SAMPLE_COUNT_1_BIT; +} + +VkSampleCountFlagBits Device_Vk::get_samples( + int c +) { + VkSampleCountFlagBits b = VK_SAMPLE_COUNT_1_BIT; + switch (c) { + case 1: b = VK_SAMPLE_COUNT_1_BIT; break; + case 2: b = VK_SAMPLE_COUNT_2_BIT; break; + case 4: b = VK_SAMPLE_COUNT_4_BIT; break; + case 8: b = VK_SAMPLE_COUNT_8_BIT; break; + case 16: b = VK_SAMPLE_COUNT_16_BIT; break; + case 32: b = VK_SAMPLE_COUNT_32_BIT; break; + case 64: b = VK_SAMPLE_COUNT_64_BIT; break; + default: break; + } + return std::min(max_samples, b); +} bool Device_Vk::has_validation() { unsigned count, i; @@ -1352,6 +1389,7 @@ void Device_Vk::init_internal() { #endif surf = app_create_vk_surface(app, inst); create_dev(&swap_cap); + max_samples = get_max_samples(); vrama.init(this); gladLoaderLoadVulkan(inst, phys_dev, dev); vkGetDeviceQueue(dev, (uint32_t)queue_index, 0, &queue); @@ -1642,7 +1680,7 @@ void Renderpass_Vk::init( auto& colour = rp.colours[i]; auto& ad = ads[index]; ad.format = get_vk_format(colour.fmt); - ad.samples = VK_SAMPLE_COUNT_1_BIT; + ad.samples = dev->get_samples(colour.samples); ad.loadOp = load_op_from_mode(colour.mode); ad.storeOp = VK_ATTACHMENT_STORE_OP_STORE; ad.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; @@ -1659,9 +1697,10 @@ void Renderpass_Vk::init( if (has_depth) { int i = count++; auto& ad = ads[i]; - ad.format = get_vk_format(dev->get_texture(rp.depth.id).fmt); - ad.samples = VK_SAMPLE_COUNT_1_BIT; - ad.loadOp = load_op_from_mode(rp.depth.mode); + auto& depth = rp.depth; + ad.format = get_vk_format(dev->get_texture(depth.id).fmt); + ad.samples = dev->get_samples(depth.samples); + ad.loadOp = load_op_from_mode(depth.mode); ad.storeOp = VK_ATTACHMENT_STORE_OP_STORE; ad.stencilLoadOp = ad.loadOp; ad.stencilStoreOp = VK_ATTACHMENT_STORE_OP_STORE; @@ -1887,7 +1926,8 @@ Texture_Id Swapchain::create_image( 1, 0, 0, - true + true, + 1 ); return id; } @@ -2286,6 +2326,37 @@ void Context::copy( ); } +void Context::resolve(Texture_Id dst, Texture_Id src) { + Context_Vk* ctx = (Context_Vk*)this; + Device_Vk* dev = ctx->dev; + Texture_Vk& d = *(Texture_Vk*)&dev->get_texture(dst); + Texture_Vk& s = *(Texture_Vk*)&dev->get_texture(src); + VkImageResolve r{}; + r.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + r.srcSubresource.layerCount = 1; + r.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + r.dstSubresource.layerCount = 1; + r.extent.width = d.w; + r.extent.height = d.h; + r.extent.depth = 1; + assert(d.w == s.w); + assert(d.h == s.h); + assert(d.d == 1 && s.d == 1); + assert(d.samples == 1 && s.samples > 1); + ctx->check_end_rp(); + transition(src, Resource_State::copy_src); + transition(dst, Resource_State::copy_dst); + vkCmdResolveImage( + ctx->cb, + s.image, + state_to_image_layout(s.state), + d.image, + state_to_image_layout(d.state), + 1, + &r + ); +} + void Context::transition(Texture_Id id, Resource_State state) { Context_Vk* ctx = (Context_Vk*)this; Device_Vk* dev = ctx->dev; @@ -2434,6 +2505,14 @@ void Context::transition(Texture_Id id, Resource_State state) { b.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; src_stage = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; dst_stage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; + } else if ( + src_layout == VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL && + dst_layout == VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL + ) { + b.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; + b.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT; + src_stage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; + dst_stage = VK_PIPELINE_STAGE_TRANSFER_BIT; } else { print_err("Bad resource transition.\n"); assert(0); @@ -2857,7 +2936,8 @@ void Pipeline_Vk::init_msaa( Arena& scope, Device_Vk* dev, VkGraphicsPipelineCreateInfo& info, - const Pipeline& desc + const Pipeline& desc, + const Render_Pass& rpo ) { VkPipelineMultisampleStateCreateInfo& mi = *(VkPipelineMultisampleStateCreateInfo*)arena_alloc( @@ -2869,7 +2949,7 @@ void Pipeline_Vk::init_msaa( zero(&mi, sizeof mi); mi.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO; mi.sampleShadingEnable = VK_FALSE; - mi.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT; + mi.rasterizationSamples = dev->get_samples(rpo.get_samples()); info.pMultisampleState = &mi; } @@ -3064,7 +3144,7 @@ void Pipeline_Vk::init(Device_Vk* dev, const Pso_Key& key) { init_input_assembly(scope, dev, info, desc); init_viewport(scope, info, desc); init_rasterisation(scope, dev, info, desc); - init_msaa(scope, dev, info, desc); + init_msaa(scope, dev, info, desc, key.rpo.rpo); init_depthstencil(scope, dev, info, desc); init_blending(scope, dev, info, key.rpo.rpo, desc); info.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; @@ -3594,7 +3674,8 @@ Texture_Id Device::create_texture( int d, int mip_count, int array_size, - Buffer_Id init + Buffer_Id init, + int samples ) { VkImageCreateInfo ii{}; VkResult r; @@ -3626,7 +3707,7 @@ Texture_Id Device::create_texture( ii.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; ii.usage = get_texture_usage(flags); ii.sharingMode = VK_SHARING_MODE_EXCLUSIVE; - ii.samples = VK_SAMPLE_COUNT_1_BIT; + ii.samples = dev->get_samples(samples); ii.flags = image_flags; r = vkCreateImage(dev->dev, &ii, &dev->ac, &image); if (r != VK_SUCCESS) { @@ -3684,7 +3765,8 @@ Texture_Id Device::create_texture( array_size, 0, 0, - false + false, + samples ); if (init) { Context& ctx = dev->acquire(); @@ -3747,7 +3829,8 @@ Texture_Id Device::alias_texture( array_size, start_mip, start_array, - true + true, + texture.samples ); nt.set_name(dev, name); return ntid; @@ -4049,7 +4132,8 @@ void Texture_Vk::init( int array_size, int start_mip, int start_array, - bool alias + bool alias, + int samples ) { t->id = id; t->parent = parent; @@ -4069,6 +4153,7 @@ void Texture_Vk::init( t->start_mip = start_mip; t->start_array = start_array; t->alias = alias; + t->samples = samples; } void Texture_Vk::destroy(Device_Vk* dev) { @@ -133,6 +133,7 @@ struct Pipeline { Cull_Mode cull_mode; Vertex_Format_Id vertex_format; Shader_Id shader; + int samples; Descriptor descriptors[pipeline_max_descriptors]; int descriptor_count; @@ -161,7 +162,8 @@ struct Pipeline { blend_dst_alpha == other.blend_dst_alpha && blend_mode == other.blend_mode && blend_mode_alpha == other.blend_mode_alpha && - cull_mode == other.cull_mode; + cull_mode == other.cull_mode && + samples == other.samples; } bool desc_layout_eq(const Pipeline& other) const { @@ -228,6 +230,7 @@ struct Render_Pass { struct Target { Texture_Id id; Texture_Format fmt; + int samples; Clear_Mode mode; union { Colour colour; @@ -266,6 +269,11 @@ struct Render_Pass { } return true; } + + int get_samples() const { + if (colour_count) return colours[0].samples; + return depth.samples; + } }; struct Vertex_Buffer_Binding { @@ -359,6 +367,7 @@ struct Texture : public Asset { int w, h, d; int mip_count, array_size; int start_mip, start_array; + int samples; bool alias; }; @@ -486,7 +495,8 @@ struct Device { int d, int mip_count, int array_size, - Buffer_Id init + Buffer_Id init, + int samples = 1 ); Texture_Id alias_texture( Texture_Id o, @@ -562,6 +572,7 @@ struct Context { int w, int h ); + void resolve(Texture_Id dst, Texture_Id src); void transition(Texture_Id id, Resource_State state); void debug_push(const char* name); void debug_pop(); |