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:
parent
5317300aaf
commit
e34daadbcd
31 changed files with 2542 additions and 2174 deletions
|
@ -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"
|
|
@ -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;
|
||||
};
|
|
@ -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);
|
||||
|
|
|
@ -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] = {};
|
||||
|
|
|
@ -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
|
||||
|
|
38
renderer/include/baserenderer.h
Normal file
38
renderer/include/baserenderer.h
Normal 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
14
renderer/include/buffer.h
Normal 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
22
renderer/include/camera.h
Normal 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
54
renderer/include/device.h
Normal 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);
|
||||
};
|
46
renderer/include/drawobject.h
Normal file
46
renderer/include/drawobject.h
Normal 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;
|
||||
};
|
104
renderer/include/gamerenderer.h
Normal file
104
renderer/include/gamerenderer.h
Normal 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;
|
||||
};
|
|
@ -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;
|
||||
};
|
67
renderer/include/rendermanager.h
Normal file
67
renderer/include/rendermanager.h
Normal 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;
|
||||
};
|
|
@ -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;
|
||||
};
|
74
renderer/include/shaderstructs.h
Normal file
74
renderer/include/shaderstructs.h
Normal 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;*/
|
||||
};
|
70
renderer/include/simplerenderer.h
Normal file
70
renderer/include/simplerenderer.h
Normal 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;
|
||||
};
|
28
renderer/include/swapchain.h
Normal file
28
renderer/include/swapchain.h
Normal 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;
|
||||
};
|
14
renderer/include/texture.h
Normal file
14
renderer/include/texture.h
Normal 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;
|
||||
};
|
14
renderer/shaders/blit.frag
Normal file
14
renderer/shaders/blit.frag
Normal 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);
|
||||
}
|
BIN
renderer/shaders/blit.frag.spv
Normal file
BIN
renderer/shaders/blit.frag.spv
Normal file
Binary file not shown.
11
renderer/shaders/blit.vert
Normal file
11
renderer/shaders/blit.vert
Normal 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);
|
||||
}
|
BIN
renderer/shaders/blit.vert.spv
Normal file
BIN
renderer/shaders/blit.vert.spv
Normal file
Binary file not shown.
|
@ -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
311
renderer/src/device.cpp
Normal 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, ®ion);
|
||||
|
||||
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);
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
784
renderer/src/rendermanager.cpp
Normal file
784
renderer/src/rendermanager.cpp
Normal 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, ®ion);
|
||||
|
||||
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);
|
||||
}
|
573
renderer/src/simplerenderer.cpp
Normal file
573
renderer/src/simplerenderer.cpp
Normal 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
131
renderer/src/swapchain.cpp
Normal 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]);
|
||||
}
|
||||
}
|
Loading…
Add table
Reference in a new issue