Candle-Fire / umbra

1 stars 3 forks source link

Replace the renderer with a modern, module version. #7

Closed TheCurle closed 1 year ago

TheCurle commented 2 years ago

The Why

Vulkan is very verbose. To render something that rotates, you need to:

That's very annoying, and extremely hardcoded for a simple object. What's worse is making a complicated object, with constraints, hinges, animations, textures, specular, cubemaps...

To make this easier would require some serious refactoring.

The Theory

Some sort of builder pattern, whereby you give each bit of geometry the data it needs to construct its vertex buffers and pipeline automatically, would help greatly.

To be able to render a skybox, for example, you only need:

To be able to render something like a walrus, you need:

This materialized in the form of ModelBuilder, and its associated Model that stores all the data necessary to render an object. Simply by passing the VkCommandBuffer currently being used to draw, allows it to handle it all automatically.

Likewise, to actually submit something for rendering, we have to:

That's a LOT. If we want to include Compute Shaders in this, it gets a lot more complicated. To handle this, the GenericRenderPass, ScreenRenderPass, ComputeRenderPass, and RenderCommand abstractions were made.

A standard render loop now looks like this:

renderCommands->executeSimple(rendercommands->getFrame(), [](const int frame) {  },
                   [&](const VkCommandBuffer& buffer, int frame) {
                       renderPass->getPass()->execute(buffer, frame, {
                           [&](const VkCommandBuffer& commands) {
                               cube->render(commands, frame, 1);
                           }
                       });
                   }
        );

Render passes with multiple subPasses can be handled too:

commands->execute(commands->getFrame(), swapchain->swapChain, update,
            [this](const VkCommandBuffer& buffer, int frame) {
                renderPass->getPass()->execute(buffer, frame, {
                        // Render our model
                        [&](const VkCommandBuffer &commands) {
                            cube->render(commands, frame, 1);
                        },
                        // Render ImGUI
                        [&](const VkCommandBuffer &commands) {
                            ImGui_ImplVulkan_NewFrame();
                            ImGui_ImplSDL2_NewFrame();
                            ImGui::NewFrame();

                            ImGui::Begin("sup?");
                            ImGui::End();

                            ImGui::Render();
                            ImGuiIO &io = ImGui::GetIO();
                            (void) io;

                            ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), commands);
                        }
                });
            }
    );

Very simply, this takes all the bullshit away from rendering with Vulkan.

The Neat Bit

The new renderer can automatically keep track of things like textures, that are no longer used. Say, a Model is destructed. The texture and vertex buffers we uploaded to the GPU are no longer necessary, so we can discard them, but doing that manually is painful.

RefCountedTexture allows for a texture to be reused by multiple objects, and deleted from the GPU when no longer accessed by a single object, without need for manual tracking or resource destruction.

Likewise, all the Buffer abstractions can automatically handle deleting their linked data when destructed, along with all the Images and VertexBuffers that use them.

Necessary changes

The Module Manager now stores the renderer as a special item, and there's a specialcase for RendererModule that contains some functions that the game needs to know about the renderer to be able to do its thing.

Extra Features

Just to be nice, i also:

TheCurle commented 1 year ago

Two things to note:

This is dependent on #8.

There are lots of validation errors currently, which should mostly be fixed by https://github.com/ocornut/imgui/issues/5922.