1
Fork 0
mirror of https://github.com/redstrate/Novus.git synced 2025-04-20 03:37:46 +00:00

Split up Renderer's source files and a lot of refactoring

This now splits up the rendering system into sensible parts, and makes
it easier to switch between the simple renderer and the new experimental
one. Lots of refactors I needed to do for a while are now done, too.
This commit is contained in:
Joshua Goins 2024-04-21 17:35:48 -04:00
parent 5317300aaf
commit e34daadbcd
31 changed files with 2542 additions and 2174 deletions

View file

@ -28,10 +28,10 @@ MDLPart::MDLPart(GameData *data, FileCache &cache, QWidget *parent)
pbd = physis_parse_pbd(physis_gamedata_extract_file(data, "chara/xls/bonedeformer/human.pbd"));
renderer = new Renderer(data);
renderer = new RenderManager(data);
auto inst = new QVulkanInstance();
inst->setVkInstance(renderer->instance);
inst->setVkInstance(renderer->device().instance);
inst->setFlags(QVulkanInstance::Flag::NoDebugOutputRedirect);
inst->create();
@ -52,14 +52,14 @@ void MDLPart::exportModel(const QString &fileName)
::exportModel(model.name, model.model, *skeleton, boneData, fileName);
}
RenderModel &MDLPart::getModel(const int index)
DrawObject &MDLPart::getModel(const int index)
{
return models[index];
}
void MDLPart::reloadModel(const int index)
{
renderer->reloadModel(models[index], 0);
renderer->reloadDrawObject(models[index], 0);
Q_EMIT modelChanged();
}
@ -82,7 +82,7 @@ void MDLPart::addModel(physis_MDL mdl,
{
qDebug() << "Adding model to MDLPart";
auto model = renderer->addModel(mdl, lod);
auto model = renderer->addDrawObject(mdl, lod);
model.name = name;
model.from_body_id = fromBodyId;
model.to_body_id = toBodyId;
@ -303,7 +303,7 @@ void MDLPart::removeModel(const physis_MDL &mdl)
{
models.erase(std::remove_if(models.begin(),
models.end(),
[mdl](const RenderModel &other) {
[mdl](const DrawObject &other) {
return mdl.p_ptr == other.model.p_ptr;
}),
models.end());
@ -312,12 +312,13 @@ void MDLPart::removeModel(const physis_MDL &mdl)
void MDLPart::setWireframe(bool wireframe)
{
renderer->wireframe = wireframe;
// renderer->wireframe = wireframe;
}
bool MDLPart::wireframe() const
{
return renderer->wireframe;
// return renderer->wireframe;
return false;
}
#include "moc_mdlpart.cpp"

View file

@ -8,7 +8,7 @@
#include <physis.hpp>
#include "mdlexport.h"
#include "renderer.hpp"
#include "rendermanager.h"
struct GameData;
@ -23,7 +23,7 @@ public:
explicit MDLPart(GameData *data, FileCache &cache, QWidget *parent = nullptr);
void exportModel(const QString &fileName);
RenderModel &getModel(int index);
DrawObject &getModel(int index);
void reloadModel(int index);
int lastX = -1;
@ -91,9 +91,9 @@ private:
FileCache &cache;
physis_PBD pbd{};
std::vector<RenderModel> models;
std::vector<DrawObject> models;
Renderer *renderer = nullptr;
RenderManager *renderer = nullptr;
VulkanWindow *vkWindow = nullptr;
bool firstTimeSkeletonDataCalculated = false;
};

View file

@ -9,7 +9,7 @@
#include <glm/gtc/quaternion.hpp>
VulkanWindow::VulkanWindow(MDLPart *part, Renderer *renderer, QVulkanInstance *instance)
VulkanWindow::VulkanWindow(MDLPart *part, RenderManager *renderer, QVulkanInstance *instance)
: m_renderer(renderer)
, m_instance(instance)
, part(part)
@ -203,14 +203,14 @@ void VulkanWindow::render()
part->position += right * movX * 2.0f;
part->position += forward * movY * 2.0f;
m_renderer->view = glm::mat4(1.0f);
m_renderer->view = glm::translate(m_renderer->view, part->position);
m_renderer->view *= glm::mat4_cast(glm::angleAxis(part->yaw, glm::vec3(0, 1, 0)) * glm::angleAxis(part->pitch, glm::vec3(1, 0, 0)));
m_renderer->view = glm::inverse(m_renderer->view);
m_renderer->camera.view = glm::mat4(1.0f);
m_renderer->camera.view = glm::translate(m_renderer->camera.view, part->position);
m_renderer->camera.view *= glm::mat4_cast(glm::angleAxis(part->yaw, glm::vec3(0, 1, 0)) * glm::angleAxis(part->pitch, glm::vec3(1, 0, 0)));
m_renderer->camera.view = glm::inverse(m_renderer->camera.view);
} else {
glm::vec3 position(part->cameraDistance * sin(part->yaw), part->cameraDistance * part->pitch, part->cameraDistance * cos(part->yaw));
m_renderer->view = glm::lookAt(part->position + position, part->position, glm::vec3(0, -1, 0));
m_renderer->camera.view = glm::lookAt(part->position + position, part->position, glm::vec3(0, -1, 0));
}
m_renderer->render(models);

View file

@ -11,7 +11,7 @@
class VulkanWindow : public QWindow
{
public:
VulkanWindow(MDLPart *part, Renderer *renderer, QVulkanInstance *instance);
VulkanWindow(MDLPart *part, RenderManager *renderer, QVulkanInstance *instance);
void exposeEvent(QExposeEvent *) override;
@ -19,12 +19,12 @@ public:
void render();
std::vector<RenderModel> models;
std::vector<DrawObject> models;
bool freeMode = false;
private:
bool m_initialized = false;
Renderer *m_renderer;
RenderManager *m_renderer;
QVulkanInstance *m_instance;
MDLPart *part;
bool pressed_keys[4] = {};

View file

@ -8,13 +8,25 @@ find_package(SPIRV-Headers REQUIRED)
add_library(renderer STATIC)
target_sources(renderer
PRIVATE
include/renderer.hpp
include/baserenderer.h
include/buffer.h
include/camera.h
include/device.h
include/drawobject.h
include/gamerenderer.h
include/rendermanager.h
include/shaderstructs.h
include/simplerenderer.h
include/swapchain.h
include/texture.h
src/renderer.cpp
src/device.cpp
src/gamerenderer.cpp
src/imguipass.cpp
src/imguipass.h
src/rendersystem.cpp
include/rendersystem.h)
src/rendermanager.cpp
src/simplerenderer.cpp
src/swapchain.cpp)
qt_add_resources(renderer
"shaders"
PREFIX "/"
@ -24,7 +36,9 @@ qt_add_resources(renderer
shaders/imgui.vert.spv
shaders/mesh.frag.spv
shaders/mesh.vert.spv
shaders/skinned.vert.spv)
shaders/skinned.vert.spv
shaders/blit.vert.spv
shaders/blit.frag.spv)
target_include_directories(renderer PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include)
target_link_libraries(renderer
PUBLIC

View file

@ -0,0 +1,38 @@
// SPDX-FileCopyrightText: 2024 Joshua Goins <josh@redstrate.com>
// SPDX-License-Identifier: GPL-3.0-or-later
#pragma once
#include <QDebug>
#include <string_view>
#include <glm/glm.hpp>
#include <physis.hpp>
#include <spirv.hpp>
#include <spirv_cross.hpp>
#include <spirv_glsl.hpp>
#include <vulkan/vulkan.h>
class Renderer;
struct DrawObject;
struct Camera;
struct Texture;
/// Base class for all rendering implementations
class BaseRenderer
{
public:
virtual ~BaseRenderer() = default;
/// Perform any operations required on resize, such as recreating images.
virtual void resize() = 0;
/// Render a frame into @p commandBuffer. @p currentFrame is the same value as SwapChain::currentFrame for convenience.
virtual void render(VkCommandBuffer commandBuffer, uint32_t currentFrame, Camera &camera, const std::vector<DrawObject> &models) = 0;
/// Do whatever is needed in the backend to prepare it for drawing
virtual void addDrawObject(const DrawObject &drawObject) = 0;
/// The final composite texture that is drawn into with render()
virtual Texture &getCompositeTexture() = 0;
};

14
renderer/include/buffer.h Normal file
View file

@ -0,0 +1,14 @@
// SPDX-FileCopyrightText: 2023 Joshua Goins <josh@redstrate.com>
// SPDX-License-Identifier: GPL-3.0-or-later
#pragma once
#include <vulkan/vulkan.h>
class Buffer
{
public:
VkBuffer buffer = VK_NULL_HANDLE;
VkDeviceMemory memory = VK_NULL_HANDLE;
size_t size = 0;
};

22
renderer/include/camera.h Normal file
View file

@ -0,0 +1,22 @@
// SPDX-FileCopyrightText: 2024 Joshua Goins <josh@redstrate.com>
// SPDX-License-Identifier: GPL-3.0-or-later
#pragma once
#include <glm/mat4x4.hpp>
struct Camera {
/// Field of view in degrees
float fieldOfView = 45.0f;
/// The aspect ratio of the camera, set automatically by @p RenderManager
float aspectRatio = 0.0f;
/// Near plane
float nearPlane = 0.1f;
/// Far plane
float farPlane = 100.0f;
glm::mat4 perspective, view;
};

54
renderer/include/device.h Normal file
View file

@ -0,0 +1,54 @@
// SPDX-FileCopyrightText: 2024 Joshua Goins <josh@redstrate.com>
// SPDX-License-Identifier: GPL-3.0-or-later
#pragma once
#include <string_view>
#include <vector>
#include <vulkan/vulkan.h>
#include "buffer.h"
#include "texture.h"
class SwapChain;
class Device
{
public:
VkInstance instance = VK_NULL_HANDLE;
VkPhysicalDevice physicalDevice = VK_NULL_HANDLE;
VkDevice device = VK_NULL_HANDLE;
VkQueue graphicsQueue = VK_NULL_HANDLE, presentQueue = VK_NULL_HANDLE;
VkCommandPool commandPool = VK_NULL_HANDLE;
SwapChain *swapChain = nullptr;
VkDescriptorPool descriptorPool = VK_NULL_HANDLE;
Buffer createBuffer(size_t size, VkBufferUsageFlags usageFlags);
void copyToBuffer(Buffer &buffer, void *data, size_t size);
uint32_t findMemoryType(uint32_t typeFilter, VkMemoryPropertyFlags properties);
VkShaderModule createShaderModule(const uint32_t *code, int length);
VkShaderModule loadShaderFromDisk(std::string_view path);
Texture createTexture(int width, int height, VkFormat format, VkImageUsageFlags usage);
Texture createDummyTexture();
Buffer createDummyBuffer();
VkCommandBuffer beginSingleTimeCommands();
void endSingleTimeCommands(VkCommandBuffer pT);
void inlineTransitionImageLayout(VkCommandBuffer commandBuffer,
VkImage image,
VkFormat format,
VkImageAspectFlags aspect,
VkImageSubresourceRange range,
VkImageLayout oldLayout,
VkImageLayout newLayout,
VkPipelineStageFlags src_stage_mask = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
VkPipelineStageFlags dst_stage_mask = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT);
};

View file

@ -0,0 +1,46 @@
// SPDX-FileCopyrightText: 2024 Joshua Goins <josh@redstrate.com>
// SPDX-License-Identifier: GPL-3.0-or-later
#pragma once
struct RenderPart {
size_t numIndices;
Buffer vertexBuffer, indexBuffer;
int materialIndex = 0;
};
struct RenderTexture {
VkImage handle = VK_NULL_HANDLE;
VkDeviceMemory memory = VK_NULL_HANDLE;
VkImageView view = VK_NULL_HANDLE;
VkSampler sampler = VK_NULL_HANDLE;
};
enum class MaterialType { Object, Skin };
struct RenderMaterial {
MaterialType type = MaterialType::Object;
RenderTexture *diffuseTexture = nullptr;
RenderTexture *normalTexture = nullptr;
RenderTexture *specularTexture = nullptr;
RenderTexture *multiTexture = nullptr;
};
struct DrawObject {
QString name;
physis_MDL model;
std::vector<RenderPart> parts;
std::array<glm::mat4, 128> boneData;
std::vector<RenderMaterial> materials;
glm::vec3 position;
bool skinned = false;
uint16_t from_body_id = 101;
uint16_t to_body_id = 101;
Buffer boneInfoBuffer;
};

View file

@ -0,0 +1,104 @@
// SPDX-FileCopyrightText: 2024 Joshua Goins <josh@redstrate.com>
// SPDX-License-Identifier: GPL-3.0-or-later
#pragma once
#include <QDebug>
#include <string_view>
#include <glm/glm.hpp>
#include <physis.hpp>
#include <spirv.hpp>
#include <spirv_cross.hpp>
#include <spirv_glsl.hpp>
#include <vulkan/vulkan.h>
#include "baserenderer.h"
#include "buffer.h"
#include "shaderstructs.h"
#include "texture.h"
class Device;
struct RenderModel;
struct DrawObject;
/// Performs rendering by using the game's existing shaders.
class GameRenderer : public BaseRenderer
{
public:
GameRenderer(Device &device, GameData *data);
void resize() override;
void render(VkCommandBuffer commandBuffer, uint32_t currentFrame, Camera &camera, const std::vector<DrawObject> &models) override;
void addDrawObject(const DrawObject &drawObject) override;
Texture &getCompositeTexture() override;
private:
void beginPass(uint32_t imageIndex, VkCommandBuffer commandBuffer, std::string_view passName);
void endPass(VkCommandBuffer commandBuffer, std::string_view passName);
void bindPipeline(VkCommandBuffer commandBuffer, std::string_view passName, physis_Shader &vertexShader, physis_Shader &pixelShader);
VkShaderModule convertShaderModule(const physis_Shader &shader, spv::ExecutionModel executionModel);
spirv_cross::CompilerGLSL getShaderModuleResources(const physis_Shader &shader);
void createImageResources();
physis_SHPK directionalLightningShpk;
physis_SHPK createViewPositionShpk;
struct RenderModel {
physis_SHPK shpk;
::DrawObject *internal_model = nullptr;
};
std::vector<RenderModel> m_renderModels;
struct RequestedBinding {
VkDescriptorType type;
VkShaderStageFlags stageFlags;
bool used = false;
};
struct RequestedSet {
bool used = true;
VkDescriptorSetLayout layout = VK_NULL_HANDLE;
std::vector<RequestedBinding> bindings;
};
struct CachedPipeline {
VkPipeline pipeline = VK_NULL_HANDLE;
VkPipelineLayout pipelineLayout = VK_NULL_HANDLE;
std::vector<VkDescriptorSetLayout> setLayouts;
std::map<uint64_t, VkDescriptorSet> cachedDescriptors;
std::vector<RequestedSet> requestedSets;
physis_Shader vertexShader, pixelShader;
};
// combined vertex + pixel code length
std::unordered_map<uint32_t, CachedPipeline> m_cachedPipelines;
Device &m_device;
GameData *m_data = nullptr;
VkDescriptorSet createDescriptorFor(const CachedPipeline &cachedPipeline, int i);
Buffer g_CameraParameter;
Buffer g_JointMatrixArray;
Buffer g_InstanceParameter;
Buffer g_ModelParameter;
Buffer g_MaterialParameter;
Buffer g_CommonParameter;
Buffer g_LightParam;
Buffer m_planeVertexBuffer;
Texture m_normalGBuffer;
Texture m_viewPositionBuffer;
Texture m_depthBuffer;
Texture m_compositeBuffer;
Texture m_dummyTex;
VkSampler m_sampler;
Buffer m_dummyBuffer;
};

View file

@ -1,162 +0,0 @@
// SPDX-FileCopyrightText: 2023 Joshua Goins <josh@redstrate.com>
// SPDX-License-Identifier: GPL-3.0-or-later
#pragma once
#include <QString>
#include <array>
#include <glm/ext/matrix_float4x4.hpp>
#include <map>
#include <vector>
#include <vulkan/vulkan.h>
#include "rendersystem.h"
struct RenderPart {
size_t numIndices;
VkBuffer vertexBuffer, indexBuffer;
VkDeviceMemory vertexMemory, indexMemory;
int materialIndex = 0;
};
struct RenderTexture {
VkImage handle = VK_NULL_HANDLE;
VkDeviceMemory memory = VK_NULL_HANDLE;
VkImageView view = VK_NULL_HANDLE;
VkSampler sampler = VK_NULL_HANDLE;
};
enum class MaterialType { Object, Skin };
struct RenderMaterial {
MaterialType type = MaterialType::Object;
RenderTexture *diffuseTexture = nullptr;
RenderTexture *normalTexture = nullptr;
RenderTexture *specularTexture = nullptr;
RenderTexture *multiTexture = nullptr;
};
struct RenderModel {
QString name;
physis_MDL model;
std::vector<RenderPart> parts;
std::array<glm::mat4, 128> boneData;
std::vector<RenderMaterial> materials;
glm::vec3 position;
bool skinned = false;
uint16_t from_body_id = 101;
uint16_t to_body_id = 101;
VkBuffer boneInfoBuffer = VK_NULL_HANDLE;
VkDeviceMemory boneInfoMemory = VK_NULL_HANDLE;
};
class ImGuiPass;
struct ImGuiContext;
class Renderer
{
public:
Renderer(GameData *data);
void initPipeline();
void initDescriptors();
void initDepth(int width, int height);
bool initSwapchain(VkSurfaceKHR surface, int width, int height);
void resize(VkSurfaceKHR surface, int width, int height);
void destroySwapchain();
RenderModel addModel(const physis_MDL &model, int lod);
void reloadModel(RenderModel &model, uint32_t lod);
RenderTexture addTexture(uint32_t width, uint32_t height, const uint8_t *data, uint32_t data_size);
void render(const std::vector<RenderModel> &models);
VkInstance instance = VK_NULL_HANDLE;
VkPhysicalDevice physicalDevice = VK_NULL_HANDLE;
VkDevice device = VK_NULL_HANDLE;
VkQueue graphicsQueue = VK_NULL_HANDLE, presentQueue = VK_NULL_HANDLE;
VkCommandPool commandPool = VK_NULL_HANDLE;
VkSwapchainKHR swapchain = VK_NULL_HANDLE;
VkExtent2D swapchainExtent;
std::vector<VkImage> swapchainImages;
std::vector<VkImageView> swapchainViews;
std::vector<VkFramebuffer> swapchainFramebuffers;
VkRenderPass renderPass;
std::array<VkCommandBuffer, 3> commandBuffers;
std::array<VkFence, 3> inFlightFences;
std::array<VkSemaphore, 3> imageAvailableSemaphores, renderFinishedSemaphores;
uint32_t currentFrame = 0;
VkImage depthImage;
VkDeviceMemory depthMemory;
VkImageView depthView;
VkBuffer dummyBuffer;
VkDeviceMemory dummyBufferMemory;
VkImage dummyImage;
VkDeviceMemory dummyMemory;
VkImageView dummyView;
VkSampler dummySampler;
VkDescriptorPool descriptorPool = VK_NULL_HANDLE;
VkDescriptorSetLayout setLayout = VK_NULL_HANDLE;
std::map<uint64_t, VkDescriptorSet> cachedDescriptors;
VkPipeline pipeline;
VkPipeline skinnedPipeline;
VkPipeline pipelineWireframe;
VkPipeline skinnedPipelineWireframe;
VkPipelineLayout pipelineLayout;
bool wireframe = false;
std::tuple<VkBuffer, VkDeviceMemory> createBuffer(size_t size, VkBufferUsageFlags usageFlags);
uint32_t findMemoryType(uint32_t typeFilter, VkMemoryPropertyFlags properties);
VkShaderModule createShaderModule(const uint32_t *code, int length);
VkShaderModule loadShaderFromDisk(std::string_view path);
VkCommandBuffer beginSingleTimeCommands();
void endSingleTimeCommands(VkCommandBuffer pT);
void inlineTransitionImageLayout(VkCommandBuffer commandBuffer,
VkImage image,
VkFormat format,
VkImageAspectFlags aspect,
VkImageSubresourceRange range,
VkImageLayout oldLayout,
VkImageLayout newLayout,
VkPipelineStageFlags src_stage_mask = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
VkPipelineStageFlags dst_stage_mask = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT);
VkDescriptorSet createDescriptorFor(const RenderModel &model, const RenderMaterial &material);
uint64_t hash(const RenderModel &model, const RenderMaterial &material);
glm::mat4 view;
ImGuiContext *ctx = nullptr;
private:
void createDummyTexture();
void createDummyBuffer();
ImGuiPass *imGuiPass = nullptr;
std::unique_ptr<RenderSystem> m_renderSystem;
GameData *m_data = nullptr;
bool m_enableNewRenderSystem = false;
};

View file

@ -0,0 +1,67 @@
// SPDX-FileCopyrightText: 2023 Joshua Goins <josh@redstrate.com>
// SPDX-License-Identifier: GPL-3.0-or-later
#pragma once
#include <array>
#include <map>
#include <vector>
#include <QString>
#include <glm/ext/matrix_float4x4.hpp>
#include <physis.hpp>
#include <vulkan/vulkan.h>
#include "camera.h"
#include "device.h"
#include "drawobject.h"
class ImGuiPass;
struct ImGuiContext;
class BaseRenderer;
/// Render 3D scenes made up of FFXIV game objects
class RenderManager
{
public:
RenderManager(GameData *data);
bool initSwapchain(VkSurfaceKHR surface, int width, int height);
void resize(VkSurfaceKHR surface, int width, int height);
void destroySwapchain();
DrawObject addDrawObject(const physis_MDL &model, int lod);
void reloadDrawObject(DrawObject &model, uint32_t lod);
RenderTexture addTexture(uint32_t width, uint32_t height, const uint8_t *data, uint32_t data_size);
void render(const std::vector<DrawObject> &models);
VkRenderPass presentationRenderPass() const;
Camera camera;
ImGuiContext *ctx = nullptr;
Device &device();
private:
void updateCamera(Camera &camera);
void initBlitPipeline();
std::array<VkCommandBuffer, 3> m_commandBuffers;
VkRenderPass m_renderPass = VK_NULL_HANDLE;
VkPipeline m_pipeline = VK_NULL_HANDLE;
VkPipelineLayout m_pipelineLayout = VK_NULL_HANDLE;
VkDescriptorSetLayout m_setLayout = VK_NULL_HANDLE;
VkSampler m_sampler = VK_NULL_HANDLE;
VkDescriptorSet m_descriptorSet = VK_NULL_HANDLE;
std::vector<VkFramebuffer> m_framebuffers;
ImGuiPass *m_imGuiPass = nullptr;
Device *m_device = nullptr;
BaseRenderer *m_renderer = nullptr;
GameData *m_data = nullptr;
};

View file

@ -1,185 +0,0 @@
// SPDX-FileCopyrightText: 2024 Joshua Goins <josh@redstrate.com>
// SPDX-License-Identifier: GPL-3.0-or-later
#pragma once
#include <QDebug>
#include <string_view>
#include <glm/glm.hpp>
#include <physis.hpp>
#include <spirv.hpp>
#include <spirv_cross.hpp>
#include <spirv_glsl.hpp>
#include <vulkan/vulkan.h>
class Renderer;
struct RenderModel;
class RenderSystem
{
public:
RenderSystem(Renderer &renderer, GameData *data);
void testInit(::RenderModel *m);
void render(uint32_t imageIndex, VkCommandBuffer commandBuffer);
void setSize(uint32_t width, uint32_t height);
private:
void beginPass(uint32_t imageIndex, VkCommandBuffer commandBuffer, std::string_view passName);
void endPass(VkCommandBuffer commandBuffer, std::string_view passName);
void bindPipeline(VkCommandBuffer commandBuffer, std::string_view passName, physis_Shader &vertexShader, physis_Shader &pixelShader);
VkShaderModule convertShaderModule(const physis_Shader &shader, spv::ExecutionModel executionModel);
spirv_cross::CompilerGLSL getShaderModuleResources(const physis_Shader &shader);
void createImageResources();
physis_SHPK directionalLightningShpk;
physis_SHPK createViewPositionShpk;
struct RenderModel {
physis_SHPK shpk;
::RenderModel *internal_model = nullptr;
};
std::vector<RenderModel> m_renderModels;
struct RequestedBinding {
VkDescriptorType type;
VkShaderStageFlags stageFlags;
bool used = false;
};
struct RequestedSet {
bool used = true;
VkDescriptorSetLayout layout = VK_NULL_HANDLE;
std::vector<RequestedBinding> bindings;
};
struct CachedPipeline {
VkPipeline pipeline = VK_NULL_HANDLE;
VkPipelineLayout pipelineLayout = VK_NULL_HANDLE;
std::vector<VkDescriptorSetLayout> setLayouts;
std::map<uint64_t, VkDescriptorSet> cachedDescriptors;
std::vector<RequestedSet> requestedSets;
physis_Shader vertexShader, pixelShader;
};
// combined vertex + pixel code length
std::unordered_map<uint32_t, CachedPipeline> m_cachedPipelines;
Renderer &m_renderer;
GameData *m_data = nullptr;
VkExtent2D m_extent = {640, 480};
VkDescriptorSet createDescriptorFor(const CachedPipeline &cachedPipeline, int i);
struct UniformBuffer {
VkBuffer buffer;
VkDeviceMemory memory;
size_t size;
};
UniformBuffer createUniformBuffer(size_t size);
void copyDataToUniform(UniformBuffer &uniformBuffer, void *data, size_t size);
// Structure definitions from https://github.com/Shaderlayan/Ouroboros
struct CameraParameter {
glm::mat3x4 m_ViewMatrix; // TODO: does it need alignment?
glm::mat3x4 m_InverseViewMatrix;
glm::mat4 m_ViewProjectionMatrix;
glm::mat4 m_InverseViewProjectionMatrix;
glm::mat4 m_InverseProjectionMatrix; // used for view position recalc
glm::mat4 m_ProjectionMatrix; // FIXME: ourburos is wrong, this is actually viewProjection
glm::mat4 m_MainViewToProjectionMatrix;
glm::vec3 m_EyePosition;
glm::vec3 m_LookAtVector;
};
UniformBuffer g_CameraParameter;
struct JointMatrixArray {
glm::mat3x4 g_JointMatrixArray[64];
};
UniformBuffer g_JointMatrixArray;
struct CameraLight {
glm::vec4 m_DiffuseSpecular;
glm::vec4 m_Rim;
};
struct InstanceParameterStruct {
glm::vec4 m_MulColor;
glm::vec4 m_EnvParameter;
CameraLight m_CameraLight;
glm::vec4 m_Wetness;
};
struct InstanceParameter {
InstanceParameterStruct g_InstanceParameter;
};
UniformBuffer g_InstanceParameter;
struct ModelParameterStruct {
glm::vec4 m_Params;
};
struct ModelParameter {
ModelParameterStruct g_ModelParameter;
};
UniformBuffer g_ModelParameter;
struct MaterialParameter {
glm::vec3 g_DiffuseColor; // TODO: align to vec4
float g_AlphaThreshold;
};
UniformBuffer g_MaterialParameter;
struct CommonParameter {
glm::vec4 m_RenderTarget;
glm::vec4 m_Viewport;
glm::vec4 m_Misc;
glm::vec4 m_Misc2;
};
UniformBuffer g_CommonParameter;
struct LightParam {
glm::vec4 m_Position;
glm::vec4 m_Direction;
glm::vec4 m_DiffuseColor;
glm::vec4 m_SpecularColor;
glm::vec4 m_Attenuation;
/*glm::vec4 m_ClipMin;
glm::vec3 m_ClipMax;
glm::vec3 m_FadeScale;
glm::vec4 m_ShadowTexMask;
glm::vec4 m_PlaneRayDirection;
glm::mat3x4 m_PlaneInversMatrix;
glm::mat3x4 m_WorldViewInversMatrix;
glm::mat4 m_LightMapMatrix;
glm::mat4 m_WorldViewProjectionMatrix;*/
};
UniformBuffer g_LightParam;
VkBuffer m_planeVertexBuffer;
VkDeviceMemory m_planeVertexMemory;
struct VulkanImage {
VkImage image;
VkImageView imageView;
VkDeviceMemory imageMemory;
};
VulkanImage createImage(int width, int height, VkFormat format, VkImageUsageFlags usage);
VulkanImage normalGBuffer;
VulkanImage viewPositionBuffer;
};

View file

@ -0,0 +1,74 @@
// SPDX-FileCopyrightText: 2024 Joshua Goins <josh@redstrate.com>
// SPDX-License-Identifier: GPL-3.0-or-later
#pragma once
// Structure definitions from https://github.com/Shaderlayan/Ouroboros
struct CameraParameter {
glm::mat3x4 m_ViewMatrix; // TODO: does it need alignment?
glm::mat3x4 m_InverseViewMatrix;
glm::mat4 m_ViewProjectionMatrix;
glm::mat4 m_InverseViewProjectionMatrix;
glm::mat4 m_InverseProjectionMatrix; // used for view position recalc
glm::mat4 m_ProjectionMatrix; // FIXME: ourburos is wrong, this is actually viewProjection
glm::mat4 m_MainViewToProjectionMatrix;
glm::vec3 m_EyePosition;
glm::vec3 m_LookAtVector;
};
struct JointMatrixArray {
glm::mat3x4 g_JointMatrixArray[64];
};
struct CameraLight {
glm::vec4 m_DiffuseSpecular;
glm::vec4 m_Rim;
};
struct InstanceParameterStruct {
glm::vec4 m_MulColor;
glm::vec4 m_EnvParameter;
CameraLight m_CameraLight;
glm::vec4 m_Wetness;
};
struct InstanceParameter {
InstanceParameterStruct g_InstanceParameter;
};
struct ModelParameterStruct {
glm::vec4 m_Params;
};
struct ModelParameter {
ModelParameterStruct g_ModelParameter;
};
struct MaterialParameter {
glm::vec3 g_DiffuseColor; // TODO: align to vec4
float g_AlphaThreshold;
};
struct CommonParameter {
glm::vec4 m_RenderTarget;
glm::vec4 m_Viewport;
glm::vec4 m_Misc;
glm::vec4 m_Misc2;
};
struct LightParam {
glm::vec4 m_Position;
glm::vec4 m_Direction;
glm::vec4 m_DiffuseColor;
glm::vec4 m_SpecularColor;
glm::vec4 m_Attenuation;
/*glm::vec4 m_ClipMin;
glm::vec3 m_ClipMax;
glm::vec3 m_FadeScale;
glm::vec4 m_ShadowTexMask;
glm::vec4 m_PlaneRayDirection;
glm::mat3x4 m_PlaneInversMatrix;
glm::mat3x4 m_WorldViewInversMatrix;
glm::mat4 m_LightMapMatrix;
glm::mat4 m_WorldViewProjectionMatrix;*/
};

View file

@ -0,0 +1,70 @@
// SPDX-FileCopyrightText: 2024 Joshua Goins <josh@redstrate.com>
// SPDX-License-Identifier: GPL-3.0-or-later
#pragma once
#include <QDebug>
#include <string_view>
#include <glm/glm.hpp>
#include <physis.hpp>
#include <spirv.hpp>
#include <spirv_cross.hpp>
#include <spirv_glsl.hpp>
#include <vulkan/vulkan.h>
#include "baserenderer.h"
#include "texture.h"
class Renderer;
struct RenderModel;
class Device;
struct DrawObject;
struct RenderMaterial;
/// Performs rendering with a basic set of shaders. Can be run without real game data.
class SimpleRenderer : public BaseRenderer
{
public:
explicit SimpleRenderer(Device &device);
void resize() override;
void render(VkCommandBuffer commandBuffer, uint32_t currentFrame, Camera &camera, const std::vector<DrawObject> &models) override;
void addDrawObject(const DrawObject &drawObject) override;
Texture &getCompositeTexture() override;
private:
void initRenderPass();
void initPipeline();
void initDescriptors();
void initTextures(int width, int height);
VkDescriptorSet createDescriptorFor(const DrawObject &model, const RenderMaterial &material);
uint64_t hash(const DrawObject &model, const RenderMaterial &material);
Texture m_dummyTex;
VkSampler m_sampler = VK_NULL_HANDLE;
VkPipeline m_pipeline = VK_NULL_HANDLE;
VkPipeline m_skinnedPipeline = VK_NULL_HANDLE;
VkPipeline m_pipelineWireframe = VK_NULL_HANDLE;
VkPipeline m_skinnedPipelineWireframe = VK_NULL_HANDLE;
VkPipelineLayout m_pipelineLayout = VK_NULL_HANDLE;
bool m_wireframe = false;
VkFramebuffer m_framebuffer;
VkRenderPass m_renderPass = VK_NULL_HANDLE;
VkDescriptorSetLayout m_setLayout = VK_NULL_HANDLE;
std::map<uint64_t, VkDescriptorSet> cachedDescriptors;
Texture m_depthTexture;
Texture m_compositeTexture;
Device &m_device;
};

View file

@ -0,0 +1,28 @@
#pragma once
#include <array>
#include <vector>
#include <vulkan/vulkan.h>
class Device;
class SwapChain
{
public:
SwapChain(Device &device, VkSurfaceKHR surface, int width, int height);
void resize(VkSurfaceKHR surface, int width, int height);
VkSwapchainKHR swapchain = VK_NULL_HANDLE;
VkExtent2D extent;
std::vector<VkImage> swapchainImages;
std::vector<VkImageView> swapchainViews;
std::array<VkFence, 3> inFlightFences;
std::array<VkSemaphore, 3> imageAvailableSemaphores, renderFinishedSemaphores;
uint32_t currentFrame = 0;
VkFormat surfaceFormat;
private:
Device &m_device;
};

View file

@ -0,0 +1,14 @@
// SPDX-FileCopyrightText: 2023 Joshua Goins <josh@redstrate.com>
// SPDX-License-Identifier: GPL-3.0-or-later
#pragma once
#include <vulkan/vulkan.h>
class Texture
{
public:
VkImage image;
VkImageView imageView;
VkDeviceMemory imageMemory;
};

View file

@ -0,0 +1,14 @@
// SPDX-FileCopyrightText: 2024 Joshua Goins <josh@redstrate.com>
// SPDX-License-Identifier: CC0-1.0
#version 450
layout(location = 0) in vec2 inUV;
layout(location = 0) out vec4 outColor;
layout(binding = 0) uniform sampler2D blitTexture;
void main() {
outColor = texture(blitTexture, inUV);
}

Binary file not shown.

View file

@ -0,0 +1,11 @@
// SPDX-FileCopyrightText: 2023 Joshua Goins <josh@redstrate.com>
// SPDX-License-Identifier: CC0-1.0
#version 460 core
layout (location = 0) out vec2 outUV;
void main() {
outUV = vec2((gl_VertexIndex << 1) & 2, gl_VertexIndex & 2);
gl_Position = vec4(outUV * 2.0f + -1.0f, 0.0f, 1.0f);
}

Binary file not shown.

View file

@ -7,4 +7,6 @@ glslc skinned.vert -o skinned.vert.spv &&
glslc mesh.frag -o mesh.frag.spv &&
glslc imgui.vert -o imgui.vert.spv &&
glslc imgui.frag -o imgui.frag.spv &&
glslc dummy.frag -o dummy.frag.spv
glslc dummy.frag -o dummy.frag.spv &&
glslc blit.vert -o blit.vert.spv &&
glslc blit.frag -o blit.frag.spv

311
renderer/src/device.cpp Normal file
View file

@ -0,0 +1,311 @@
// SPDX-FileCopyrightText: 2024 Joshua Goins <josh@redstrate.com>
// SPDX-License-Identifier: GPL-3.0-or-later
#include "device.h"
#include <QFile>
Buffer Device::createBuffer(const size_t size, const VkBufferUsageFlags usageFlags)
{
vkDeviceWaitIdle(device);
// create buffer
VkBufferCreateInfo bufferInfo = {};
bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
bufferInfo.size = size;
bufferInfo.usage = usageFlags;
bufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
VkBuffer handle;
vkCreateBuffer(device, &bufferInfo, nullptr, &handle);
// allocate memory
VkMemoryRequirements memRequirements;
vkGetBufferMemoryRequirements(device, handle, &memRequirements);
VkMemoryAllocateInfo allocInfo = {};
allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
allocInfo.allocationSize = memRequirements.size;
allocInfo.memoryTypeIndex = findMemoryType(memRequirements.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
VkDeviceMemory memory;
vkAllocateMemory(device, &allocInfo, nullptr, &memory);
vkBindBufferMemory(device, handle, memory, 0);
return {handle, memory, size};
}
void Device::copyToBuffer(Buffer &buffer, void *data, const size_t size)
{
void *mapped_data;
vkMapMemory(device, buffer.memory, 0, size, 0, &mapped_data);
memcpy(mapped_data, data, size);
vkUnmapMemory(device, buffer.memory);
}
uint32_t Device::findMemoryType(const uint32_t typeFilter, const VkMemoryPropertyFlags properties)
{
VkPhysicalDeviceMemoryProperties memProperties;
vkGetPhysicalDeviceMemoryProperties(physicalDevice, &memProperties);
for (uint32_t i = 0; i < memProperties.memoryTypeCount; i++) {
if ((typeFilter & (1 << i)) && (memProperties.memoryTypes[i].propertyFlags & properties) == properties) {
return i;
}
}
return -1;
}
VkShaderModule Device::createShaderModule(const uint32_t *code, const int length)
{
VkShaderModuleCreateInfo createInfo = {};
createInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
createInfo.codeSize = length;
createInfo.pCode = reinterpret_cast<const uint32_t *>(code);
VkShaderModule shaderModule;
vkCreateShaderModule(device, &createInfo, nullptr, &shaderModule);
return shaderModule;
}
VkShaderModule Device::loadShaderFromDisk(const std::string_view path)
{
QFile file((QLatin1String(path)));
file.open(QFile::ReadOnly);
if (!file.isOpen()) {
qFatal("Failed to open shader file: %s", path.data());
}
auto contents = file.readAll();
return createShaderModule(reinterpret_cast<const uint32_t *>(contents.data()), contents.size());
}
Texture Device::createTexture(const int width, const int height, const VkFormat format, const VkImageUsageFlags usage)
{
VkImage image;
VkImageView imageView;
VkDeviceMemory imageMemory;
VkImageCreateInfo imageCreateInfo = {};
imageCreateInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
imageCreateInfo.imageType = VK_IMAGE_TYPE_2D;
imageCreateInfo.extent.width = width;
imageCreateInfo.extent.height = height;
imageCreateInfo.extent.depth = 1;
imageCreateInfo.mipLevels = 1;
imageCreateInfo.arrayLayers = 1;
imageCreateInfo.format = format;
imageCreateInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
imageCreateInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
imageCreateInfo.usage = usage;
imageCreateInfo.samples = VK_SAMPLE_COUNT_1_BIT;
imageCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
vkCreateImage(device, &imageCreateInfo, nullptr, &image);
VkMemoryRequirements memRequirements;
vkGetImageMemoryRequirements(device, image, &memRequirements);
VkMemoryAllocateInfo allocateInfo = {};
allocateInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
allocateInfo.allocationSize = memRequirements.size;
allocateInfo.memoryTypeIndex = findMemoryType(memRequirements.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
vkAllocateMemory(device, &allocateInfo, nullptr, &imageMemory);
vkBindImageMemory(device, image, imageMemory, 0);
VkImageViewCreateInfo viewCreateInfo = {};
viewCreateInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
viewCreateInfo.image = image;
viewCreateInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
viewCreateInfo.format = format;
viewCreateInfo.subresourceRange.aspectMask =
usage == VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT ? VK_IMAGE_ASPECT_DEPTH_BIT : VK_IMAGE_ASPECT_COLOR_BIT; // TODO: hardcoded
viewCreateInfo.subresourceRange.levelCount = 1;
viewCreateInfo.subresourceRange.layerCount = 1;
vkCreateImageView(device, &viewCreateInfo, nullptr, &imageView);
return {image, imageView, imageMemory};
}
Texture Device::createDummyTexture()
{
auto texture = createTexture(1, 1, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT);
// copy image data
VkBuffer stagingBuffer;
VkDeviceMemory stagingBufferMemory;
VkBufferCreateInfo bufferInfo = {};
bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
bufferInfo.size = 4;
bufferInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
bufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
vkCreateBuffer(device, &bufferInfo, nullptr, &stagingBuffer);
// allocate staging memory
VkMemoryRequirements memRequirements;
vkGetBufferMemoryRequirements(device, stagingBuffer, &memRequirements);
VkMemoryAllocateInfo allocInfo = {};
allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
allocInfo.allocationSize = memRequirements.size;
allocInfo.memoryTypeIndex = findMemoryType(memRequirements.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
vkAllocateMemory(device, &allocInfo, nullptr, &stagingBufferMemory);
vkBindBufferMemory(device, stagingBuffer, stagingBufferMemory, 0);
uint8_t dummydata[4] = {255, 255, 255, 255};
// copy to staging buffer
void *mapped_data;
vkMapMemory(device, stagingBufferMemory, 0, 4 * sizeof(uint8_t), 0, &mapped_data);
memcpy(mapped_data, dummydata, 4 * sizeof(uint8_t));
vkUnmapMemory(device, stagingBufferMemory);
// copy staging buffer to image
VkCommandBuffer commandBuffer = beginSingleTimeCommands();
VkImageSubresourceRange range = {};
range.baseMipLevel = 0;
range.levelCount = 1;
range.baseArrayLayer = 0;
range.layerCount = 1;
inlineTransitionImageLayout(commandBuffer,
texture.image,
VK_FORMAT_R8G8B8A8_UNORM,
VK_IMAGE_ASPECT_COLOR_BIT,
range,
VK_IMAGE_LAYOUT_UNDEFINED,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
VkBufferImageCopy region = {};
region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
region.imageSubresource.mipLevel = 0;
region.imageSubresource.baseArrayLayer = 0;
region.imageSubresource.layerCount = 1;
region.imageExtent = {(uint32_t)1, (uint32_t)1, 1};
vkCmdCopyBufferToImage(commandBuffer, stagingBuffer, texture.image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &region);
inlineTransitionImageLayout(commandBuffer,
texture.image,
VK_FORMAT_R8G8B8A8_UNORM,
VK_IMAGE_ASPECT_COLOR_BIT,
range,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
endSingleTimeCommands(commandBuffer);
return texture;
}
Buffer Device::createDummyBuffer()
{
auto buffer = createBuffer(655360, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT);
// TODO: fill with data?
return buffer;
}
VkCommandBuffer Device::beginSingleTimeCommands()
{
VkCommandBufferAllocateInfo allocInfo = {};
allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
allocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
allocInfo.commandPool = commandPool;
allocInfo.commandBufferCount = 1;
VkCommandBuffer commandBuffer;
vkAllocateCommandBuffers(device, &allocInfo, &commandBuffer);
VkCommandBufferBeginInfo beginInfo = {};
beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
vkBeginCommandBuffer(commandBuffer, &beginInfo);
return commandBuffer;
}
void Device::endSingleTimeCommands(VkCommandBuffer commandBuffer)
{
vkEndCommandBuffer(commandBuffer);
VkSubmitInfo submitInfo = {};
submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
submitInfo.commandBufferCount = 1;
submitInfo.pCommandBuffers = &commandBuffer;
vkQueueSubmit(graphicsQueue, 1, &submitInfo, VK_NULL_HANDLE);
vkQueueWaitIdle(graphicsQueue);
vkFreeCommandBuffers(device, commandPool, 1, &commandBuffer);
}
void Device::inlineTransitionImageLayout(VkCommandBuffer commandBuffer,
VkImage image,
VkFormat format,
VkImageAspectFlags aspect,
VkImageSubresourceRange range,
VkImageLayout oldLayout,
VkImageLayout newLayout,
VkPipelineStageFlags src_stage_mask,
VkPipelineStageFlags dst_stage_mask)
{
Q_UNUSED(format)
VkImageMemoryBarrier barrier = {};
barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
barrier.oldLayout = oldLayout;
barrier.newLayout = newLayout;
barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
barrier.image = image;
barrier.subresourceRange = range;
barrier.subresourceRange.aspectMask = aspect;
switch (oldLayout) {
case VK_IMAGE_LAYOUT_UNDEFINED:
barrier.srcAccessMask = 0;
break;
case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL:
barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
break;
case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL:
barrier.srcAccessMask = VK_ACCESS_SHADER_READ_BIT;
break;
case VK_IMAGE_LAYOUT_GENERAL:
barrier.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT;
break;
default:
break;
}
switch (newLayout) {
case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL:
barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
break;
case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL:
barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
break;
case VK_IMAGE_LAYOUT_GENERAL:
barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
break;
default:
break;
}
vkCmdPipelineBarrier(commandBuffer, src_stage_mask, dst_stage_mask, 0, 0, nullptr, 0, nullptr, 1, &barrier);
}

View file

@ -1,20 +1,21 @@
// SPDX-FileCopyrightText: 2024 Joshua Goins <josh@redstrate.com>
// SPDX-License-Identifier: GPL-3.0-or-later
#include "rendersystem.h"
#include "gamerenderer.h"
#include <array>
#include <QDebug>
#include <glm/ext/matrix_clip_space.hpp>
#include <physis.hpp>
#include "dxbc_module.h"
#include "dxbc_reader.h"
#include "renderer.hpp"
#include <spirv_glsl.hpp>
#include <glm/ext/matrix_clip_space.hpp>
#include "camera.h"
#include "dxbc_module.h"
#include "dxbc_reader.h"
#include "rendermanager.h"
#include "swapchain.h"
// TODO: maybe need UV?
// note: SQEX passes the vertice positions as UV coordinates (yes, -1 to 1.) the shaders then transform them back with the g_CommonParameter.m_RenderTarget vec4
@ -53,79 +54,64 @@ const std::array<std::string, 14> passes = {
const int INVALID_PASS = 255;
RenderSystem::RenderSystem(Renderer &renderer, GameData *data)
: m_renderer(renderer)
GameRenderer::GameRenderer(Device &device, GameData *data)
: m_device(device)
, m_data(data)
{
m_dummyTex = m_device.createDummyTexture();
m_dummyBuffer = m_device.createDummyBuffer();
size_t vertexSize = planeVertices.size() * sizeof(glm::vec4);
auto [vertexBuffer, vertexMemory] = m_renderer.createBuffer(vertexSize, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT);
m_planeVertexBuffer = vertexBuffer;
m_planeVertexMemory = vertexMemory;
// copy vertex data
{
void *mapped_data = nullptr;
vkMapMemory(m_renderer.device, vertexMemory, 0, vertexSize, 0, &mapped_data);
memcpy(mapped_data, planeVertices.data(), vertexSize);
VkMappedMemoryRange range = {};
range.sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE;
range.memory = vertexMemory;
range.size = vertexSize;
vkFlushMappedMemoryRanges(m_renderer.device, 1, &range);
vkUnmapMemory(m_renderer.device, vertexMemory);
}
m_planeVertexBuffer = m_device.createBuffer(vertexSize, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT);
m_device.copyToBuffer(m_planeVertexBuffer, (void *)planeVertices.data(), vertexSize);
directionalLightningShpk = physis_parse_shpk(physis_gamedata_extract_file(m_data, "shader/sm5/shpk/directionallighting.shpk"));
createViewPositionShpk = physis_parse_shpk(physis_gamedata_extract_file(m_data, "shader/sm5/shpk/createviewposition.shpk"));
// camera data
{
g_CameraParameter = createUniformBuffer(sizeof(CameraParameter));
g_CameraParameter = m_device.createBuffer(sizeof(CameraParameter), VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT);
}
// joint matrix data
{
g_JointMatrixArray = createUniformBuffer(sizeof(JointMatrixArray));
g_JointMatrixArray = m_device.createBuffer(sizeof(JointMatrixArray), VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT);
JointMatrixArray jointMatrixArray{};
for (int i = 0; i < 64; i++) {
jointMatrixArray.g_JointMatrixArray[i] = glm::mat3x4(1.0f);
}
copyDataToUniform(g_JointMatrixArray, &jointMatrixArray, sizeof(JointMatrixArray));
m_device.copyToBuffer(g_JointMatrixArray, &jointMatrixArray, sizeof(JointMatrixArray));
}
// instance data
{
g_InstanceParameter = createUniformBuffer(sizeof(InstanceParameter));
g_InstanceParameter = m_device.createBuffer(sizeof(InstanceParameter), VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT);
InstanceParameter instanceParameter{};
copyDataToUniform(g_InstanceParameter, &instanceParameter, sizeof(InstanceParameter));
m_device.copyToBuffer(g_InstanceParameter, &instanceParameter, sizeof(InstanceParameter));
}
// model data
{
g_ModelParameter = createUniformBuffer(sizeof(ModelParameter));
g_ModelParameter = m_device.createBuffer(sizeof(ModelParameter), VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT);
ModelParameter modelParameter{};
copyDataToUniform(g_ModelParameter, &modelParameter, sizeof(ModelParameter));
m_device.copyToBuffer(g_ModelParameter, &modelParameter, sizeof(ModelParameter));
}
// material data
{
g_MaterialParameter = createUniformBuffer(sizeof(MaterialParameter));
g_MaterialParameter = m_device.createBuffer(sizeof(MaterialParameter), VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT);
MaterialParameter materialParameter{};
materialParameter.g_AlphaThreshold = 0.0f;
materialParameter.g_DiffuseColor = glm::vec3(1.0f);
copyDataToUniform(g_MaterialParameter, &materialParameter, sizeof(MaterialParameter));
m_device.copyToBuffer(g_MaterialParameter, &materialParameter, sizeof(MaterialParameter));
}
// light data
{
g_LightParam = createUniformBuffer(sizeof(LightParam));
g_LightParam = m_device.createBuffer(sizeof(LightParam), VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT);
LightParam lightParam{};
lightParam.m_Position = glm::vec4(-5);
@ -136,35 +122,45 @@ RenderSystem::RenderSystem(Renderer &renderer, GameData *data)
/*lightParam.m_ClipMin = glm::vec4(0.0f);
lightParam.m_ClipMax = glm::vec4(5.0f);*/
copyDataToUniform(g_LightParam, &lightParam, sizeof(LightParam));
m_device.copyToBuffer(g_LightParam, &lightParam, sizeof(LightParam));
}
// common data
{
g_CommonParameter = createUniformBuffer(sizeof(CommonParameter));
g_CommonParameter = m_device.createBuffer(sizeof(CommonParameter), VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT);
}
VkSamplerCreateInfo samplerInfo = {};
samplerInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO;
samplerInfo.magFilter = VK_FILTER_LINEAR;
samplerInfo.minFilter = VK_FILTER_LINEAR;
samplerInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT;
samplerInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT;
samplerInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT;
samplerInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR;
samplerInfo.maxLod = 1.0f;
vkCreateSampler(m_device.device, &samplerInfo, nullptr, &m_sampler);
createImageResources();
}
void RenderSystem::testInit(::RenderModel *m)
void GameRenderer::addDrawObject(const DrawObject &drawObject)
{
RenderModel model{.shpk = physis_parse_shpk(physis_gamedata_extract_file(m_data, "shader/sm5/shpk/character.shpk")),
.internal_model = new ::RenderModel(*m)};
.internal_model = new DrawObject(drawObject)};
m_renderModels.push_back(model);
}
void RenderSystem::render(uint32_t imageIndex, VkCommandBuffer commandBuffer)
void GameRenderer::render(VkCommandBuffer commandBuffer, uint32_t imageIndex, Camera &camera, const std::vector<DrawObject> &)
{
// TODO: this shouldn't be here
CameraParameter cameraParameter{};
glm::mat4 projectionMatrix = glm::perspective(glm::radians(45.0f), (float)m_extent.width / (float)m_extent.height, 0.1f, 1000.0f);
glm::mat4 viewMatrix = m_renderer.view;
glm::mat4 viewProjectionMatrix = projectionMatrix * viewMatrix;
const glm::mat4 viewProjectionMatrix = camera.perspective * camera.view;
cameraParameter.m_ViewMatrix = glm::transpose(viewMatrix);
cameraParameter.m_InverseViewMatrix = glm::transpose(glm::inverse(viewMatrix));
cameraParameter.m_ViewMatrix = glm::transpose(camera.view);
cameraParameter.m_InverseViewMatrix = glm::transpose(glm::inverse(camera.view));
cameraParameter.m_ViewProjectionMatrix = glm::transpose(viewProjectionMatrix);
cameraParameter.m_InverseViewProjectionMatrix = glm::transpose(glm::inverse(viewProjectionMatrix));
@ -172,11 +168,11 @@ void RenderSystem::render(uint32_t imageIndex, VkCommandBuffer commandBuffer)
cameraParameter.m_InverseProjectionMatrix = glm::transpose(glm::inverse(viewProjectionMatrix));
cameraParameter.m_ProjectionMatrix = glm::transpose(viewProjectionMatrix);
cameraParameter.m_MainViewToProjectionMatrix = glm::transpose(glm::inverse(projectionMatrix));
cameraParameter.m_MainViewToProjectionMatrix = glm::transpose(glm::inverse(camera.perspective));
cameraParameter.m_EyePosition = glm::vec3(5.0f); // placeholder
cameraParameter.m_LookAtVector = glm::vec3(0.0f); // placeholder
copyDataToUniform(g_CameraParameter, &cameraParameter, sizeof(CameraParameter));
m_device.copyToBuffer(g_CameraParameter, &cameraParameter, sizeof(CameraParameter));
int i = 0;
for (const auto pass : passes) {
@ -235,8 +231,8 @@ void RenderSystem::render(uint32_t imageIndex, VkCommandBuffer commandBuffer)
for (const auto &part : model.internal_model->parts) {
VkDeviceSize offsets[] = {0};
vkCmdBindVertexBuffers(commandBuffer, 0, 1, &part.vertexBuffer, offsets);
vkCmdBindIndexBuffer(commandBuffer, part.indexBuffer, 0, VK_INDEX_TYPE_UINT16);
vkCmdBindVertexBuffers(commandBuffer, 0, 1, &part.vertexBuffer.buffer, offsets);
vkCmdBindIndexBuffer(commandBuffer, part.indexBuffer.buffer, 0, VK_INDEX_TYPE_UINT16);
vkCmdDrawIndexed(commandBuffer, part.numIndices, 1, 0, 0, 0);
}
@ -284,7 +280,7 @@ void RenderSystem::render(uint32_t imageIndex, VkCommandBuffer commandBuffer)
bindPipeline(commandBuffer, "PASS_LIGHTING_OPAQUE_VIEWPOSITION", vertexShader, pixelShader);
VkDeviceSize offsets[] = {0};
vkCmdBindVertexBuffers(commandBuffer, 0, 1, &m_planeVertexBuffer, offsets);
vkCmdBindVertexBuffers(commandBuffer, 0, 1, &m_planeVertexBuffer.buffer, offsets);
vkCmdDraw(commandBuffer, 6, 1, 0, 0);
}
@ -335,7 +331,7 @@ void RenderSystem::render(uint32_t imageIndex, VkCommandBuffer commandBuffer)
bindPipeline(commandBuffer, pass, vertexShader, pixelShader);
VkDeviceSize offsets[] = {0};
vkCmdBindVertexBuffers(commandBuffer, 0, 1, &m_planeVertexBuffer, offsets);
vkCmdBindVertexBuffers(commandBuffer, 0, 1, &m_planeVertexBuffer.buffer, offsets);
vkCmdDraw(commandBuffer, 6, 1, 0, 0);
}
@ -347,9 +343,8 @@ void RenderSystem::render(uint32_t imageIndex, VkCommandBuffer commandBuffer)
}
}
void RenderSystem::setSize(uint32_t width, uint32_t height)
void GameRenderer::resize()
{
m_extent = {width, height};
// TODO: this is because of our terrible resource handling. an image referenced in these may be gone due to resizing, for example
for (auto &[hash, cachedPipeline] : m_cachedPipelines) {
cachedPipeline.cachedDescriptors.clear();
@ -358,10 +353,10 @@ void RenderSystem::setSize(uint32_t width, uint32_t height)
createImageResources();
}
void RenderSystem::beginPass(uint32_t imageIndex, VkCommandBuffer commandBuffer, const std::string_view passName)
void GameRenderer::beginPass(uint32_t imageIndex, VkCommandBuffer commandBuffer, const std::string_view passName)
{
VkRenderingInfo renderingInfo{VK_STRUCTURE_TYPE_RENDERING_INFO};
renderingInfo.renderArea.extent = m_extent;
renderingInfo.renderArea.extent = m_device.swapChain->extent;
std::vector<VkRenderingAttachmentInfo> colorAttachments;
VkRenderingAttachmentInfo depthStencilAttachment{};
@ -370,7 +365,7 @@ void RenderSystem::beginPass(uint32_t imageIndex, VkCommandBuffer commandBuffer,
// normals, it seems like
{
VkRenderingAttachmentInfo attachmentInfo{VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO};
attachmentInfo.imageView = normalGBuffer.imageView;
attachmentInfo.imageView = m_normalGBuffer.imageView;
attachmentInfo.imageLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; // VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL
attachmentInfo.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
attachmentInfo.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
@ -408,7 +403,7 @@ void RenderSystem::beginPass(uint32_t imageIndex, VkCommandBuffer commandBuffer,
// depth
{
VkRenderingAttachmentInfo attachmentInfo{VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO};
attachmentInfo.imageView = m_renderer.depthView;
attachmentInfo.imageView = m_depthBuffer.imageView;
attachmentInfo.imageLayout = VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL;
attachmentInfo.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
attachmentInfo.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
@ -420,7 +415,7 @@ void RenderSystem::beginPass(uint32_t imageIndex, VkCommandBuffer commandBuffer,
// normals, it seems like
{
VkRenderingAttachmentInfo attachmentInfo{VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO};
attachmentInfo.imageView = m_renderer.swapchainViews[imageIndex];
attachmentInfo.imageView = m_compositeBuffer.imageView;
attachmentInfo.imageLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; // VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL
attachmentInfo.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
attachmentInfo.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
@ -447,7 +442,7 @@ void RenderSystem::beginPass(uint32_t imageIndex, VkCommandBuffer commandBuffer,
// TODO: Hack we should not be using a special pass for this, we should just design our API better
{
VkRenderingAttachmentInfo attachmentInfo{VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO};
attachmentInfo.imageView = viewPositionBuffer.imageView;
attachmentInfo.imageView = m_viewPositionBuffer.imageView;
attachmentInfo.imageLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; // VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL
attachmentInfo.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
attachmentInfo.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
@ -463,7 +458,7 @@ void RenderSystem::beginPass(uint32_t imageIndex, VkCommandBuffer commandBuffer,
// normals, it seems like
{
VkRenderingAttachmentInfo attachmentInfo{VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO};
attachmentInfo.imageView = m_renderer.swapchainViews[imageIndex];
attachmentInfo.imageView = m_compositeBuffer.imageView;
attachmentInfo.imageLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; // VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL
attachmentInfo.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
attachmentInfo.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
@ -499,12 +494,12 @@ void RenderSystem::beginPass(uint32_t imageIndex, VkCommandBuffer commandBuffer,
vkCmdBeginRendering(commandBuffer, &renderingInfo);
}
void RenderSystem::endPass(VkCommandBuffer commandBuffer, std::string_view passName)
void GameRenderer::endPass(VkCommandBuffer commandBuffer, std::string_view passName)
{
vkCmdEndRendering(commandBuffer);
}
void RenderSystem::bindPipeline(VkCommandBuffer commandBuffer, std::string_view passName, physis_Shader &vertexShader, physis_Shader &pixelShader)
void GameRenderer::bindPipeline(VkCommandBuffer commandBuffer, std::string_view passName, physis_Shader &vertexShader, physis_Shader &pixelShader)
{
const uint32_t hash = vertexShader.len + pixelShader.len + physis_shpk_crc(passName.data());
if (!m_cachedPipelines.contains(hash)) {
@ -607,7 +602,7 @@ void RenderSystem::bindPipeline(VkCommandBuffer commandBuffer, std::string_view
layoutInfo.bindingCount = bindings.size();
layoutInfo.pBindings = bindings.data();
vkCreateDescriptorSetLayout(m_renderer.device, &layoutInfo, nullptr, &set.layout);
vkCreateDescriptorSetLayout(m_device.device, &layoutInfo, nullptr, &set.layout);
}
}
@ -748,7 +743,7 @@ void RenderSystem::bindPipeline(VkCommandBuffer commandBuffer, std::string_view
pipelineLayoutInfo.pSetLayouts = setLayouts.data();
VkPipelineLayout pipelineLayout = VK_NULL_HANDLE;
vkCreatePipelineLayout(m_renderer.device, &pipelineLayoutInfo, nullptr, &pipelineLayout);
vkCreatePipelineLayout(m_device.device, &pipelineLayoutInfo, nullptr, &pipelineLayout);
VkPipelineDepthStencilStateCreateInfo depthStencil = {};
depthStencil.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO;
@ -782,7 +777,7 @@ void RenderSystem::bindPipeline(VkCommandBuffer commandBuffer, std::string_view
// createInfo.renderPass = m_renderer.renderPass;
VkPipeline pipeline = VK_NULL_HANDLE;
vkCreateGraphicsPipelines(m_renderer.device, VK_NULL_HANDLE, 1, &createInfo, nullptr, &pipeline);
vkCreateGraphicsPipelines(m_device.device, VK_NULL_HANDLE, 1, &createInfo, nullptr, &pipeline);
qInfo() << "Created" << pipeline << "for hash" << hash;
m_cachedPipelines[hash] = CachedPipeline{.pipeline = pipeline,
@ -813,18 +808,18 @@ void RenderSystem::bindPipeline(VkCommandBuffer commandBuffer, std::string_view
}
VkViewport viewport = {};
viewport.width = m_extent.width;
viewport.height = m_extent.height;
viewport.width = m_device.swapChain->extent.width;
viewport.height = m_device.swapChain->extent.height;
viewport.maxDepth = 1.0f;
VkRect2D scissor = {};
scissor.extent = m_extent;
scissor.extent = m_device.swapChain->extent;
vkCmdSetViewport(commandBuffer, 0, 1, &viewport);
vkCmdSetScissor(commandBuffer, 0, 1, &scissor);
}
VkShaderModule RenderSystem::convertShaderModule(const physis_Shader &shader, spv::ExecutionModel executionModel)
VkShaderModule GameRenderer::convertShaderModule(const physis_Shader &shader, spv::ExecutionModel executionModel)
{
dxvk::DxbcReader reader(reinterpret_cast<const char *>(shader.bytecode), shader.len);
@ -839,7 +834,7 @@ VkShaderModule RenderSystem::convertShaderModule(const physis_Shader &shader, sp
createInfo.pCode = reinterpret_cast<const uint32_t *>(result.code.data());
VkShaderModule shaderModule;
vkCreateShaderModule(m_renderer.device, &createInfo, nullptr, &shaderModule);
vkCreateShaderModule(m_device.device, &createInfo, nullptr, &shaderModule);
// TODO: for debug only
spirv_cross::CompilerGLSL glsl(result.code.data(), result.code.dwords());
@ -879,7 +874,7 @@ VkShaderModule RenderSystem::convertShaderModule(const physis_Shader &shader, sp
return shaderModule;
}
spirv_cross::CompilerGLSL RenderSystem::getShaderModuleResources(const physis_Shader &shader)
spirv_cross::CompilerGLSL GameRenderer::getShaderModuleResources(const physis_Shader &shader)
{
dxvk::DxbcReader reader(reinterpret_cast<const char *>(shader.bytecode), shader.len);
@ -893,17 +888,17 @@ spirv_cross::CompilerGLSL RenderSystem::getShaderModuleResources(const physis_Sh
return spirv_cross::CompilerGLSL(result.code.data(), result.code.dwords());
}
VkDescriptorSet RenderSystem::createDescriptorFor(const CachedPipeline &pipeline, int i)
VkDescriptorSet GameRenderer::createDescriptorFor(const CachedPipeline &pipeline, int i)
{
VkDescriptorSet set;
VkDescriptorSetAllocateInfo allocateInfo = {};
allocateInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
allocateInfo.descriptorPool = m_renderer.descriptorPool;
allocateInfo.descriptorPool = m_device.descriptorPool;
allocateInfo.descriptorSetCount = 1;
allocateInfo.pSetLayouts = &pipeline.setLayouts[i];
vkAllocateDescriptorSets(m_renderer.device, &allocateInfo, &set);
vkAllocateDescriptorSets(m_device.device, &allocateInfo, &set);
if (set == VK_NULL_HANDLE) {
// qFatal("Failed to create descriptor set!");
return VK_NULL_HANDLE;
@ -947,18 +942,18 @@ VkDescriptorSet RenderSystem::createDescriptorFor(const CachedPipeline &pipeline
auto name = pipeline.pixelShader.resource_parameters[p].name;
qInfo() << "Requesting image" << name << "at" << j;
if (strcmp(name, "g_SamplerGBuffer") == 0) {
info->imageView = normalGBuffer.imageView;
info->imageView = m_normalGBuffer.imageView;
} else if (strcmp(name, "g_SamplerViewPosition") == 0) {
info->imageView = viewPositionBuffer.imageView;
info->imageView = m_viewPositionBuffer.imageView;
} else if (strcmp(name, "g_SamplerDepth") == 0) {
info->imageView = m_renderer.depthView;
info->imageView = m_depthBuffer.imageView;
} else {
info->imageView = m_renderer.dummyView;
info->imageView = m_dummyTex.imageView;
}
p++;
} else {
info->imageView = m_renderer.dummyView;
info->imageView = m_dummyTex.imageView;
}
info->imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
@ -967,13 +962,13 @@ VkDescriptorSet RenderSystem::createDescriptorFor(const CachedPipeline &pipeline
auto info = &imageInfo.emplace_back();
descriptorWrite.pImageInfo = info;
info->sampler = m_renderer.dummySampler;
info->sampler = m_sampler;
} break;
case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER: {
auto info = &bufferInfo.emplace_back();
descriptorWrite.pBufferInfo = info;
auto useUniformBuffer = [&info](UniformBuffer &buffer) {
auto useUniformBuffer = [&info](Buffer &buffer) {
info->buffer = buffer.buffer;
info->range = buffer.size;
};
@ -997,7 +992,7 @@ VkDescriptorSet RenderSystem::createDescriptorFor(const CachedPipeline &pipeline
useUniformBuffer(g_CommonParameter);
} else {
qInfo() << "Unknown resource:" << name;
info->buffer = m_renderer.dummyBuffer;
info->buffer = m_dummyBuffer.buffer;
info->range = 655360;
}
};
@ -1014,7 +1009,7 @@ VkDescriptorSet RenderSystem::createDescriptorFor(const CachedPipeline &pipeline
z++;
} else {
// placeholder buffer so it at least doesn't crash
info->buffer = m_renderer.dummyBuffer;
info->buffer = m_dummyBuffer.buffer;
info->range = 655360;
}
} break;
@ -1023,111 +1018,40 @@ VkDescriptorSet RenderSystem::createDescriptorFor(const CachedPipeline &pipeline
j++;
}
vkUpdateDescriptorSets(m_renderer.device, writes.size(), writes.data(), 0, nullptr);
vkUpdateDescriptorSets(m_device.device, writes.size(), writes.data(), 0, nullptr);
return set;
}
RenderSystem::UniformBuffer RenderSystem::createUniformBuffer(size_t size)
void GameRenderer::createImageResources()
{
UniformBuffer uniformBuffer{};
uniformBuffer.size = size;
VkBufferCreateInfo bufferInfo = {};
bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
bufferInfo.size = size;
bufferInfo.usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT;
bufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
vkCreateBuffer(m_renderer.device, &bufferInfo, nullptr, &uniformBuffer.buffer);
// allocate staging memory
VkMemoryRequirements memRequirements;
vkGetBufferMemoryRequirements(m_renderer.device, uniformBuffer.buffer, &memRequirements);
VkMemoryAllocateInfo allocInfo = {};
allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
allocInfo.allocationSize = memRequirements.size;
allocInfo.memoryTypeIndex =
m_renderer.findMemoryType(memRequirements.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
vkAllocateMemory(m_renderer.device, &allocInfo, nullptr, &uniformBuffer.memory);
vkBindBufferMemory(m_renderer.device, uniformBuffer.buffer, uniformBuffer.memory, 0);
return uniformBuffer;
}
void RenderSystem::copyDataToUniform(RenderSystem::UniformBuffer &uniformBuffer, void *data, size_t size)
{
// copy to staging buffer
void *mapped_data;
vkMapMemory(m_renderer.device, uniformBuffer.memory, 0, size, 0, &mapped_data);
memcpy(mapped_data, data, size);
vkUnmapMemory(m_renderer.device, uniformBuffer.memory);
}
RenderSystem::VulkanImage RenderSystem::createImage(int width, int height, VkFormat format, VkImageUsageFlags usage)
{
VkImage image;
VkImageView imageView;
VkDeviceMemory imageMemory;
VkImageCreateInfo imageCreateInfo = {};
imageCreateInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
imageCreateInfo.imageType = VK_IMAGE_TYPE_2D;
imageCreateInfo.extent.width = width;
imageCreateInfo.extent.height = height;
imageCreateInfo.extent.depth = 1;
imageCreateInfo.mipLevels = 1;
imageCreateInfo.arrayLayers = 1;
imageCreateInfo.format = format;
imageCreateInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
imageCreateInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
imageCreateInfo.usage = usage;
imageCreateInfo.samples = VK_SAMPLE_COUNT_1_BIT;
imageCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
vkCreateImage(m_renderer.device, &imageCreateInfo, nullptr, &image);
VkMemoryRequirements memRequirements;
vkGetImageMemoryRequirements(m_renderer.device, image, &memRequirements);
VkMemoryAllocateInfo allocateInfo = {};
allocateInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
allocateInfo.allocationSize = memRequirements.size;
allocateInfo.memoryTypeIndex = m_renderer.findMemoryType(memRequirements.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
vkAllocateMemory(m_renderer.device, &allocateInfo, nullptr, &imageMemory);
vkBindImageMemory(m_renderer.device, image, imageMemory, 0);
VkImageViewCreateInfo viewCreateInfo = {};
viewCreateInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
viewCreateInfo.image = image;
viewCreateInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
viewCreateInfo.format = format;
viewCreateInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; // TODO: hardcoded
viewCreateInfo.subresourceRange.levelCount = 1;
viewCreateInfo.subresourceRange.layerCount = 1;
vkCreateImageView(m_renderer.device, &viewCreateInfo, nullptr, &imageView);
return {image, imageView, imageMemory};
}
void RenderSystem::createImageResources()
{
normalGBuffer = createImage(m_extent.width, m_extent.height, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT);
viewPositionBuffer = createImage(m_extent.width, m_extent.height, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT);
m_normalGBuffer = m_device.createTexture(m_device.swapChain->extent.width,
m_device.swapChain->extent.height,
VK_FORMAT_R8G8B8A8_UNORM,
VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT);
m_viewPositionBuffer = m_device.createTexture(m_device.swapChain->extent.width,
m_device.swapChain->extent.height,
VK_FORMAT_R8G8B8A8_UNORM,
VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT);
m_compositeBuffer = m_device.createTexture(m_device.swapChain->extent.width,
m_device.swapChain->extent.height,
VK_FORMAT_R8G8B8A8_UNORM,
VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT);
m_depthBuffer = m_device.createTexture(m_device.swapChain->extent.width,
m_device.swapChain->extent.height,
VK_FORMAT_D32_SFLOAT,
VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT);
CommonParameter commonParam{};
/*commonParam.m_RenderTarget = {1640.0f / 2.0f,
480.0f / 2.0f,
640.0f / 2.0,
480.0f / 2.0}; // used to convert screen-space coordinates back into 0.0-1.0
*/
commonParam.m_RenderTarget = {1.0f / m_extent.width, 1.0f / m_extent.height, 0.0f, 0.0f}; // used to convert screen-space coordinates back into 0.0-1.0
commonParam.m_RenderTarget = {1.0f / m_device.swapChain->extent.width,
1.0f / m_device.swapChain->extent.height,
0.0f,
0.0f}; // used to convert screen-space coordinates back into 0.0-1.0
copyDataToUniform(g_CommonParameter, &commonParam, sizeof(CommonParameter));
m_device.copyToBuffer(g_CommonParameter, &commonParam, sizeof(CommonParameter));
}
Texture &GameRenderer::getCompositeTexture()
{
return m_compositeBuffer;
}

View file

@ -8,9 +8,9 @@
#include <glm/glm.hpp>
#include <imgui.h>
#include "renderer.hpp"
#include "rendermanager.h"
ImGuiPass::ImGuiPass(Renderer &renderer)
ImGuiPass::ImGuiPass(RenderManager &renderer)
: renderer_(renderer)
{
createDescriptorSetLayout();
@ -20,15 +20,15 @@ ImGuiPass::ImGuiPass(Renderer &renderer)
ImGuiPass::~ImGuiPass()
{
vkDestroySampler(renderer_.device, fontSampler_, nullptr);
vkDestroyImageView(renderer_.device, fontImageView_, nullptr);
vkFreeMemory(renderer_.device, fontMemory_, nullptr);
vkDestroyImage(renderer_.device, fontImage_, nullptr);
vkDestroySampler(renderer_.device().device, fontSampler_, nullptr);
vkDestroyImageView(renderer_.device().device, fontImageView_, nullptr);
vkFreeMemory(renderer_.device().device, fontMemory_, nullptr);
vkDestroyImage(renderer_.device().device, fontImage_, nullptr);
vkDestroyPipeline(renderer_.device, pipeline_, nullptr);
vkDestroyPipelineLayout(renderer_.device, pipelineLayout_, nullptr);
vkDestroyPipeline(renderer_.device().device, pipeline_, nullptr);
vkDestroyPipelineLayout(renderer_.device().device, pipelineLayout_, nullptr);
vkDestroyDescriptorSetLayout(renderer_.device, setLayout_, nullptr);
vkDestroyDescriptorSetLayout(renderer_.device().device, setLayout_, nullptr);
}
void ImGuiPass::render(VkCommandBuffer commandBuffer)
@ -55,8 +55,8 @@ void ImGuiPass::render(VkCommandBuffer commandBuffer)
ImDrawVert *vertexData = nullptr;
ImDrawIdx *indexData = nullptr;
vkMapMemory(renderer_.device, vertexMemory, 0, vertexSize, 0, reinterpret_cast<void **>(&vertexData));
vkMapMemory(renderer_.device, indexMemory, 0, indexSize, 0, reinterpret_cast<void **>(&indexData));
vkMapMemory(renderer_.device().device, vertexMemory, 0, vertexSize, 0, reinterpret_cast<void **>(&vertexData));
vkMapMemory(renderer_.device().device, indexMemory, 0, indexSize, 0, reinterpret_cast<void **>(&indexData));
for (int i = 0; i < drawData->CmdListsCount; i++) {
const ImDrawList *cmd_list = drawData->CmdLists[i];
@ -68,8 +68,8 @@ void ImGuiPass::render(VkCommandBuffer commandBuffer)
indexData += cmd_list->IdxBuffer.Size;
}
vkUnmapMemory(renderer_.device, vertexMemory);
vkUnmapMemory(renderer_.device, indexMemory);
vkUnmapMemory(renderer_.device().device, vertexMemory);
vkUnmapMemory(renderer_.device().device, indexMemory);
vkCmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_);
@ -107,12 +107,12 @@ void ImGuiPass::render(VkCommandBuffer commandBuffer)
} else {
VkDescriptorSetAllocateInfo allocInfo = {};
allocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
allocInfo.descriptorPool = renderer_.descriptorPool;
allocInfo.descriptorPool = renderer_.device().descriptorPool;
allocInfo.descriptorSetCount = 1;
allocInfo.pSetLayouts = &setLayout_;
VkDescriptorSet set = nullptr;
vkAllocateDescriptorSets(renderer_.device, &allocInfo, &set);
vkAllocateDescriptorSets(renderer_.device().device, &allocInfo, &set);
VkDescriptorImageInfo imageInfo = {};
imageInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
@ -126,7 +126,7 @@ void ImGuiPass::render(VkCommandBuffer commandBuffer)
descriptorWrite.dstSet = set;
descriptorWrite.pImageInfo = &imageInfo;
vkUpdateDescriptorSets(renderer_.device, 1, &descriptorWrite, 0, nullptr);
vkUpdateDescriptorSets(renderer_.device().device, 1, &descriptorWrite, 0, nullptr);
vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout_, 0, 1, &set, 0, nullptr);
@ -166,13 +166,13 @@ void ImGuiPass::createDescriptorSetLayout()
createInfo.bindingCount = 1;
createInfo.pBindings = &samplerBinding;
vkCreateDescriptorSetLayout(renderer_.device, &createInfo, nullptr, &setLayout_);
vkCreateDescriptorSetLayout(renderer_.device().device, &createInfo, nullptr, &setLayout_);
}
void ImGuiPass::createPipeline()
{
VkShaderModule vertShaderModule = renderer_.loadShaderFromDisk(":/shaders/imgui.vert.spv");
VkShaderModule fragShaderModule = renderer_.loadShaderFromDisk(":/shaders/imgui.frag.spv");
VkShaderModule vertShaderModule = renderer_.device().loadShaderFromDisk(":/shaders/imgui.vert.spv");
VkShaderModule fragShaderModule = renderer_.device().loadShaderFromDisk(":/shaders/imgui.frag.spv");
VkPipelineShaderStageCreateInfo vertShaderStageInfo = {};
vertShaderStageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
@ -268,7 +268,7 @@ void ImGuiPass::createPipeline()
pipelineLayoutInfo.pushConstantRangeCount = 1;
pipelineLayoutInfo.pPushConstantRanges = &pushConstant;
vkCreatePipelineLayout(renderer_.device, &pipelineLayoutInfo, nullptr, &pipelineLayout_);
vkCreatePipelineLayout(renderer_.device().device, &pipelineLayoutInfo, nullptr, &pipelineLayout_);
VkPipelineDepthStencilStateCreateInfo depthStencilStateCreateInfo = {};
depthStencilStateCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO;
@ -286,12 +286,12 @@ void ImGuiPass::createPipeline()
pipelineInfo.pDynamicState = &dynamicState;
pipelineInfo.layout = pipelineLayout_;
pipelineInfo.pDepthStencilState = &depthStencilStateCreateInfo;
pipelineInfo.renderPass = renderer_.renderPass;
pipelineInfo.renderPass = renderer_.presentationRenderPass();
vkCreateGraphicsPipelines(renderer_.device, nullptr, 1, &pipelineInfo, nullptr, &pipeline_);
vkCreateGraphicsPipelines(renderer_.device().device, nullptr, 1, &pipelineInfo, nullptr, &pipeline_);
vkDestroyShaderModule(renderer_.device, fragShaderModule, nullptr);
vkDestroyShaderModule(renderer_.device, vertShaderModule, nullptr);
vkDestroyShaderModule(renderer_.device().device, fragShaderModule, nullptr);
vkDestroyShaderModule(renderer_.device().device, vertShaderModule, nullptr);
}
void ImGuiPass::createFontImage()
@ -312,10 +312,10 @@ void ImGuiPass::createFontImage()
void ImGuiPass::createBuffer(VkBuffer &buffer, VkDeviceMemory &memory, VkDeviceSize size, VkBufferUsageFlagBits bufferUsage)
{
if (buffer != nullptr)
vkDestroyBuffer(renderer_.device, buffer, nullptr);
vkDestroyBuffer(renderer_.device().device, buffer, nullptr);
if (memory != nullptr)
vkFreeMemory(renderer_.device, memory, nullptr);
vkFreeMemory(renderer_.device().device, memory, nullptr);
VkBufferCreateInfo bufferInfo = {};
bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
@ -323,17 +323,17 @@ void ImGuiPass::createBuffer(VkBuffer &buffer, VkDeviceMemory &memory, VkDeviceS
bufferInfo.usage = bufferUsage;
bufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
vkCreateBuffer(renderer_.device, &bufferInfo, nullptr, &buffer);
vkCreateBuffer(renderer_.device().device, &bufferInfo, nullptr, &buffer);
VkMemoryRequirements memRequirements = {};
vkGetBufferMemoryRequirements(renderer_.device, buffer, &memRequirements);
vkGetBufferMemoryRequirements(renderer_.device().device, buffer, &memRequirements);
VkMemoryAllocateInfo allocInfo = {};
allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
allocInfo.allocationSize = memRequirements.size;
allocInfo.memoryTypeIndex =
renderer_.findMemoryType(memRequirements.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
renderer_.device().findMemoryType(memRequirements.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
vkAllocateMemory(renderer_.device, &allocInfo, nullptr, &memory);
vkBindBufferMemory(renderer_.device, buffer, memory, 0);
vkAllocateMemory(renderer_.device().device, &allocInfo, nullptr, &memory);
vkBindBufferMemory(renderer_.device().device, buffer, memory, 0);
}

View file

@ -6,12 +6,12 @@
#include <map>
#include <vulkan/vulkan.h>
class Renderer;
class RenderManager;
class ImGuiPass
{
public:
explicit ImGuiPass(Renderer &renderer);
explicit ImGuiPass(RenderManager &renderer);
~ImGuiPass();
void render(VkCommandBuffer commandBuffer);
@ -38,5 +38,5 @@ private:
std::map<VkImageView, VkDescriptorSet> descriptorSets_ = {};
Renderer &renderer_;
RenderManager &renderer_;
};

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,784 @@
// SPDX-FileCopyrightText: 2023 Joshua Goins <josh@redstrate.com>
// SPDX-License-Identifier: GPL-3.0-or-later
#include "rendermanager.h"
#include <QDebug>
#include <QFile>
#include <array>
#include <fstream>
#include <glm/gtc/matrix_transform.hpp>
#include <valarray>
#include <vector>
#include <vulkan/vulkan.h>
#include "gamerenderer.h"
#include "imgui.h"
#include "imguipass.h"
#include "simplerenderer.h"
#include "swapchain.h"
VkResult CreateDebugUtilsMessengerEXT(VkInstance instance,
const VkDebugUtilsMessengerCreateInfoEXT *pCreateInfo,
const VkAllocationCallbacks *pAllocator,
VkDebugUtilsMessengerEXT *pCallback)
{
// Note: It seems that static_cast<...> doesn't work. Use the C-style forced
// cast.
auto func = (PFN_vkCreateDebugUtilsMessengerEXT)vkGetInstanceProcAddr(instance, "vkCreateDebugUtilsMessengerEXT");
if (func != nullptr) {
return func(instance, pCreateInfo, pAllocator, pCallback);
} else {
return VK_ERROR_EXTENSION_NOT_PRESENT;
}
}
VKAPI_ATTR VkBool32 VKAPI_CALL DebugCallback(VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity,
VkDebugUtilsMessageTypeFlagsEXT messageType,
const VkDebugUtilsMessengerCallbackDataEXT *pCallbackData,
void *pUserData)
{
Q_UNUSED(messageSeverity)
Q_UNUSED(messageType)
Q_UNUSED(pUserData)
qInfo() << pCallbackData->pMessage;
return VK_FALSE;
}
RenderManager::RenderManager(GameData *data)
: m_data(data)
{
Q_INIT_RESOURCE(shaders);
m_device = new Device();
ctx = ImGui::CreateContext();
ImGui::SetCurrentContext(ctx);
ImGui::GetIO().IniFilename = "";
ImGui::StyleColorsDark();
std::vector<const char *> instanceExtensions = {"VK_EXT_debug_utils"};
uint32_t extensionCount = 0;
vkEnumerateInstanceExtensionProperties(nullptr, &extensionCount, nullptr);
std::vector<VkExtensionProperties> extensions(extensionCount);
vkEnumerateInstanceExtensionProperties(nullptr, &extensionCount, extensions.data());
for (auto &extension : extensions) {
if (strstr(extension.extensionName, "surface") != nullptr) {
instanceExtensions.push_back(extension.extensionName);
}
if (strstr(extension.extensionName, "VK_KHR_get_physical_device_properties2") != nullptr) {
instanceExtensions.push_back(extension.extensionName);
}
}
VkDebugUtilsMessengerCreateInfoEXT debugCreateInfo = {};
debugCreateInfo.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT;
debugCreateInfo.messageSeverity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT;
debugCreateInfo.messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT;
debugCreateInfo.pfnUserCallback = DebugCallback;
VkApplicationInfo applicationInfo = {VK_STRUCTURE_TYPE_APPLICATION_INFO};
applicationInfo.apiVersion = VK_API_VERSION_1_3;
VkInstanceCreateInfo createInfo = {};
createInfo.pNext = &debugCreateInfo;
createInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
createInfo.ppEnabledExtensionNames = instanceExtensions.data();
createInfo.enabledExtensionCount = instanceExtensions.size();
createInfo.pApplicationInfo = &applicationInfo;
vkCreateInstance(&createInfo, nullptr, &m_device->instance);
VkDebugUtilsMessengerEXT callback;
CreateDebugUtilsMessengerEXT(m_device->instance, &debugCreateInfo, nullptr, &callback);
// pick physical device
uint32_t deviceCount = 0;
vkEnumeratePhysicalDevices(m_device->instance, &deviceCount, nullptr);
std::vector<VkPhysicalDevice> devices(deviceCount);
vkEnumeratePhysicalDevices(m_device->instance, &deviceCount, devices.data());
int preferredDevice = 0;
int deviceIndex = 0;
for (auto device : devices) {
VkPhysicalDeviceProperties deviceProperties;
vkGetPhysicalDeviceProperties(device, &deviceProperties);
if (deviceProperties.deviceType == VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU) {
preferredDevice = deviceIndex;
}
deviceIndex++;
}
m_device->physicalDevice = devices[preferredDevice];
extensionCount = 0;
vkEnumerateDeviceExtensionProperties(m_device->physicalDevice, nullptr, &extensionCount, nullptr);
std::vector<VkExtensionProperties> extensionProperties(extensionCount);
vkEnumerateDeviceExtensionProperties(m_device->physicalDevice, nullptr, &extensionCount, extensionProperties.data());
// we want to choose the portability subset on platforms that
// support it, this is a requirement of the portability spec
std::vector<const char *> deviceExtensions = {"VK_KHR_swapchain"};
for (auto extension : extensionProperties) {
if (!strcmp(extension.extensionName, "VK_KHR_portability_subset"))
deviceExtensions.push_back("VK_KHR_portability_subset");
}
uint32_t graphicsFamilyIndex = 0, presentFamilyIndex = 0;
// create logical device
uint32_t queueFamilyCount = 0;
vkGetPhysicalDeviceQueueFamilyProperties(m_device->physicalDevice, &queueFamilyCount, nullptr);
std::vector<VkQueueFamilyProperties> queueFamilies(queueFamilyCount);
vkGetPhysicalDeviceQueueFamilyProperties(m_device->physicalDevice, &queueFamilyCount, queueFamilies.data());
int i = 0;
for (const auto &queueFamily : queueFamilies) {
if (queueFamily.queueCount > 0 && queueFamily.queueFlags & VK_QUEUE_GRAPHICS_BIT) {
graphicsFamilyIndex = i;
}
i++;
}
std::vector<VkDeviceQueueCreateInfo> queueCreateInfos;
if (graphicsFamilyIndex == presentFamilyIndex) {
VkDeviceQueueCreateInfo queueCreateInfo = {};
queueCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
queueCreateInfo.queueFamilyIndex = graphicsFamilyIndex;
queueCreateInfo.queueCount = 1;
float queuePriority = 1.0f;
queueCreateInfo.pQueuePriorities = &queuePriority;
queueCreateInfos.push_back(queueCreateInfo);
} else {
// graphics
{
VkDeviceQueueCreateInfo queueCreateInfo = {};
queueCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
queueCreateInfo.queueFamilyIndex = graphicsFamilyIndex;
queueCreateInfo.queueCount = 1;
float queuePriority = 1.0f;
queueCreateInfo.pQueuePriorities = &queuePriority;
queueCreateInfos.push_back(queueCreateInfo);
}
// present
{
VkDeviceQueueCreateInfo queueCreateInfo = {};
queueCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
queueCreateInfo.queueFamilyIndex = presentFamilyIndex;
queueCreateInfo.queueCount = 1;
float queuePriority = 1.0f;
queueCreateInfo.pQueuePriorities = &queuePriority;
queueCreateInfos.push_back(queueCreateInfo);
}
}
VkPhysicalDeviceFeatures enabledFeatures{};
enabledFeatures.shaderClipDistance = VK_TRUE;
enabledFeatures.shaderCullDistance = VK_TRUE;
VkPhysicalDeviceVulkan11Features enabled11Features{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_FEATURES};
enabled11Features.shaderDrawParameters = VK_TRUE;
VkPhysicalDeviceVulkan12Features enabled12Features{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES};
enabled12Features.vulkanMemoryModel = VK_TRUE;
enabled12Features.pNext = &enabled11Features;
VkPhysicalDeviceVulkan13Features enabled13Features{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_3_FEATURES};
enabled13Features.shaderDemoteToHelperInvocation = VK_TRUE;
enabled13Features.dynamicRendering = VK_TRUE;
enabled13Features.pNext = &enabled12Features;
VkDeviceCreateInfo deviceCeateInfo = {};
deviceCeateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
deviceCeateInfo.pQueueCreateInfos = queueCreateInfos.data();
deviceCeateInfo.queueCreateInfoCount = static_cast<uint32_t>(queueCreateInfos.size());
deviceCeateInfo.ppEnabledExtensionNames = deviceExtensions.data();
deviceCeateInfo.enabledExtensionCount = static_cast<uint32_t>(deviceExtensions.size());
deviceCeateInfo.pEnabledFeatures = &enabledFeatures;
deviceCeateInfo.pNext = &enabled13Features;
vkCreateDevice(m_device->physicalDevice, &deviceCeateInfo, nullptr, &m_device->device);
// get queues
vkGetDeviceQueue(m_device->device, graphicsFamilyIndex, 0, &m_device->graphicsQueue);
vkGetDeviceQueue(m_device->device, presentFamilyIndex, 0, &m_device->presentQueue);
// command pool
VkCommandPoolCreateInfo poolInfo = {};
poolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
poolInfo.queueFamilyIndex = graphicsFamilyIndex;
poolInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
vkCreateCommandPool(m_device->device, &poolInfo, nullptr, &m_device->commandPool);
VkDescriptorPoolSize poolSize = {};
poolSize.type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
poolSize.descriptorCount = 150;
VkDescriptorPoolSize poolSize2 = {};
poolSize2.type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
poolSize2.descriptorCount = 150;
const std::array poolSizes = {poolSize, poolSize2};
VkDescriptorPoolCreateInfo poolCreateInfo = {};
poolCreateInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
poolCreateInfo.poolSizeCount = poolSizes.size();
poolCreateInfo.pPoolSizes = poolSizes.data();
poolCreateInfo.maxSets = 150;
vkCreateDescriptorPool(m_device->device, &poolCreateInfo, nullptr, &m_device->descriptorPool);
qInfo() << "Initialized renderer!";
}
bool RenderManager::initSwapchain(VkSurfaceKHR surface, int width, int height)
{
if (m_device->swapChain == nullptr) {
m_device->swapChain = new SwapChain(*m_device, surface, width, height);
} else {
m_device->swapChain->resize(surface, width, height);
}
// allocate command buffers
for (int i = 0; i < 3; i++) {
VkCommandBufferAllocateInfo allocInfo = {};
allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
allocInfo.commandPool = m_device->commandPool;
allocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
allocInfo.commandBufferCount = 1;
vkAllocateCommandBuffers(m_device->device, &allocInfo, &m_commandBuffers[i]);
}
VkAttachmentDescription colorAttachment = {};
colorAttachment.format = m_device->swapChain->surfaceFormat;
colorAttachment.samples = VK_SAMPLE_COUNT_1_BIT;
colorAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
colorAttachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
colorAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
colorAttachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
colorAttachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
colorAttachment.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
VkAttachmentReference colorAttachmentRef = {};
colorAttachmentRef.attachment = 0;
colorAttachmentRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
VkSubpassDependency dependency = {};
dependency.srcSubpass = VK_SUBPASS_EXTERNAL;
dependency.dstSubpass = 0;
dependency.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT;
dependency.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT;
dependency.srcAccessMask = 0;
dependency.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
dependency.dependencyFlags = 0;
VkSubpassDescription subpass = {};
subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
subpass.colorAttachmentCount = 1;
subpass.pColorAttachments = &colorAttachmentRef;
std::array<VkAttachmentDescription, 1> attachments = {colorAttachment};
VkRenderPassCreateInfo renderPassInfo = {};
renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
renderPassInfo.attachmentCount = attachments.size();
renderPassInfo.pAttachments = attachments.data();
renderPassInfo.subpassCount = 1;
renderPassInfo.pSubpasses = &subpass;
renderPassInfo.dependencyCount = 1;
renderPassInfo.pDependencies = &dependency;
vkCreateRenderPass(m_device->device, &renderPassInfo, nullptr, &m_renderPass);
ImGui::SetCurrentContext(ctx);
m_imGuiPass = new ImGuiPass(*this);
if (qgetenv("NOVUS_USE_NEW_RENDERER") == QByteArrayLiteral("1")) {
m_renderer = new GameRenderer(*m_device, m_data);
} else {
m_renderer = new SimpleRenderer(*m_device);
}
m_renderer->resize();
initBlitPipeline(); // this creates a desc set for the renderer's offscreen texture. need to make sure we regen it
m_framebuffers.resize(m_device->swapChain->swapchainImages.size());
for (int i = 0; i < m_device->swapChain->swapchainImages.size(); i++) {
VkFramebufferCreateInfo framebufferInfo = {};
framebufferInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
framebufferInfo.renderPass = m_renderPass;
framebufferInfo.attachmentCount = 1;
framebufferInfo.pAttachments = &m_device->swapChain->swapchainViews[i];
framebufferInfo.width = m_device->swapChain->extent.width;
framebufferInfo.height = m_device->swapChain->extent.height;
framebufferInfo.layers = 1;
vkCreateFramebuffer(m_device->device, &framebufferInfo, nullptr, &m_framebuffers[i]);
}
return true;
}
void RenderManager::resize(VkSurfaceKHR surface, int width, int height)
{
initSwapchain(surface, width, height);
}
void RenderManager::destroySwapchain()
{
// TODO: port to new swapchain aPI
/*if (swapchain != VK_NULL_HANDLE) {
vkDestroySwapchainKHR(device, swapchain, nullptr);
swapchain = VK_NULL_HANDLE;
}*/
}
void RenderManager::render(const std::vector<DrawObject> &models)
{
vkWaitForFences(m_device->device,
1,
&m_device->swapChain->inFlightFences[m_device->swapChain->currentFrame],
VK_TRUE,
std::numeric_limits<uint64_t>::max());
uint32_t imageIndex = 0;
VkResult result = vkAcquireNextImageKHR(m_device->device,
m_device->swapChain->swapchain,
std::numeric_limits<uint64_t>::max(),
m_device->swapChain->imageAvailableSemaphores[m_device->swapChain->currentFrame],
VK_NULL_HANDLE,
&imageIndex);
if (result == VK_ERROR_OUT_OF_DATE_KHR) {
return;
}
VkCommandBuffer commandBuffer = m_commandBuffers[m_device->swapChain->currentFrame];
VkCommandBufferBeginInfo beginInfo = {};
beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
beginInfo.flags = VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT;
vkBeginCommandBuffer(commandBuffer, &beginInfo);
updateCamera(camera);
m_renderer->render(commandBuffer, m_device->swapChain->currentFrame, camera, models);
VkRenderPassBeginInfo renderPassInfo = {};
renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
renderPassInfo.renderPass = m_renderPass;
renderPassInfo.framebuffer = m_framebuffers[imageIndex];
std::array<VkClearValue, 2> clearValues = {};
clearValues[0].color.float32[0] = 0.24;
clearValues[0].color.float32[1] = 0.24;
clearValues[0].color.float32[2] = 0.24;
clearValues[0].color.float32[3] = 1.0;
clearValues[1].depthStencil = {1.0f, 0};
renderPassInfo.clearValueCount = clearValues.size();
renderPassInfo.pClearValues = clearValues.data();
renderPassInfo.renderArea.extent = m_device->swapChain->extent;
vkCmdBeginRenderPass(commandBuffer, &renderPassInfo, VK_SUBPASS_CONTENTS_INLINE);
vkCmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipeline);
vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipelineLayout, 0, 1, &m_descriptorSet, 0, nullptr);
vkCmdDraw(commandBuffer, 4, 1, 0, 0);
// Render offscreen texture, and overlay imgui
if (m_imGuiPass != nullptr) {
ImGui::SetCurrentContext(ctx);
m_imGuiPass->render(commandBuffer);
}
vkCmdEndRenderPass(commandBuffer);
vkEndCommandBuffer(commandBuffer);
VkSubmitInfo submitInfo = {};
submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
VkSemaphore waitSemaphores[] = {m_device->swapChain->imageAvailableSemaphores[m_device->swapChain->currentFrame]};
VkPipelineStageFlags waitStages[] = {VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT};
submitInfo.waitSemaphoreCount = 1;
submitInfo.pWaitSemaphores = waitSemaphores;
submitInfo.pWaitDstStageMask = waitStages;
submitInfo.commandBufferCount = 1;
submitInfo.pCommandBuffers = &commandBuffer;
VkSemaphore signalSemaphores[] = {m_device->swapChain->renderFinishedSemaphores[m_device->swapChain->currentFrame]};
submitInfo.signalSemaphoreCount = 1;
submitInfo.pSignalSemaphores = signalSemaphores;
vkResetFences(m_device->device, 1, &m_device->swapChain->inFlightFences[m_device->swapChain->currentFrame]);
if (vkQueueSubmit(m_device->graphicsQueue, 1, &submitInfo, m_device->swapChain->inFlightFences[m_device->swapChain->currentFrame]) != VK_SUCCESS)
return;
// present
VkPresentInfoKHR presentInfo = {};
presentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
presentInfo.waitSemaphoreCount = 1;
presentInfo.pWaitSemaphores = signalSemaphores;
VkSwapchainKHR swapChains[] = {m_device->swapChain->swapchain};
presentInfo.swapchainCount = 1;
presentInfo.pSwapchains = swapChains;
presentInfo.pImageIndices = &imageIndex;
vkQueuePresentKHR(m_device->presentQueue, &presentInfo);
m_device->swapChain->currentFrame = (m_device->swapChain->currentFrame + 1) % 3;
}
VkRenderPass RenderManager::presentationRenderPass() const
{
return m_renderPass;
}
DrawObject RenderManager::addDrawObject(const physis_MDL &model, int lod)
{
DrawObject DrawObject;
DrawObject.model = model;
reloadDrawObject(DrawObject, lod);
m_renderer->addDrawObject(DrawObject);
return DrawObject;
}
void RenderManager::reloadDrawObject(DrawObject &DrawObject, uint32_t lod)
{
if (lod > DrawObject.model.num_lod)
return;
DrawObject.parts.clear();
for (uint32_t i = 0; i < DrawObject.model.lods[lod].num_parts; i++) {
RenderPart renderPart;
const physis_Part part = DrawObject.model.lods[lod].parts[i];
renderPart.materialIndex = part.material_index;
size_t vertexSize = part.num_vertices * sizeof(Vertex);
renderPart.vertexBuffer = m_device->createBuffer(vertexSize, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT);
m_device->copyToBuffer(renderPart.vertexBuffer, (void *)part.vertices, vertexSize);
size_t indexSize = part.num_indices * sizeof(uint16_t);
renderPart.indexBuffer = m_device->createBuffer(indexSize, VK_BUFFER_USAGE_INDEX_BUFFER_BIT);
m_device->copyToBuffer(renderPart.indexBuffer, (void *)part.indices, indexSize);
renderPart.numIndices = part.num_indices;
DrawObject.parts.push_back(renderPart);
}
const size_t bufferSize = sizeof(glm::mat4) * 128;
DrawObject.boneInfoBuffer = m_device->createBuffer(bufferSize, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT);
}
RenderTexture RenderManager::addTexture(const uint32_t width, const uint32_t height, const uint8_t *data, const uint32_t data_size)
{
RenderTexture newTexture = {};
VkImageCreateInfo imageInfo = {};
imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
imageInfo.imageType = VK_IMAGE_TYPE_2D;
imageInfo.extent.width = width;
imageInfo.extent.height = height;
imageInfo.extent.depth = 1;
imageInfo.mipLevels = 1;
imageInfo.arrayLayers = 1;
imageInfo.format = VK_FORMAT_R8G8B8A8_UNORM;
imageInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
imageInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
imageInfo.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT;
imageInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
imageInfo.samples = VK_SAMPLE_COUNT_1_BIT;
vkCreateImage(m_device->device, &imageInfo, nullptr, &newTexture.handle);
VkMemoryRequirements memRequirements;
vkGetImageMemoryRequirements(m_device->device, newTexture.handle, &memRequirements);
VkMemoryAllocateInfo allocInfo = {};
allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
allocInfo.allocationSize = memRequirements.size;
allocInfo.memoryTypeIndex = m_device->findMemoryType(memRequirements.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
vkAllocateMemory(m_device->device, &allocInfo, nullptr, &newTexture.memory);
vkBindImageMemory(m_device->device, newTexture.handle, newTexture.memory, 0);
// copy image data
VkBuffer stagingBuffer;
VkDeviceMemory stagingBufferMemory;
VkBufferCreateInfo bufferInfo = {};
bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
bufferInfo.size = data_size;
bufferInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
bufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
vkCreateBuffer(m_device->device, &bufferInfo, nullptr, &stagingBuffer);
// allocate staging memory
vkGetBufferMemoryRequirements(m_device->device, stagingBuffer, &memRequirements);
allocInfo = {};
allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
allocInfo.allocationSize = memRequirements.size;
allocInfo.memoryTypeIndex =
m_device->findMemoryType(memRequirements.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
vkAllocateMemory(m_device->device, &allocInfo, nullptr, &stagingBufferMemory);
vkBindBufferMemory(m_device->device, stagingBuffer, stagingBufferMemory, 0);
// copy to staging buffer
void *mapped_data;
vkMapMemory(m_device->device, stagingBufferMemory, 0, data_size, 0, &mapped_data);
memcpy(mapped_data, data, data_size);
vkUnmapMemory(m_device->device, stagingBufferMemory);
// copy staging buffer to image
VkCommandBuffer commandBuffer = m_device->beginSingleTimeCommands();
VkImageSubresourceRange range = {};
range.baseMipLevel = 0;
range.levelCount = 1;
range.baseArrayLayer = 0;
range.layerCount = 1;
m_device->inlineTransitionImageLayout(commandBuffer,
newTexture.handle,
imageInfo.format,
VK_IMAGE_ASPECT_COLOR_BIT,
range,
VK_IMAGE_LAYOUT_UNDEFINED,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
VkBufferImageCopy region = {};
region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
region.imageSubresource.mipLevel = 0;
region.imageSubresource.baseArrayLayer = 0;
region.imageSubresource.layerCount = 1;
region.imageExtent = {(uint32_t)width, (uint32_t)height, 1};
vkCmdCopyBufferToImage(commandBuffer, stagingBuffer, newTexture.handle, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &region);
m_device->inlineTransitionImageLayout(commandBuffer,
newTexture.handle,
imageInfo.format,
VK_IMAGE_ASPECT_COLOR_BIT,
range,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
m_device->endSingleTimeCommands(commandBuffer);
range = {};
range.levelCount = 1;
range.layerCount = 1;
range.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
VkImageViewCreateInfo viewInfo = {};
viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
viewInfo.image = newTexture.handle;
viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
viewInfo.format = imageInfo.format;
viewInfo.subresourceRange = range;
vkCreateImageView(m_device->device, &viewInfo, nullptr, &newTexture.view);
VkSamplerCreateInfo samplerInfo = {};
samplerInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO;
samplerInfo.magFilter = VK_FILTER_LINEAR;
samplerInfo.minFilter = VK_FILTER_LINEAR;
samplerInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT;
samplerInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT;
samplerInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT;
samplerInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR;
samplerInfo.maxLod = 1.0f;
vkCreateSampler(m_device->device, &samplerInfo, nullptr, &newTexture.sampler);
return newTexture;
}
Device &RenderManager::device()
{
return *m_device;
}
void RenderManager::updateCamera(Camera &camera)
{
camera.aspectRatio = static_cast<float>(m_device->swapChain->extent.width) / static_cast<float>(m_device->swapChain->extent.height);
camera.perspective = glm::perspective(glm::radians(camera.fieldOfView), camera.aspectRatio, camera.nearPlane, camera.farPlane);
}
void RenderManager::initBlitPipeline()
{
VkDescriptorSetLayoutBinding binding = {};
binding.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
binding.descriptorCount = 1;
binding.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;
binding.binding = 0;
VkDescriptorSetLayoutCreateInfo layoutInfo = {};
layoutInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
layoutInfo.bindingCount = 1;
layoutInfo.pBindings = &binding;
vkCreateDescriptorSetLayout(m_device->device, &layoutInfo, nullptr, &m_setLayout);
VkPipelineShaderStageCreateInfo vertexShaderStageInfo = {};
vertexShaderStageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
vertexShaderStageInfo.stage = VK_SHADER_STAGE_VERTEX_BIT;
vertexShaderStageInfo.module = m_device->loadShaderFromDisk(":/shaders/blit.vert.spv");
vertexShaderStageInfo.pName = "main";
VkPipelineShaderStageCreateInfo fragmentShaderStageInfo = {};
fragmentShaderStageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
fragmentShaderStageInfo.stage = VK_SHADER_STAGE_FRAGMENT_BIT;
fragmentShaderStageInfo.module = m_device->loadShaderFromDisk(":/shaders/blit.frag.spv");
fragmentShaderStageInfo.pName = "main";
std::array<VkPipelineShaderStageCreateInfo, 2> shaderStages = {vertexShaderStageInfo, fragmentShaderStageInfo};
VkPipelineVertexInputStateCreateInfo vertexInputState = {};
vertexInputState.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
VkPipelineInputAssemblyStateCreateInfo inputAssembly = {};
inputAssembly.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
inputAssembly.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
VkViewport viewport = {};
viewport.width = m_device->swapChain->extent.width;
viewport.height = m_device->swapChain->extent.height;
viewport.maxDepth = 1.0f;
VkRect2D scissor = {};
scissor.extent = m_device->swapChain->extent;
VkPipelineViewportStateCreateInfo viewportState = {};
viewportState.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
viewportState.viewportCount = 1;
viewportState.pViewports = &viewport;
viewportState.scissorCount = 1;
viewportState.pScissors = &scissor;
VkPipelineRasterizationStateCreateInfo rasterizer = {};
rasterizer.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
rasterizer.lineWidth = 1.0f;
rasterizer.cullMode = VK_CULL_MODE_BACK_BIT;
rasterizer.frontFace = VK_FRONT_FACE_CLOCKWISE;
VkPipelineMultisampleStateCreateInfo multisampling = {};
multisampling.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
multisampling.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
VkPipelineColorBlendAttachmentState colorBlendAttachment = {};
colorBlendAttachment.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
VkPipelineColorBlendStateCreateInfo colorBlending = {};
colorBlending.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
colorBlending.attachmentCount = 1;
colorBlending.pAttachments = &colorBlendAttachment;
VkPipelineDynamicStateCreateInfo dynamicState = {};
dynamicState.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO;
VkPipelineLayoutCreateInfo pipelineLayoutInfo{};
pipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
pipelineLayoutInfo.setLayoutCount = 1;
pipelineLayoutInfo.pSetLayouts = &m_setLayout;
vkCreatePipelineLayout(m_device->device, &pipelineLayoutInfo, nullptr, &m_pipelineLayout);
VkPipelineDepthStencilStateCreateInfo depthStencil = {};
depthStencil.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO;
depthStencil.depthTestEnable = VK_TRUE;
depthStencil.depthWriteEnable = VK_TRUE;
depthStencil.depthCompareOp = VK_COMPARE_OP_LESS;
depthStencil.maxDepthBounds = 1.0f;
VkGraphicsPipelineCreateInfo createInfo = {};
createInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
createInfo.stageCount = shaderStages.size();
createInfo.pStages = shaderStages.data();
createInfo.pVertexInputState = &vertexInputState;
createInfo.pInputAssemblyState = &inputAssembly;
createInfo.pViewportState = &viewportState;
createInfo.pRasterizationState = &rasterizer;
createInfo.pMultisampleState = &multisampling;
createInfo.pColorBlendState = &colorBlending;
createInfo.pDynamicState = &dynamicState;
createInfo.pDepthStencilState = &depthStencil;
createInfo.layout = m_pipelineLayout;
createInfo.renderPass = m_renderPass;
vkCreateGraphicsPipelines(m_device->device, VK_NULL_HANDLE, 1, &createInfo, nullptr, &m_pipeline);
VkSamplerCreateInfo samplerInfo = {};
samplerInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO;
samplerInfo.magFilter = VK_FILTER_LINEAR;
samplerInfo.minFilter = VK_FILTER_LINEAR;
samplerInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT;
samplerInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT;
samplerInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT;
samplerInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR;
samplerInfo.maxLod = 1.0f;
vkCreateSampler(m_device->device, &samplerInfo, nullptr, &m_sampler);
VkDescriptorSetAllocateInfo allocateInfo = {};
allocateInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
allocateInfo.descriptorPool = m_device->descriptorPool;
allocateInfo.descriptorSetCount = 1;
allocateInfo.pSetLayouts = &m_setLayout;
vkAllocateDescriptorSets(m_device->device, &allocateInfo, &m_descriptorSet);
VkDescriptorImageInfo multiImageInfo = {};
multiImageInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
multiImageInfo.imageView = m_renderer->getCompositeTexture().imageView;
multiImageInfo.sampler = m_sampler;
VkWriteDescriptorSet multiDescriptorWrite2 = {};
multiDescriptorWrite2.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
multiDescriptorWrite2.dstSet = m_descriptorSet;
multiDescriptorWrite2.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
multiDescriptorWrite2.descriptorCount = 1;
multiDescriptorWrite2.pImageInfo = &multiImageInfo;
multiDescriptorWrite2.dstBinding = 0;
vkUpdateDescriptorSets(m_device->device, 1, &multiDescriptorWrite2, 0, nullptr);
}

View file

@ -0,0 +1,573 @@
// SPDX-FileCopyrightText: 2024 Joshua Goins <josh@redstrate.com>
// SPDX-License-Identifier: GPL-3.0-or-later
#include "simplerenderer.h"
#include <glm/ext/matrix_transform.hpp>
#include "camera.h"
#include "device.h"
#include "drawobject.h"
#include "swapchain.h"
SimpleRenderer::SimpleRenderer(Device &device)
: m_device(device)
{
m_dummyTex = m_device.createDummyTexture();
VkSamplerCreateInfo samplerInfo = {};
samplerInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO;
samplerInfo.magFilter = VK_FILTER_LINEAR;
samplerInfo.minFilter = VK_FILTER_LINEAR;
samplerInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT;
samplerInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT;
samplerInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT;
samplerInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR;
samplerInfo.maxLod = 1.0f;
vkCreateSampler(m_device.device, &samplerInfo, nullptr, &m_sampler);
}
void SimpleRenderer::resize()
{
initRenderPass();
initDescriptors();
initPipeline();
initTextures(m_device.swapChain->extent.width, m_device.swapChain->extent.height);
std::array<VkImageView, 2> attachments = {m_compositeTexture.imageView, m_depthTexture.imageView};
VkFramebufferCreateInfo framebufferInfo = {};
framebufferInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
framebufferInfo.renderPass = m_renderPass;
framebufferInfo.attachmentCount = attachments.size();
framebufferInfo.pAttachments = attachments.data();
framebufferInfo.width = m_device.swapChain->extent.width;
framebufferInfo.height = m_device.swapChain->extent.height;
framebufferInfo.layers = 1;
vkCreateFramebuffer(m_device.device, &framebufferInfo, nullptr, &m_framebuffer);
}
void SimpleRenderer::render(VkCommandBuffer commandBuffer, uint32_t currentFrame, Camera &camera, const std::vector<DrawObject> &models)
{
VkRenderPassBeginInfo renderPassInfo = {};
renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
renderPassInfo.renderPass = m_renderPass;
renderPassInfo.framebuffer = m_framebuffer;
std::array<VkClearValue, 2> clearValues = {};
clearValues[0].color.float32[0] = 0.24;
clearValues[0].color.float32[1] = 0.24;
clearValues[0].color.float32[2] = 0.24;
clearValues[0].color.float32[3] = 1.0;
clearValues[1].depthStencil = {1.0f, 0};
renderPassInfo.clearValueCount = clearValues.size();
renderPassInfo.pClearValues = clearValues.data();
renderPassInfo.renderArea.extent = m_device.swapChain->extent;
vkCmdBeginRenderPass(commandBuffer, &renderPassInfo, VK_SUBPASS_CONTENTS_INLINE);
for (auto model : models) {
if (model.skinned) {
if (m_wireframe) {
vkCmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, m_skinnedPipelineWireframe);
} else {
vkCmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, m_skinnedPipeline);
}
} else {
if (m_wireframe) {
vkCmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipelineWireframe);
} else {
vkCmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipeline);
}
}
// copy bone data
{
const size_t bufferSize = sizeof(glm::mat4) * 128;
void *mapped_data = nullptr;
vkMapMemory(m_device.device, model.boneInfoBuffer.memory, 0, bufferSize, 0, &mapped_data);
memcpy(mapped_data, model.boneData.data(), bufferSize);
VkMappedMemoryRange range = {};
range.sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE;
range.memory = model.boneInfoBuffer.memory;
range.size = bufferSize;
vkFlushMappedMemoryRanges(m_device.device, 1, &range);
vkUnmapMemory(m_device.device, model.boneInfoBuffer.memory);
}
for (const auto &part : model.parts) {
RenderMaterial defaultMaterial = {};
RenderMaterial *material = nullptr;
if (static_cast<size_t>(part.materialIndex) >= model.materials.size()) {
material = &defaultMaterial;
} else {
material = &model.materials[part.materialIndex];
}
const auto h = hash(model, *material);
if (!cachedDescriptors.count(h)) {
if (auto descriptor = createDescriptorFor(model, *material); descriptor != VK_NULL_HANDLE) {
cachedDescriptors[h] = descriptor;
} else {
continue;
}
}
vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipelineLayout, 0, 1, &cachedDescriptors[h], 0, nullptr);
VkDeviceSize offsets[] = {0};
vkCmdBindVertexBuffers(commandBuffer, 0, 1, &part.vertexBuffer.buffer, offsets);
vkCmdBindIndexBuffer(commandBuffer, part.indexBuffer.buffer, 0, VK_INDEX_TYPE_UINT16);
glm::mat4 vp = camera.perspective * camera.view;
vkCmdPushConstants(commandBuffer, m_pipelineLayout, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(glm::mat4), &vp);
auto m = glm::mat4(1.0f);
m = glm::translate(m, model.position);
vkCmdPushConstants(commandBuffer,
m_pipelineLayout,
VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT,
sizeof(glm::mat4),
sizeof(glm::mat4),
&m);
int test = 0;
vkCmdPushConstants(commandBuffer,
m_pipelineLayout,
VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT,
sizeof(glm::mat4) * 2,
sizeof(int),
&test);
int type = (int)material->type;
vkCmdPushConstants(commandBuffer,
m_pipelineLayout,
VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT,
sizeof(glm::mat4) * 2 + sizeof(int),
sizeof(int),
&type);
vkCmdDrawIndexed(commandBuffer, part.numIndices, 1, 0, 0, 0);
}
}
vkCmdEndRenderPass(commandBuffer);
}
void SimpleRenderer::initRenderPass()
{
VkAttachmentDescription colorAttachment = {};
colorAttachment.format = m_device.swapChain->surfaceFormat;
colorAttachment.samples = VK_SAMPLE_COUNT_1_BIT;
colorAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
colorAttachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
colorAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
colorAttachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
colorAttachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
colorAttachment.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
VkAttachmentReference colorAttachmentRef = {};
colorAttachmentRef.attachment = 0;
colorAttachmentRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
VkAttachmentDescription depthAttachment = {};
depthAttachment.format = VK_FORMAT_D32_SFLOAT;
depthAttachment.samples = VK_SAMPLE_COUNT_1_BIT;
depthAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
depthAttachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
depthAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
depthAttachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
depthAttachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
depthAttachment.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
VkAttachmentReference depthAttachmentRef = {};
depthAttachmentRef.attachment = 1;
depthAttachmentRef.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
VkSubpassDependency dependency = {};
dependency.srcSubpass = VK_SUBPASS_EXTERNAL;
dependency.dstSubpass = 0;
dependency.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT;
dependency.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT;
dependency.srcAccessMask = 0;
dependency.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
dependency.dependencyFlags = 0;
VkSubpassDescription subpass = {};
subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
subpass.colorAttachmentCount = 1;
subpass.pColorAttachments = &colorAttachmentRef;
subpass.pDepthStencilAttachment = &depthAttachmentRef;
std::array<VkAttachmentDescription, 2> attachments = {colorAttachment, depthAttachment};
VkRenderPassCreateInfo renderPassInfo = {};
renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
renderPassInfo.attachmentCount = attachments.size();
renderPassInfo.pAttachments = attachments.data();
renderPassInfo.subpassCount = 1;
renderPassInfo.pSubpasses = &subpass;
renderPassInfo.dependencyCount = 1;
renderPassInfo.pDependencies = &dependency;
vkCreateRenderPass(m_device.device, &renderPassInfo, nullptr, &m_renderPass);
}
void SimpleRenderer::initPipeline()
{
VkPipelineShaderStageCreateInfo vertexShaderStageInfo = {};
vertexShaderStageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
vertexShaderStageInfo.stage = VK_SHADER_STAGE_VERTEX_BIT;
vertexShaderStageInfo.module = m_device.loadShaderFromDisk(":/shaders/mesh.vert.spv");
vertexShaderStageInfo.pName = "main";
VkPipelineShaderStageCreateInfo skinnedVertexShaderStageInfo = {};
skinnedVertexShaderStageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
skinnedVertexShaderStageInfo.stage = VK_SHADER_STAGE_VERTEX_BIT;
skinnedVertexShaderStageInfo.module = m_device.loadShaderFromDisk(":/shaders/skinned.vert.spv");
skinnedVertexShaderStageInfo.pName = "main";
VkPipelineShaderStageCreateInfo fragmentShaderStageInfo = {};
fragmentShaderStageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
fragmentShaderStageInfo.stage = VK_SHADER_STAGE_FRAGMENT_BIT;
fragmentShaderStageInfo.module = m_device.loadShaderFromDisk(":/shaders/mesh.frag.spv");
fragmentShaderStageInfo.pName = "main";
std::array<VkPipelineShaderStageCreateInfo, 2> shaderStages = {vertexShaderStageInfo, fragmentShaderStageInfo};
VkVertexInputBindingDescription binding = {};
binding.stride = sizeof(Vertex);
VkVertexInputAttributeDescription positionAttribute = {};
positionAttribute.format = VK_FORMAT_R32G32B32_SFLOAT;
positionAttribute.offset = offsetof(Vertex, position);
VkVertexInputAttributeDescription uv0Attribute = {};
uv0Attribute.format = VK_FORMAT_R32G32_SFLOAT;
uv0Attribute.location = 1;
uv0Attribute.offset = offsetof(Vertex, uv0);
VkVertexInputAttributeDescription uv1Attribute = {};
uv1Attribute.format = VK_FORMAT_R32G32_SFLOAT;
uv1Attribute.location = 2;
uv1Attribute.offset = offsetof(Vertex, uv1);
VkVertexInputAttributeDescription normalAttribute = {};
normalAttribute.format = VK_FORMAT_R32G32B32_SFLOAT;
normalAttribute.location = 3;
normalAttribute.offset = offsetof(Vertex, normal);
VkVertexInputAttributeDescription bitangentAttribute = {};
bitangentAttribute.format = VK_FORMAT_R32G32B32A32_SFLOAT;
bitangentAttribute.location = 4;
bitangentAttribute.offset = offsetof(Vertex, bitangent);
VkVertexInputAttributeDescription colorAttribute = {};
colorAttribute.format = VK_FORMAT_R32G32B32A32_SFLOAT;
colorAttribute.location = 5;
colorAttribute.offset = offsetof(Vertex, color);
VkVertexInputAttributeDescription boneWeightAttribute = {};
boneWeightAttribute.format = VK_FORMAT_R32G32B32A32_SFLOAT;
boneWeightAttribute.location = 6;
boneWeightAttribute.offset = offsetof(Vertex, bone_weight);
VkVertexInputAttributeDescription boneIdAttribute = {};
boneIdAttribute.format = VK_FORMAT_R8G8B8A8_UINT;
boneIdAttribute.location = 7;
boneIdAttribute.offset = offsetof(Vertex, bone_id);
const std::array attributes =
{positionAttribute, uv0Attribute, uv1Attribute, normalAttribute, bitangentAttribute, colorAttribute, boneWeightAttribute, boneIdAttribute};
VkPipelineVertexInputStateCreateInfo vertexInputState = {};
vertexInputState.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
vertexInputState.vertexBindingDescriptionCount = 1;
vertexInputState.pVertexBindingDescriptions = &binding;
vertexInputState.vertexAttributeDescriptionCount = attributes.size();
vertexInputState.pVertexAttributeDescriptions = attributes.data();
VkPipelineInputAssemblyStateCreateInfo inputAssembly = {};
inputAssembly.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
inputAssembly.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
VkViewport viewport = {};
viewport.width = m_device.swapChain->extent.width;
viewport.height = m_device.swapChain->extent.height;
viewport.maxDepth = 1.0f;
VkRect2D scissor = {};
scissor.extent = m_device.swapChain->extent;
VkPipelineViewportStateCreateInfo viewportState = {};
viewportState.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
viewportState.viewportCount = 1;
viewportState.pViewports = &viewport;
viewportState.scissorCount = 1;
viewportState.pScissors = &scissor;
VkPipelineRasterizationStateCreateInfo rasterizer = {};
rasterizer.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
rasterizer.lineWidth = 1.0f;
rasterizer.cullMode = VK_CULL_MODE_BACK_BIT;
rasterizer.frontFace = VK_FRONT_FACE_CLOCKWISE;
VkPipelineMultisampleStateCreateInfo multisampling = {};
multisampling.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
multisampling.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
VkPipelineColorBlendAttachmentState colorBlendAttachment = {};
colorBlendAttachment.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
VkPipelineColorBlendStateCreateInfo colorBlending = {};
colorBlending.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
colorBlending.attachmentCount = 1;
colorBlending.pAttachments = &colorBlendAttachment;
VkPipelineDynamicStateCreateInfo dynamicState = {};
dynamicState.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO;
VkPushConstantRange pushConstantRange = {};
pushConstantRange.size = (sizeof(glm::mat4) * 2) + sizeof(int) * 2;
pushConstantRange.stageFlags = VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT;
VkPipelineLayoutCreateInfo pipelineLayoutInfo{};
pipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
pipelineLayoutInfo.pushConstantRangeCount = 1;
pipelineLayoutInfo.pPushConstantRanges = &pushConstantRange;
pipelineLayoutInfo.setLayoutCount = 1;
pipelineLayoutInfo.pSetLayouts = &m_setLayout;
vkCreatePipelineLayout(m_device.device, &pipelineLayoutInfo, nullptr, &m_pipelineLayout);
VkPipelineDepthStencilStateCreateInfo depthStencil = {};
depthStencil.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO;
depthStencil.depthTestEnable = VK_TRUE;
depthStencil.depthWriteEnable = VK_TRUE;
depthStencil.depthCompareOp = VK_COMPARE_OP_LESS;
depthStencil.maxDepthBounds = 1.0f;
VkGraphicsPipelineCreateInfo createInfo = {};
createInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
createInfo.stageCount = shaderStages.size();
createInfo.pStages = shaderStages.data();
createInfo.pVertexInputState = &vertexInputState;
createInfo.pInputAssemblyState = &inputAssembly;
createInfo.pViewportState = &viewportState;
createInfo.pRasterizationState = &rasterizer;
createInfo.pMultisampleState = &multisampling;
createInfo.pColorBlendState = &colorBlending;
createInfo.pDynamicState = &dynamicState;
createInfo.pDepthStencilState = &depthStencil;
createInfo.layout = m_pipelineLayout;
createInfo.renderPass = m_renderPass;
vkCreateGraphicsPipelines(m_device.device, VK_NULL_HANDLE, 1, &createInfo, nullptr, &m_pipeline);
shaderStages[0] = skinnedVertexShaderStageInfo;
vkCreateGraphicsPipelines(m_device.device, VK_NULL_HANDLE, 1, &createInfo, nullptr, &m_skinnedPipeline);
rasterizer.polygonMode = VK_POLYGON_MODE_LINE;
vkCreateGraphicsPipelines(m_device.device, VK_NULL_HANDLE, 1, &createInfo, nullptr, &m_skinnedPipelineWireframe);
shaderStages[0] = vertexShaderStageInfo;
vkCreateGraphicsPipelines(m_device.device, VK_NULL_HANDLE, 1, &createInfo, nullptr, &m_pipelineWireframe);
}
void SimpleRenderer::initDescriptors()
{
VkDescriptorSetLayoutBinding boneInfoBufferBinding = {};
boneInfoBufferBinding.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
boneInfoBufferBinding.descriptorCount = 1;
boneInfoBufferBinding.stageFlags = VK_SHADER_STAGE_VERTEX_BIT;
boneInfoBufferBinding.binding = 2;
VkDescriptorSetLayoutBinding textureBinding = {};
textureBinding.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
textureBinding.descriptorCount = 1;
textureBinding.stageFlags = VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT;
textureBinding.binding = 3;
VkDescriptorSetLayoutBinding normalBinding = {};
normalBinding.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
normalBinding.descriptorCount = 1;
normalBinding.stageFlags = VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT;
normalBinding.binding = 4;
VkDescriptorSetLayoutBinding specularBinding = {};
specularBinding.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
specularBinding.descriptorCount = 1;
specularBinding.stageFlags = VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT;
specularBinding.binding = 5;
VkDescriptorSetLayoutBinding multiBinding = {};
multiBinding.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
multiBinding.descriptorCount = 1;
multiBinding.stageFlags = VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT;
multiBinding.binding = 6;
const std::array bindings = {boneInfoBufferBinding, textureBinding, normalBinding, specularBinding, multiBinding};
VkDescriptorSetLayoutCreateInfo layoutInfo = {};
layoutInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
layoutInfo.bindingCount = bindings.size();
layoutInfo.pBindings = bindings.data();
vkCreateDescriptorSetLayout(m_device.device, &layoutInfo, nullptr, &m_setLayout);
}
void SimpleRenderer::initTextures(int width, int height)
{
m_compositeTexture = m_device.createTexture(width, height, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT);
m_depthTexture = m_device.createTexture(width, height, VK_FORMAT_D32_SFLOAT, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT);
}
uint64_t SimpleRenderer::hash(const DrawObject &model, const RenderMaterial &material)
{
uint64_t hash = 0;
hash += reinterpret_cast<intptr_t>((void *)&model);
if (material.diffuseTexture)
hash += reinterpret_cast<intptr_t>((void *)material.diffuseTexture);
if (material.normalTexture)
hash += reinterpret_cast<intptr_t>((void *)material.normalTexture);
if (material.specularTexture)
hash += reinterpret_cast<intptr_t>((void *)material.specularTexture);
if (material.multiTexture)
hash += reinterpret_cast<intptr_t>((void *)material.multiTexture);
return hash;
}
VkDescriptorSet SimpleRenderer::createDescriptorFor(const DrawObject &model, const RenderMaterial &material)
{
VkDescriptorSet set;
VkDescriptorSetAllocateInfo allocateInfo = {};
allocateInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
allocateInfo.descriptorPool = m_device.descriptorPool;
allocateInfo.descriptorSetCount = 1;
allocateInfo.pSetLayouts = &m_setLayout;
vkAllocateDescriptorSets(m_device.device, &allocateInfo, &set);
if (set == VK_NULL_HANDLE) {
// qFatal("Failed to create descriptor set!");
return VK_NULL_HANDLE;
}
const size_t bufferSize = sizeof(glm::mat4) * 128;
std::vector<VkWriteDescriptorSet> writes;
VkDescriptorBufferInfo bufferInfo = {};
bufferInfo.buffer = model.boneInfoBuffer.buffer;
bufferInfo.range = bufferSize;
VkWriteDescriptorSet descriptorWrite = {};
descriptorWrite.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
descriptorWrite.dstSet = set;
descriptorWrite.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
descriptorWrite.descriptorCount = 1;
descriptorWrite.pBufferInfo = &bufferInfo;
descriptorWrite.dstBinding = 2;
writes.push_back(descriptorWrite);
VkDescriptorImageInfo imageInfo = {};
imageInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
if (material.diffuseTexture) {
imageInfo.imageView = material.diffuseTexture->view;
imageInfo.sampler = material.diffuseTexture->sampler;
} else {
imageInfo.imageView = m_dummyTex.imageView;
imageInfo.sampler = m_sampler;
}
VkWriteDescriptorSet descriptorWrite2 = {};
descriptorWrite2.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
descriptorWrite2.dstSet = set;
descriptorWrite2.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
descriptorWrite2.descriptorCount = 1;
descriptorWrite2.pImageInfo = &imageInfo;
descriptorWrite2.dstBinding = 3;
writes.push_back(descriptorWrite2);
VkDescriptorImageInfo normalImageInfo = {};
normalImageInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
if (material.normalTexture) {
normalImageInfo.imageView = material.normalTexture->view;
normalImageInfo.sampler = material.normalTexture->sampler;
VkWriteDescriptorSet normalDescriptorWrite2 = {};
normalDescriptorWrite2.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
normalDescriptorWrite2.dstSet = set;
normalDescriptorWrite2.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
normalDescriptorWrite2.descriptorCount = 1;
normalDescriptorWrite2.pImageInfo = &normalImageInfo;
normalDescriptorWrite2.dstBinding = 4;
writes.push_back(normalDescriptorWrite2);
}
VkDescriptorImageInfo specularImageInfo = {};
specularImageInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
if (material.specularTexture) {
specularImageInfo.imageView = material.specularTexture->view;
specularImageInfo.sampler = material.specularTexture->sampler;
VkWriteDescriptorSet specularDescriptorWrite2 = {};
specularDescriptorWrite2.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
specularDescriptorWrite2.dstSet = set;
specularDescriptorWrite2.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
specularDescriptorWrite2.descriptorCount = 1;
specularDescriptorWrite2.pImageInfo = &specularImageInfo;
specularDescriptorWrite2.dstBinding = 5;
writes.push_back(specularDescriptorWrite2);
}
VkDescriptorImageInfo multiImageInfo = {};
multiImageInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
if (material.multiTexture) {
multiImageInfo.imageView = material.multiTexture->view;
multiImageInfo.sampler = material.multiTexture->sampler;
VkWriteDescriptorSet multiDescriptorWrite2 = {};
multiDescriptorWrite2.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
multiDescriptorWrite2.dstSet = set;
multiDescriptorWrite2.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
multiDescriptorWrite2.descriptorCount = 1;
multiDescriptorWrite2.pImageInfo = &multiImageInfo;
multiDescriptorWrite2.dstBinding = 6;
writes.push_back(multiDescriptorWrite2);
}
vkUpdateDescriptorSets(m_device.device, writes.size(), writes.data(), 0, nullptr);
return set;
}
void SimpleRenderer::addDrawObject(const DrawObject &drawObject)
{
}
Texture &SimpleRenderer::getCompositeTexture()
{
return m_compositeTexture;
}

131
renderer/src/swapchain.cpp Normal file
View file

@ -0,0 +1,131 @@
// SPDX-FileCopyrightText: 2024 Joshua Goins <josh@redstrate.com>
// SPDX-License-Identifier: GPL-3.0-or-later
#include "swapchain.h"
#include "device.h"
SwapChain::SwapChain(Device &device, VkSurfaceKHR surface, int width, int height)
: m_device(device)
{
resize(surface, width, height);
}
void SwapChain::resize(VkSurfaceKHR surface, int width, int height)
{
vkQueueWaitIdle(m_device.presentQueue);
if (width == 0 || height == 0)
return;
// TODO: fix this pls
VkBool32 supported;
vkGetPhysicalDeviceSurfaceSupportKHR(m_device.physicalDevice, 0, surface, &supported);
// query swapchain support
VkSurfaceCapabilitiesKHR capabilities;
vkGetPhysicalDeviceSurfaceCapabilitiesKHR(m_device.physicalDevice, surface, &capabilities);
std::vector<VkSurfaceFormatKHR> formats;
uint32_t formatCount;
vkGetPhysicalDeviceSurfaceFormatsKHR(m_device.physicalDevice, surface, &formatCount, nullptr);
formats.resize(formatCount);
vkGetPhysicalDeviceSurfaceFormatsKHR(m_device.physicalDevice, surface, &formatCount, formats.data());
std::vector<VkPresentModeKHR> presentModes;
uint32_t presentModeCount;
vkGetPhysicalDeviceSurfacePresentModesKHR(m_device.physicalDevice, surface, &presentModeCount, nullptr);
presentModes.resize(presentModeCount);
vkGetPhysicalDeviceSurfacePresentModesKHR(m_device.physicalDevice, surface, &presentModeCount, presentModes.data());
// choosing swapchain features
VkSurfaceFormatKHR swapchainSurfaceFormat = formats[0];
for (const auto &availableFormat : formats) {
if (availableFormat.format == VK_FORMAT_B8G8R8A8_UNORM && availableFormat.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) {
swapchainSurfaceFormat = availableFormat;
}
}
VkPresentModeKHR swapchainPresentMode = VK_PRESENT_MODE_FIFO_KHR;
for (const auto &availablePresentMode : presentModes) {
if (availablePresentMode == VK_PRESENT_MODE_MAILBOX_KHR) {
swapchainPresentMode = availablePresentMode;
}
}
uint32_t imageCount = capabilities.minImageCount + 1;
if (capabilities.maxImageCount > 0 && imageCount > capabilities.maxImageCount) {
imageCount = capabilities.maxImageCount;
}
// create swapchain
VkSwapchainCreateInfoKHR createInfo = {};
createInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
createInfo.surface = surface;
createInfo.minImageCount = imageCount;
createInfo.imageFormat = swapchainSurfaceFormat.format;
createInfo.imageColorSpace = swapchainSurfaceFormat.colorSpace;
createInfo.imageExtent.width = width;
createInfo.imageExtent.height = height;
createInfo.imageArrayLayers = 1;
createInfo.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
createInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
createInfo.preTransform = capabilities.currentTransform;
createInfo.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
createInfo.presentMode = swapchainPresentMode;
createInfo.clipped = VK_TRUE;
surfaceFormat = swapchainSurfaceFormat.format;
VkSwapchainKHR oldSwapchain = swapchain;
createInfo.oldSwapchain = oldSwapchain;
vkCreateSwapchainKHR(m_device.device, &createInfo, nullptr, &swapchain);
if (oldSwapchain != VK_NULL_HANDLE)
vkDestroySwapchainKHR(m_device.device, oldSwapchain, nullptr);
extent.width = width;
extent.height = height;
vkGetSwapchainImagesKHR(m_device.device, swapchain, &imageCount, nullptr);
swapchainImages.resize(imageCount);
vkGetSwapchainImagesKHR(m_device.device, swapchain, &imageCount, swapchainImages.data());
swapchainViews.resize(swapchainImages.size());
for (size_t i = 0; i < swapchainImages.size(); i++) {
VkImageViewCreateInfo view_create_info = {};
view_create_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
view_create_info.image = swapchainImages[i];
view_create_info.viewType = VK_IMAGE_VIEW_TYPE_2D;
view_create_info.format = swapchainSurfaceFormat.format;
view_create_info.components.r = VK_COMPONENT_SWIZZLE_IDENTITY;
view_create_info.components.g = VK_COMPONENT_SWIZZLE_IDENTITY;
view_create_info.components.b = VK_COMPONENT_SWIZZLE_IDENTITY;
view_create_info.components.a = VK_COMPONENT_SWIZZLE_IDENTITY;
view_create_info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
view_create_info.subresourceRange.baseMipLevel = 0;
view_create_info.subresourceRange.levelCount = 1;
view_create_info.subresourceRange.baseArrayLayer = 0;
view_create_info.subresourceRange.layerCount = 1;
vkCreateImageView(m_device.device, &view_create_info, nullptr, &swapchainViews[i]);
}
VkSemaphoreCreateInfo semaphoreInfo = {};
semaphoreInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
VkFenceCreateInfo fenceCreateInfo = {};
fenceCreateInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
fenceCreateInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT;
for (size_t i = 0; i < 3; i++) {
vkCreateSemaphore(m_device.device, &semaphoreInfo, nullptr, &imageAvailableSemaphores[i]);
vkCreateSemaphore(m_device.device, &semaphoreInfo, nullptr, &renderFinishedSemaphores[i]);
vkCreateFence(m_device.device, &fenceCreateInfo, nullptr, &inFlightFences[i]);
}
}