mirror of
https://github.com/redstrate/Novus.git
synced 2025-04-21 19:57:44 +00:00
Add experimental new rendering system
I started writing this late last year, and finally uploading parts of it. Currently, doesn't work, but doesn't crash either. Enable it via the NOVUS_USE_NEW_RENDERER environment variable. The goal is to use the game's own shaders instead of creating our own, it's lacking support for buffers with actual data in them and constants so while it "works" nothing is displayed on screen yet.
This commit is contained in:
parent
db50a7ff36
commit
b9b162b377
9 changed files with 883 additions and 109 deletions
2
extern/libphysis
vendored
2
extern/libphysis
vendored
|
@ -1 +1 @@
|
||||||
Subproject commit d90badda85518997d9e639c49744531d4745d165
|
Subproject commit 991146eeff4c154a6206d58a9f17b4ecea517d58
|
|
@ -28,7 +28,7 @@ MDLPart::MDLPart(GameData *data, FileCache &cache, QWidget *parent)
|
||||||
|
|
||||||
pbd = physis_parse_pbd(physis_gamedata_extract_file(data, "chara/xls/bonedeformer/human.pbd"));
|
pbd = physis_parse_pbd(physis_gamedata_extract_file(data, "chara/xls/bonedeformer/human.pbd"));
|
||||||
|
|
||||||
renderer = new Renderer();
|
renderer = new Renderer(data);
|
||||||
|
|
||||||
auto inst = new QVulkanInstance();
|
auto inst = new QVulkanInstance();
|
||||||
inst->setVkInstance(renderer->instance);
|
inst->setVkInstance(renderer->instance);
|
||||||
|
|
|
@ -9,8 +9,6 @@
|
||||||
#include <QVBoxLayout>
|
#include <QVBoxLayout>
|
||||||
#include <spirv_glsl.hpp>
|
#include <spirv_glsl.hpp>
|
||||||
|
|
||||||
dxvk::Logger dxvk::Logger::s_instance("dxbc.log");
|
|
||||||
|
|
||||||
SHPKPart::SHPKPart(GameData *data, QWidget *parent)
|
SHPKPart::SHPKPart(GameData *data, QWidget *parent)
|
||||||
: QWidget(parent)
|
: QWidget(parent)
|
||||||
, data(data)
|
, data(data)
|
||||||
|
|
|
@ -1,6 +1,10 @@
|
||||||
# SPDX-FileCopyrightText: 2023 Joshua Goins <josh@redstrate.com>
|
# SPDX-FileCopyrightText: 2023 Joshua Goins <josh@redstrate.com>
|
||||||
# SPDX-License-Identifier: CC0-1.0
|
# SPDX-License-Identifier: CC0-1.0
|
||||||
|
|
||||||
|
find_package(spirv_cross_core REQUIRED)
|
||||||
|
find_package(spirv_cross_glsl REQUIRED)
|
||||||
|
find_package(SPIRV-Headers REQUIRED)
|
||||||
|
|
||||||
add_library(renderer STATIC)
|
add_library(renderer STATIC)
|
||||||
target_sources(renderer
|
target_sources(renderer
|
||||||
PRIVATE
|
PRIVATE
|
||||||
|
@ -8,7 +12,9 @@ target_sources(renderer
|
||||||
|
|
||||||
src/renderer.cpp
|
src/renderer.cpp
|
||||||
src/imguipass.cpp
|
src/imguipass.cpp
|
||||||
src/imguipass.h)
|
src/imguipass.h
|
||||||
|
src/rendersystem.cpp
|
||||||
|
include/rendersystem.h)
|
||||||
qt_add_resources(renderer
|
qt_add_resources(renderer
|
||||||
"shaders"
|
"shaders"
|
||||||
PREFIX "/"
|
PREFIX "/"
|
||||||
|
@ -25,7 +31,10 @@ target_link_libraries(renderer
|
||||||
Vulkan::Vulkan
|
Vulkan::Vulkan
|
||||||
Physis::Physis
|
Physis::Physis
|
||||||
glm::glm
|
glm::glm
|
||||||
imgui)
|
imgui
|
||||||
|
dxbc
|
||||||
|
spirv-cross-core
|
||||||
|
spirv-cross-glsl)
|
||||||
target_compile_definitions(renderer PUBLIC GLM_FORCE_RADIANS GLM_FORCE_DEPTH_ZERO_TO_ONE GLM_ENABLE_EXPERIMENTAL)
|
target_compile_definitions(renderer PUBLIC GLM_FORCE_RADIANS GLM_FORCE_DEPTH_ZERO_TO_ONE GLM_ENABLE_EXPERIMENTAL)
|
||||||
|
|
||||||
add_library(Novus::Renderer ALIAS renderer)
|
add_library(Novus::Renderer ALIAS renderer)
|
|
@ -1,3 +1,9 @@
|
||||||
# Renderer
|
# Renderer
|
||||||
|
|
||||||
This handles rendering FFXIV visual data, such as models and materials. It's still basic at the moment.
|
This handles rendering FFXIV visual data, such as models and materials.
|
||||||
|
|
||||||
|
Currently it has a basic rendering method enabled by default, which is limited to displaying a material's diffuse texture and not much else.
|
||||||
|
|
||||||
|
## Experimental
|
||||||
|
|
||||||
|
There's a more advanced renderer which is still in development, which uses the game's own shaders to render models. Launch any Novus tool with `NOVUS_USE_NEW_RENDERER=1` set to enable it.
|
|
@ -10,7 +10,7 @@
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <vulkan/vulkan.h>
|
#include <vulkan/vulkan.h>
|
||||||
|
|
||||||
#include <physis.hpp>
|
#include "rendersystem.h"
|
||||||
|
|
||||||
struct RenderPart {
|
struct RenderPart {
|
||||||
size_t numIndices;
|
size_t numIndices;
|
||||||
|
@ -62,7 +62,7 @@ struct ImGuiContext;
|
||||||
class Renderer
|
class Renderer
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Renderer();
|
Renderer(GameData *data);
|
||||||
|
|
||||||
void initPipeline();
|
void initPipeline();
|
||||||
void initDescriptors();
|
void initDescriptors();
|
||||||
|
@ -98,6 +98,9 @@ public:
|
||||||
VkDeviceMemory depthMemory;
|
VkDeviceMemory depthMemory;
|
||||||
VkImageView depthView;
|
VkImageView depthView;
|
||||||
|
|
||||||
|
VkBuffer dummyBuffer;
|
||||||
|
VkDeviceMemory dummyBufferMemory;
|
||||||
|
|
||||||
VkImage dummyImage;
|
VkImage dummyImage;
|
||||||
VkDeviceMemory dummyMemory;
|
VkDeviceMemory dummyMemory;
|
||||||
VkImageView dummyView;
|
VkImageView dummyView;
|
||||||
|
@ -148,6 +151,12 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void createDummyTexture();
|
void createDummyTexture();
|
||||||
|
void createDummyBuffer();
|
||||||
|
|
||||||
ImGuiPass *imGuiPass = nullptr;
|
ImGuiPass *imGuiPass = nullptr;
|
||||||
|
|
||||||
|
std::unique_ptr<RenderSystem> m_renderSystem;
|
||||||
|
|
||||||
|
GameData *m_data = nullptr;
|
||||||
|
bool m_enableNewRenderSystem = false;
|
||||||
};
|
};
|
71
renderer/include/rendersystem.h
Normal file
71
renderer/include/rendersystem.h
Normal file
|
@ -0,0 +1,71 @@
|
||||||
|
// SPDX-FileCopyrightText: 2024 Joshua Goins <josh@redstrate.com>
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <QDebug>
|
||||||
|
#include <string_view>
|
||||||
|
|
||||||
|
#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);
|
||||||
|
void bindPipeline(VkCommandBuffer commandBuffer, physis_Shader &vertexShader, physis_Shader &pixelShader);
|
||||||
|
VkShaderModule convertShaderModule(const physis_Shader &shader, spv::ExecutionModel executionModel);
|
||||||
|
spirv_cross::CompilerGLSL getShaderModuleResources(const physis_Shader &shader);
|
||||||
|
|
||||||
|
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;
|
||||||
|
};
|
||||||
|
|
||||||
|
// 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 RenderModel &model, const CachedPipeline &cachedPipeline, int i);
|
||||||
|
};
|
|
@ -45,8 +45,11 @@ VKAPI_ATTR VkBool32 VKAPI_CALL DebugCallback(VkDebugUtilsMessageSeverityFlagBits
|
||||||
return VK_FALSE;
|
return VK_FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
Renderer::Renderer()
|
Renderer::Renderer(GameData *data)
|
||||||
|
: m_data(data)
|
||||||
{
|
{
|
||||||
|
m_enableNewRenderSystem = qgetenv("NOVUS_USE_NEW_RENDERER") == QByteArrayLiteral("1");
|
||||||
|
|
||||||
Q_INIT_RESOURCE(shaders);
|
Q_INIT_RESOURCE(shaders);
|
||||||
|
|
||||||
ctx = ImGui::CreateContext();
|
ctx = ImGui::CreateContext();
|
||||||
|
@ -80,11 +83,15 @@ Renderer::Renderer()
|
||||||
debugCreateInfo.messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT;
|
debugCreateInfo.messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT;
|
||||||
debugCreateInfo.pfnUserCallback = DebugCallback;
|
debugCreateInfo.pfnUserCallback = DebugCallback;
|
||||||
|
|
||||||
|
VkApplicationInfo applicationInfo = {VK_STRUCTURE_TYPE_APPLICATION_INFO};
|
||||||
|
applicationInfo.apiVersion = VK_API_VERSION_1_3;
|
||||||
|
|
||||||
VkInstanceCreateInfo createInfo = {};
|
VkInstanceCreateInfo createInfo = {};
|
||||||
createInfo.pNext = &debugCreateInfo;
|
createInfo.pNext = &debugCreateInfo;
|
||||||
createInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
|
createInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
|
||||||
createInfo.ppEnabledExtensionNames = instanceExtensions.data();
|
createInfo.ppEnabledExtensionNames = instanceExtensions.data();
|
||||||
createInfo.enabledExtensionCount = instanceExtensions.size();
|
createInfo.enabledExtensionCount = instanceExtensions.size();
|
||||||
|
createInfo.pApplicationInfo = &applicationInfo;
|
||||||
|
|
||||||
vkCreateInstance(&createInfo, nullptr, &instance);
|
vkCreateInstance(&createInfo, nullptr, &instance);
|
||||||
|
|
||||||
|
@ -184,12 +191,30 @@ Renderer::Renderer()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 = {};
|
VkDeviceCreateInfo deviceCeateInfo = {};
|
||||||
deviceCeateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
|
deviceCeateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
|
||||||
deviceCeateInfo.pQueueCreateInfos = queueCreateInfos.data();
|
deviceCeateInfo.pQueueCreateInfos = queueCreateInfos.data();
|
||||||
deviceCeateInfo.queueCreateInfoCount = static_cast<uint32_t>(queueCreateInfos.size());
|
deviceCeateInfo.queueCreateInfoCount = static_cast<uint32_t>(queueCreateInfos.size());
|
||||||
deviceCeateInfo.ppEnabledExtensionNames = deviceExtensions.data();
|
deviceCeateInfo.ppEnabledExtensionNames = deviceExtensions.data();
|
||||||
deviceCeateInfo.enabledExtensionCount = static_cast<uint32_t>(deviceExtensions.size());
|
deviceCeateInfo.enabledExtensionCount = static_cast<uint32_t>(deviceExtensions.size());
|
||||||
|
deviceCeateInfo.pEnabledFeatures = &enabledFeatures;
|
||||||
|
deviceCeateInfo.pNext = &enabled13Features;
|
||||||
|
|
||||||
vkCreateDevice(physicalDevice, &deviceCeateInfo, nullptr, &device);
|
vkCreateDevice(physicalDevice, &deviceCeateInfo, nullptr, &device);
|
||||||
|
|
||||||
|
@ -206,6 +231,11 @@ Renderer::Renderer()
|
||||||
vkCreateCommandPool(device, &poolInfo, nullptr, &commandPool);
|
vkCreateCommandPool(device, &poolInfo, nullptr, &commandPool);
|
||||||
|
|
||||||
createDummyTexture();
|
createDummyTexture();
|
||||||
|
createDummyBuffer();
|
||||||
|
|
||||||
|
if (m_enableNewRenderSystem) {
|
||||||
|
m_renderSystem = std::make_unique<RenderSystem>(*this, m_data);
|
||||||
|
}
|
||||||
|
|
||||||
qInfo() << "Initialized renderer!";
|
qInfo() << "Initialized renderer!";
|
||||||
}
|
}
|
||||||
|
@ -418,6 +448,10 @@ bool Renderer::initSwapchain(VkSurfaceKHR surface, int width, int height)
|
||||||
ImGui::SetCurrentContext(ctx);
|
ImGui::SetCurrentContext(ctx);
|
||||||
imGuiPass = new ImGuiPass(*this);
|
imGuiPass = new ImGuiPass(*this);
|
||||||
|
|
||||||
|
if (m_enableNewRenderSystem) {
|
||||||
|
m_renderSystem->setSize(width, height);
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -454,6 +488,9 @@ void Renderer::render(const std::vector<RenderModel> &models)
|
||||||
|
|
||||||
vkBeginCommandBuffer(commandBuffer, &beginInfo);
|
vkBeginCommandBuffer(commandBuffer, &beginInfo);
|
||||||
|
|
||||||
|
if (m_enableNewRenderSystem) {
|
||||||
|
m_renderSystem->render(imageIndex, commandBuffer);
|
||||||
|
} else {
|
||||||
VkRenderPassBeginInfo renderPassInfo = {};
|
VkRenderPassBeginInfo renderPassInfo = {};
|
||||||
renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
|
renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
|
||||||
renderPassInfo.renderPass = renderPass;
|
renderPassInfo.renderPass = renderPass;
|
||||||
|
@ -572,6 +609,8 @@ void Renderer::render(const std::vector<RenderModel> &models)
|
||||||
}
|
}
|
||||||
|
|
||||||
vkCmdEndRenderPass(commandBuffer);
|
vkCmdEndRenderPass(commandBuffer);
|
||||||
|
}
|
||||||
|
|
||||||
vkEndCommandBuffer(commandBuffer);
|
vkEndCommandBuffer(commandBuffer);
|
||||||
|
|
||||||
VkSubmitInfo submitInfo = {};
|
VkSubmitInfo submitInfo = {};
|
||||||
|
@ -662,6 +701,10 @@ RenderModel Renderer::addModel(const physis_MDL &model, int lod)
|
||||||
|
|
||||||
reloadModel(renderModel, lod);
|
reloadModel(renderModel, lod);
|
||||||
|
|
||||||
|
if (m_enableNewRenderSystem) {
|
||||||
|
m_renderSystem->testInit(&renderModel);
|
||||||
|
}
|
||||||
|
|
||||||
return renderModel;
|
return renderModel;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1501,3 +1544,38 @@ void Renderer::createDummyTexture()
|
||||||
|
|
||||||
vkCreateSampler(device, &samplerInfo, nullptr, &dummySampler);
|
vkCreateSampler(device, &samplerInfo, nullptr, &dummySampler);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Renderer::createDummyBuffer()
|
||||||
|
{
|
||||||
|
VkBufferCreateInfo bufferInfo = {};
|
||||||
|
bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
|
||||||
|
bufferInfo.size = 655360;
|
||||||
|
bufferInfo.usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT;
|
||||||
|
bufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
||||||
|
|
||||||
|
vkCreateBuffer(device, &bufferInfo, nullptr, &dummyBuffer);
|
||||||
|
|
||||||
|
// allocate staging memory
|
||||||
|
VkMemoryRequirements memRequirements;
|
||||||
|
vkGetBufferMemoryRequirements(device, dummyBuffer, &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, &dummyBufferMemory);
|
||||||
|
|
||||||
|
vkBindBufferMemory(device, dummyBuffer, dummyBufferMemory, 0);
|
||||||
|
|
||||||
|
std::vector<glm::vec4> fakeData(192);
|
||||||
|
for (int i = 0; i < fakeData.size(); i++) {
|
||||||
|
fakeData[i] = glm::vec4{1.0f};
|
||||||
|
}
|
||||||
|
|
||||||
|
// copy to staging buffer
|
||||||
|
void *mapped_data;
|
||||||
|
vkMapMemory(device, dummyBufferMemory, 0, sizeof(glm::vec4) * 192, 0, &mapped_data);
|
||||||
|
memcpy(mapped_data, fakeData.data(), sizeof(glm::vec4) * 192);
|
||||||
|
vkUnmapMemory(device, dummyBufferMemory);
|
||||||
|
}
|
||||||
|
|
603
renderer/src/rendersystem.cpp
Normal file
603
renderer/src/rendersystem.cpp
Normal file
|
@ -0,0 +1,603 @@
|
||||||
|
// SPDX-FileCopyrightText: 2024 Joshua Goins <josh@redstrate.com>
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
#include "rendersystem.h"
|
||||||
|
|
||||||
|
#include <array>
|
||||||
|
|
||||||
|
#include <QDebug>
|
||||||
|
|
||||||
|
#include <physis.hpp>
|
||||||
|
|
||||||
|
#include "dxbc_module.h"
|
||||||
|
#include "dxbc_reader.h"
|
||||||
|
#include "renderer.hpp"
|
||||||
|
#include <spirv_glsl.hpp>
|
||||||
|
|
||||||
|
dxvk::Logger dxvk::Logger::s_instance("dxbc.log");
|
||||||
|
|
||||||
|
const std::array passes = {
|
||||||
|
// Shadows?
|
||||||
|
"PASS_0",
|
||||||
|
"PASS_Z_OPAQUE",
|
||||||
|
// Z "Prepass", normals + depth (or is this maybe G_OPAQUE?
|
||||||
|
"PASS_G_OPAQUE",
|
||||||
|
// g run for each light
|
||||||
|
// takes view pos, then unknown texture and normal
|
||||||
|
"PASS_LIGHTING_OPAQUE",
|
||||||
|
"PASS_G_SEMITRANSPARENCY",
|
||||||
|
"PASS_COMPOSITE_OPAQUE",
|
||||||
|
"PASS_7",
|
||||||
|
"PASS_WATER",
|
||||||
|
"PASS_WATER_Z",
|
||||||
|
"PASS_SEMITRANSPARENCY",
|
||||||
|
"PASS_COMPOSITE_SEMITRANSPARENCY",
|
||||||
|
"PASS_10",
|
||||||
|
"PASS_12",
|
||||||
|
"PASS_14"};
|
||||||
|
|
||||||
|
/*
|
||||||
|
// TODO: auto-select node from material shader keys (see main.rs in physis)
|
||||||
|
auto node = shpk->get_node(12);
|
||||||
|
|
||||||
|
for (int i = 0; i < 16; i++) {
|
||||||
|
const int passIndex = node->pass_indices[i];
|
||||||
|
if (passIndex != -1) {
|
||||||
|
physis_ShaderPass *pass = node->passes[passIndex];
|
||||||
|
|
||||||
|
auto vertex_shader = shpk->shaders[pass->vertex_shader_index];
|
||||||
|
auto pixel_shader = shpk->shaders[pass->vertex_shader_index];
|
||||||
|
|
||||||
|
use_shader(vertex_shader);
|
||||||
|
use_shader(pixel_shader);
|
||||||
|
|
||||||
|
// set parameters from material
|
||||||
|
g_MaterialParameter = mtrl->constants;
|
||||||
|
|
||||||
|
draw();
|
||||||
|
}
|
||||||
|
}*/
|
||||||
|
|
||||||
|
RenderSystem::RenderSystem(Renderer &renderer, GameData *data)
|
||||||
|
: m_renderer(renderer)
|
||||||
|
, m_data(data)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenderSystem::testInit(::RenderModel *m)
|
||||||
|
{
|
||||||
|
qInfo() << "initialzing render system with dummy data...";
|
||||||
|
RenderModel model{.internal_model = new ::RenderModel(*m),
|
||||||
|
.shpk = physis_parse_shpk(physis_gamedata_extract_file(m_data, "shader/sm5/shpk/character.shpk"))};
|
||||||
|
m_renderModels.push_back(model);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenderSystem::render(uint32_t imageIndex, VkCommandBuffer commandBuffer)
|
||||||
|
{
|
||||||
|
int i = 0;
|
||||||
|
for (const auto pass : passes) {
|
||||||
|
beginPass(imageIndex, commandBuffer, pass);
|
||||||
|
|
||||||
|
// hardcoded to the known pass for now
|
||||||
|
if (std::string_view{"PASS_G_OPAQUE"} == pass) {
|
||||||
|
for (auto &model : m_renderModels) {
|
||||||
|
// hardcoded selector for now
|
||||||
|
const u_int32_t selector = 276147857;
|
||||||
|
const physis_SHPKNode node = physis_shpk_get_node(&model.shpk, selector);
|
||||||
|
|
||||||
|
// check if invalid
|
||||||
|
if (node.pass_count == 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// this is an index into the node's pass array, not to get confused with the global one we always follow.
|
||||||
|
const int passIndice = node.pass_indices[i];
|
||||||
|
if (passIndice != 255) {
|
||||||
|
const Pass currentPass = node.passes[passIndice];
|
||||||
|
|
||||||
|
const uint32_t vertexShaderIndice = currentPass.vertex_shader;
|
||||||
|
const uint32_t pixelShaderIndice = currentPass.vertex_shader;
|
||||||
|
|
||||||
|
physis_Shader vertexShader = model.shpk.vertex_shaders[vertexShaderIndice];
|
||||||
|
physis_Shader pixelShader = model.shpk.pixel_shaders[pixelShaderIndice];
|
||||||
|
|
||||||
|
bindPipeline(commandBuffer, vertexShader, pixelShader);
|
||||||
|
|
||||||
|
for (const auto &part : model.internal_model->parts) {
|
||||||
|
// if (part.materialIndex == 1) {
|
||||||
|
const uint32_t hash = vertexShader.len + pixelShader.len;
|
||||||
|
auto &cachedPipeline = m_cachedPipelines[hash];
|
||||||
|
|
||||||
|
int i = 0;
|
||||||
|
for (auto setLayout : cachedPipeline.setLayouts) {
|
||||||
|
qInfo() << "Trying to cache descriptor set at " << i;
|
||||||
|
|
||||||
|
if (!cachedPipeline.cachedDescriptors.count(i)) {
|
||||||
|
if (auto descriptor = createDescriptorFor(model, cachedPipeline, i); descriptor != VK_NULL_HANDLE) {
|
||||||
|
cachedPipeline.cachedDescriptors[i] = descriptor;
|
||||||
|
} else {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: we can pass all descriptors in one function call
|
||||||
|
vkCmdBindDescriptorSets(commandBuffer,
|
||||||
|
VK_PIPELINE_BIND_POINT_GRAPHICS,
|
||||||
|
cachedPipeline.pipelineLayout,
|
||||||
|
i,
|
||||||
|
1,
|
||||||
|
&cachedPipeline.cachedDescriptors[i],
|
||||||
|
0,
|
||||||
|
nullptr);
|
||||||
|
qInfo() << "Binding descriptor set at " << i;
|
||||||
|
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
VkDeviceSize offsets[] = {0};
|
||||||
|
vkCmdBindVertexBuffers(commandBuffer, 0, 1, &part.vertexBuffer, offsets);
|
||||||
|
vkCmdBindIndexBuffer(commandBuffer, part.indexBuffer, 0, VK_INDEX_TYPE_UINT16);
|
||||||
|
|
||||||
|
qInfo() << "Calling index";
|
||||||
|
vkCmdDrawIndexed(commandBuffer, part.numIndices, 1, 0, 0, 0);
|
||||||
|
//}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
endPass(commandBuffer);
|
||||||
|
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenderSystem::setSize(uint32_t width, uint32_t height)
|
||||||
|
{
|
||||||
|
m_extent = {width, height};
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenderSystem::beginPass(uint32_t imageIndex, VkCommandBuffer commandBuffer, const std::string_view passName)
|
||||||
|
{
|
||||||
|
VkRenderingInfo renderingInfo{VK_STRUCTURE_TYPE_RENDERING_INFO};
|
||||||
|
|
||||||
|
renderingInfo.renderArea.extent = m_extent;
|
||||||
|
|
||||||
|
std::vector<VkRenderingAttachmentInfo> colorAttachments;
|
||||||
|
VkRenderingAttachmentInfo depthStencilAttachment{};
|
||||||
|
|
||||||
|
if (passName == "PASS_G_OPAQUE") {
|
||||||
|
// normals, it seems like
|
||||||
|
{
|
||||||
|
VkRenderingAttachmentInfo attachmentInfo{VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO};
|
||||||
|
attachmentInfo.imageView = m_renderer.swapchainViews[imageIndex];
|
||||||
|
attachmentInfo.imageLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; // VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL
|
||||||
|
attachmentInfo.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
|
||||||
|
attachmentInfo.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
|
||||||
|
|
||||||
|
attachmentInfo.clearValue.color.float32[0] = 0.24;
|
||||||
|
attachmentInfo.clearValue.color.float32[1] = 0.24;
|
||||||
|
attachmentInfo.clearValue.color.float32[2] = 0.24;
|
||||||
|
attachmentInfo.clearValue.color.float32[3] = 1.0;
|
||||||
|
|
||||||
|
colorAttachments.push_back(attachmentInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
// unknown, seems to be background?
|
||||||
|
{
|
||||||
|
VkRenderingAttachmentInfo attachmentInfo{VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO};
|
||||||
|
attachmentInfo.imageView = VK_NULL_HANDLE;
|
||||||
|
attachmentInfo.imageLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
|
||||||
|
attachmentInfo.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
|
||||||
|
attachmentInfo.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
|
||||||
|
|
||||||
|
colorAttachments.push_back(attachmentInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
// unknown, seems to be background?
|
||||||
|
{
|
||||||
|
VkRenderingAttachmentInfo attachmentInfo{VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO};
|
||||||
|
attachmentInfo.imageView = VK_NULL_HANDLE;
|
||||||
|
attachmentInfo.imageLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
|
||||||
|
attachmentInfo.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
|
||||||
|
attachmentInfo.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
|
||||||
|
|
||||||
|
colorAttachments.push_back(attachmentInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
// depth
|
||||||
|
{
|
||||||
|
VkRenderingAttachmentInfo attachmentInfo{VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO};
|
||||||
|
attachmentInfo.imageView = m_renderer.depthView;
|
||||||
|
attachmentInfo.imageLayout = VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL;
|
||||||
|
attachmentInfo.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
|
||||||
|
attachmentInfo.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
|
||||||
|
attachmentInfo.clearValue.depthStencil.depth = 1.0f;
|
||||||
|
|
||||||
|
depthStencilAttachment = attachmentInfo;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// qWarning() << "Unimplemented pass" << passName;
|
||||||
|
}
|
||||||
|
|
||||||
|
renderingInfo.layerCount = 1;
|
||||||
|
renderingInfo.pColorAttachments = colorAttachments.data();
|
||||||
|
renderingInfo.colorAttachmentCount = colorAttachments.size();
|
||||||
|
|
||||||
|
if (depthStencilAttachment.imageView != VK_NULL_HANDLE) {
|
||||||
|
renderingInfo.pDepthAttachment = &depthStencilAttachment;
|
||||||
|
// renderingInfo.pStencilAttachment = &depthStencilAttachment;
|
||||||
|
}
|
||||||
|
|
||||||
|
vkCmdBeginRendering(commandBuffer, &renderingInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenderSystem::endPass(VkCommandBuffer commandBuffer)
|
||||||
|
{
|
||||||
|
vkCmdEndRendering(commandBuffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenderSystem::bindPipeline(VkCommandBuffer commandBuffer, physis_Shader &vertexShader, physis_Shader &pixelShader)
|
||||||
|
{
|
||||||
|
const uint32_t hash = vertexShader.len + pixelShader.len;
|
||||||
|
if (!m_cachedPipelines.contains(hash)) {
|
||||||
|
qInfo() << "Creating new pipeline...";
|
||||||
|
|
||||||
|
auto vertexShaderModule = convertShaderModule(vertexShader, spv::ExecutionModelVertex);
|
||||||
|
auto fragmentShaderModule = convertShaderModule(pixelShader, spv::ExecutionModelFragment);
|
||||||
|
|
||||||
|
VkPipelineShaderStageCreateInfo vertexShaderStageInfo = {};
|
||||||
|
vertexShaderStageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
|
||||||
|
vertexShaderStageInfo.stage = VK_SHADER_STAGE_VERTEX_BIT;
|
||||||
|
vertexShaderStageInfo.module = vertexShaderModule;
|
||||||
|
vertexShaderStageInfo.pName = "main";
|
||||||
|
|
||||||
|
VkPipelineShaderStageCreateInfo fragmentShaderStageInfo = {};
|
||||||
|
fragmentShaderStageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
|
||||||
|
fragmentShaderStageInfo.stage = VK_SHADER_STAGE_FRAGMENT_BIT;
|
||||||
|
fragmentShaderStageInfo.module = fragmentShaderModule;
|
||||||
|
fragmentShaderStageInfo.pName = "main";
|
||||||
|
|
||||||
|
std::array<VkPipelineShaderStageCreateInfo, 2> shaderStages = {vertexShaderStageInfo, fragmentShaderStageInfo};
|
||||||
|
|
||||||
|
VkVertexInputBindingDescription binding = {};
|
||||||
|
binding.stride = sizeof(Vertex);
|
||||||
|
|
||||||
|
auto vertex_glsl = getShaderModuleResources(vertexShader);
|
||||||
|
auto vertex_resources = vertex_glsl.get_shader_resources();
|
||||||
|
|
||||||
|
auto fragment_glsl = getShaderModuleResources(pixelShader);
|
||||||
|
auto fragment_resources = fragment_glsl.get_shader_resources();
|
||||||
|
|
||||||
|
std::vector<RequestedSet> requestedSets;
|
||||||
|
|
||||||
|
const auto &collectResources = [&requestedSets](const spirv_cross::CompilerGLSL &glsl,
|
||||||
|
const spirv_cross::SmallVector<spirv_cross::Resource> &resources,
|
||||||
|
const VkShaderStageFlagBits stageFlagBit) {
|
||||||
|
for (auto resource : resources) {
|
||||||
|
unsigned set = glsl.get_decoration(resource.id, spv::DecorationDescriptorSet);
|
||||||
|
unsigned binding = glsl.get_decoration(resource.id, spv::DecorationBinding);
|
||||||
|
|
||||||
|
if (requestedSets.size() <= set) {
|
||||||
|
requestedSets.resize(set + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto &requestSet = requestedSets[set];
|
||||||
|
requestSet.used = true;
|
||||||
|
|
||||||
|
if (requestSet.bindings.size() <= binding) {
|
||||||
|
requestSet.bindings.resize(binding + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto type = glsl.get_type(resource.type_id);
|
||||||
|
|
||||||
|
if (type.basetype == spirv_cross::SPIRType::Image) {
|
||||||
|
requestSet.bindings[binding].type = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE;
|
||||||
|
} else if (type.basetype == spirv_cross::SPIRType::Struct) {
|
||||||
|
requestSet.bindings[binding].type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
|
||||||
|
} else if (type.basetype == spirv_cross::SPIRType::Sampler) {
|
||||||
|
requestSet.bindings[binding].type = VK_DESCRIPTOR_TYPE_SAMPLER;
|
||||||
|
}
|
||||||
|
|
||||||
|
requestSet.bindings[binding].used = true;
|
||||||
|
requestSet.bindings[binding].stageFlags |= stageFlagBit;
|
||||||
|
|
||||||
|
qInfo() << "Requesting set" << set << "at" << binding;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
collectResources(vertex_glsl, vertex_resources.uniform_buffers, VK_SHADER_STAGE_VERTEX_BIT);
|
||||||
|
collectResources(vertex_glsl, vertex_resources.separate_images, VK_SHADER_STAGE_VERTEX_BIT);
|
||||||
|
collectResources(vertex_glsl, vertex_resources.separate_samplers, VK_SHADER_STAGE_VERTEX_BIT);
|
||||||
|
|
||||||
|
collectResources(fragment_glsl, fragment_resources.uniform_buffers, VK_SHADER_STAGE_FRAGMENT_BIT);
|
||||||
|
collectResources(fragment_glsl, fragment_resources.separate_images, VK_SHADER_STAGE_FRAGMENT_BIT);
|
||||||
|
collectResources(fragment_glsl, fragment_resources.separate_samplers, VK_SHADER_STAGE_FRAGMENT_BIT);
|
||||||
|
|
||||||
|
for (auto &set : requestedSets) {
|
||||||
|
if (set.used) {
|
||||||
|
int j = 0;
|
||||||
|
std::vector<VkDescriptorSetLayoutBinding> bindings;
|
||||||
|
for (auto &binding : set.bindings) {
|
||||||
|
if (binding.used) {
|
||||||
|
VkDescriptorSetLayoutBinding boneInfoBufferBinding = {};
|
||||||
|
boneInfoBufferBinding.descriptorType = binding.type;
|
||||||
|
boneInfoBufferBinding.descriptorCount = 1;
|
||||||
|
boneInfoBufferBinding.stageFlags = binding.stageFlags;
|
||||||
|
boneInfoBufferBinding.binding = j;
|
||||||
|
|
||||||
|
bindings.push_back(boneInfoBufferBinding);
|
||||||
|
}
|
||||||
|
j++;
|
||||||
|
}
|
||||||
|
|
||||||
|
VkDescriptorSetLayoutCreateInfo layoutInfo = {};
|
||||||
|
layoutInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
|
||||||
|
layoutInfo.bindingCount = bindings.size();
|
||||||
|
layoutInfo.pBindings = bindings.data();
|
||||||
|
|
||||||
|
vkCreateDescriptorSetLayout(m_renderer.device, &layoutInfo, nullptr, &set.layout);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
VkVertexInputAttributeDescription positionAttribute = {};
|
||||||
|
positionAttribute.format = VK_FORMAT_R32G32B32_SFLOAT;
|
||||||
|
positionAttribute.offset = offsetof(Vertex, position);
|
||||||
|
|
||||||
|
std::vector<VkVertexInputAttributeDescription> attributeDescs;
|
||||||
|
|
||||||
|
for (auto texture : vertex_resources.stage_inputs) {
|
||||||
|
unsigned binding = vertex_glsl.get_decoration(texture.id, spv::DecorationLocation);
|
||||||
|
|
||||||
|
VkVertexInputAttributeDescription uv0Attribute = {};
|
||||||
|
|
||||||
|
auto type = vertex_glsl.get_type(texture.type_id);
|
||||||
|
if (type.basetype == spirv_cross::SPIRType::Int) {
|
||||||
|
switch (type.vecsize) {
|
||||||
|
case 1:
|
||||||
|
uv0Attribute.format = VK_FORMAT_R32_SINT;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
uv0Attribute.format = VK_FORMAT_R32G32_SINT;
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
uv0Attribute.format = VK_FORMAT_R32G32B32_SINT;
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
uv0Attribute.format = VK_FORMAT_R32G32B32A32_SINT;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
switch (type.vecsize) {
|
||||||
|
case 1:
|
||||||
|
uv0Attribute.format = VK_FORMAT_R32_SFLOAT;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
uv0Attribute.format = VK_FORMAT_R32G32_SFLOAT;
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
uv0Attribute.format = VK_FORMAT_R32G32B32_SFLOAT;
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
uv0Attribute.format = VK_FORMAT_R32G32B32A32_SFLOAT;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uv0Attribute.location = binding;
|
||||||
|
uv0Attribute.offset = offsetof(Vertex, position);
|
||||||
|
|
||||||
|
attributeDescs.push_back(uv0Attribute);
|
||||||
|
}
|
||||||
|
|
||||||
|
VkPipelineVertexInputStateCreateInfo vertexInputState = {};
|
||||||
|
vertexInputState.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
|
||||||
|
vertexInputState.vertexBindingDescriptionCount = 1;
|
||||||
|
vertexInputState.pVertexBindingDescriptions = &binding;
|
||||||
|
vertexInputState.vertexAttributeDescriptionCount = attributeDescs.size();
|
||||||
|
vertexInputState.pVertexAttributeDescriptions = attributeDescs.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 = 640.0;
|
||||||
|
viewport.height = 480.0;
|
||||||
|
viewport.maxDepth = 1.0f;
|
||||||
|
|
||||||
|
VkRect2D scissor = {};
|
||||||
|
scissor.extent.width = 640;
|
||||||
|
scissor.extent.height = 480;
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
std::vector<VkPipelineColorBlendAttachmentState> colorBlendAttachments = {colorBlendAttachment, colorBlendAttachment, colorBlendAttachment};
|
||||||
|
|
||||||
|
VkPipelineColorBlendStateCreateInfo colorBlending = {};
|
||||||
|
colorBlending.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
|
||||||
|
colorBlending.attachmentCount = colorBlendAttachments.size();
|
||||||
|
colorBlending.pAttachments = colorBlendAttachments.data();
|
||||||
|
|
||||||
|
VkPipelineDynamicStateCreateInfo dynamicState = {};
|
||||||
|
dynamicState.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO;
|
||||||
|
|
||||||
|
VkPipelineLayoutCreateInfo pipelineLayoutInfo{};
|
||||||
|
pipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
|
||||||
|
// pipelineLayoutInfo.pushConstantRangeCount = 1;
|
||||||
|
// pipelineLayoutInfo.pPushConstantRanges = &pushConstantRange;
|
||||||
|
|
||||||
|
std::vector<VkDescriptorSetLayout> setLayouts;
|
||||||
|
for (auto &set : requestedSets) {
|
||||||
|
if (set.used) {
|
||||||
|
setLayouts.push_back(set.layout);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pipelineLayoutInfo.setLayoutCount = setLayouts.size();
|
||||||
|
pipelineLayoutInfo.pSetLayouts = setLayouts.data();
|
||||||
|
|
||||||
|
VkPipelineLayout pipelineLayout = VK_NULL_HANDLE;
|
||||||
|
vkCreatePipelineLayout(m_renderer.device, &pipelineLayoutInfo, nullptr, &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;
|
||||||
|
|
||||||
|
std::array<VkFormat, 3> colorAttachmentFormats = {VK_FORMAT_B8G8R8A8_UNORM, VK_FORMAT_UNDEFINED, VK_FORMAT_UNDEFINED};
|
||||||
|
|
||||||
|
VkPipelineRenderingCreateInfo pipelineRenderingCreateInfo = {};
|
||||||
|
pipelineRenderingCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO;
|
||||||
|
pipelineRenderingCreateInfo.colorAttachmentCount = 3; // TODO: hardcoded
|
||||||
|
pipelineRenderingCreateInfo.pColorAttachmentFormats = colorAttachmentFormats.data();
|
||||||
|
pipelineRenderingCreateInfo.depthAttachmentFormat = VK_FORMAT_D32_SFLOAT; // TODO: hardcoded
|
||||||
|
|
||||||
|
VkGraphicsPipelineCreateInfo createInfo = {};
|
||||||
|
createInfo.pNext = &pipelineRenderingCreateInfo;
|
||||||
|
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 = pipelineLayout;
|
||||||
|
// createInfo.renderPass = m_renderer.renderPass;
|
||||||
|
|
||||||
|
VkPipeline pipeline = VK_NULL_HANDLE;
|
||||||
|
vkCreateGraphicsPipelines(m_renderer.device, VK_NULL_HANDLE, 1, &createInfo, nullptr, &pipeline);
|
||||||
|
|
||||||
|
qInfo() << "Created" << pipeline << "for hash" << hash;
|
||||||
|
m_cachedPipelines[hash] =
|
||||||
|
CachedPipeline{.pipeline = pipeline, .pipelineLayout = pipelineLayout, .setLayouts = setLayouts, .requestedSets = requestedSets};
|
||||||
|
}
|
||||||
|
|
||||||
|
auto &pipeline = m_cachedPipelines[hash];
|
||||||
|
vkCmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline.pipeline); // TODO: return CachedPipeline&
|
||||||
|
}
|
||||||
|
|
||||||
|
VkShaderModule RenderSystem::convertShaderModule(const physis_Shader &shader, spv::ExecutionModel executionModel)
|
||||||
|
{
|
||||||
|
dxvk::DxbcReader reader(reinterpret_cast<const char *>(shader.bytecode), shader.len);
|
||||||
|
|
||||||
|
dxvk::DxbcModule module(reader);
|
||||||
|
|
||||||
|
dxvk::DxbcModuleInfo info;
|
||||||
|
auto result = module.compile(info, "test");
|
||||||
|
|
||||||
|
VkShaderModuleCreateInfo createInfo = {};
|
||||||
|
createInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
|
||||||
|
createInfo.codeSize = result.code.size();
|
||||||
|
createInfo.pCode = reinterpret_cast<const uint32_t *>(result.code.data());
|
||||||
|
|
||||||
|
VkShaderModule shaderModule;
|
||||||
|
vkCreateShaderModule(m_renderer.device, &createInfo, nullptr, &shaderModule);
|
||||||
|
|
||||||
|
return shaderModule;
|
||||||
|
}
|
||||||
|
|
||||||
|
spirv_cross::CompilerGLSL RenderSystem::getShaderModuleResources(const physis_Shader &shader)
|
||||||
|
{
|
||||||
|
dxvk::DxbcReader reader(reinterpret_cast<const char *>(shader.bytecode), shader.len);
|
||||||
|
|
||||||
|
dxvk::DxbcModule module(reader);
|
||||||
|
|
||||||
|
dxvk::DxbcModuleInfo info;
|
||||||
|
auto result = module.compile(info, "test");
|
||||||
|
;
|
||||||
|
|
||||||
|
// glsl.build_combined_image_samplers();
|
||||||
|
|
||||||
|
return spirv_cross::CompilerGLSL(result.code.data(), result.code.dwords());
|
||||||
|
}
|
||||||
|
|
||||||
|
VkDescriptorSet RenderSystem::createDescriptorFor(const RenderModel &model, const CachedPipeline &pipeline, int i)
|
||||||
|
{
|
||||||
|
VkDescriptorSet set;
|
||||||
|
|
||||||
|
VkDescriptorSetAllocateInfo allocateInfo = {};
|
||||||
|
allocateInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
|
||||||
|
allocateInfo.descriptorPool = m_renderer.descriptorPool;
|
||||||
|
allocateInfo.descriptorSetCount = 1;
|
||||||
|
allocateInfo.pSetLayouts = &pipeline.setLayouts[i];
|
||||||
|
|
||||||
|
vkAllocateDescriptorSets(m_renderer.device, &allocateInfo, &set);
|
||||||
|
if (set == VK_NULL_HANDLE) {
|
||||||
|
// qFatal("Failed to create descriptor set!");
|
||||||
|
return VK_NULL_HANDLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: way too eager
|
||||||
|
std::vector<VkWriteDescriptorSet> writes;
|
||||||
|
std::vector<VkDescriptorBufferInfo> bufferInfo;
|
||||||
|
std::vector<VkDescriptorImageInfo> imageInfo;
|
||||||
|
|
||||||
|
writes.reserve(pipeline.requestedSets[i].bindings.size());
|
||||||
|
bufferInfo.reserve(pipeline.requestedSets[i].bindings.size());
|
||||||
|
imageInfo.reserve(pipeline.requestedSets[i].bindings.size());
|
||||||
|
|
||||||
|
int j = 0;
|
||||||
|
for (auto binding : pipeline.requestedSets[i].bindings) {
|
||||||
|
if (binding.used) {
|
||||||
|
VkWriteDescriptorSet &descriptorWrite = writes.emplace_back();
|
||||||
|
descriptorWrite.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
|
||||||
|
descriptorWrite.descriptorType = binding.type;
|
||||||
|
descriptorWrite.dstSet = set;
|
||||||
|
descriptorWrite.descriptorCount = 1;
|
||||||
|
descriptorWrite.dstBinding = j;
|
||||||
|
|
||||||
|
switch (binding.type) {
|
||||||
|
case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE: {
|
||||||
|
auto info = &imageInfo.emplace_back();
|
||||||
|
descriptorWrite.pImageInfo = info;
|
||||||
|
|
||||||
|
info->imageView = m_renderer.dummyView;
|
||||||
|
info->imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
|
||||||
|
} break;
|
||||||
|
case VK_DESCRIPTOR_TYPE_SAMPLER: {
|
||||||
|
auto info = &imageInfo.emplace_back();
|
||||||
|
descriptorWrite.pImageInfo = info;
|
||||||
|
|
||||||
|
info->sampler = m_renderer.dummySampler;
|
||||||
|
} break;
|
||||||
|
case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER: {
|
||||||
|
auto info = &bufferInfo.emplace_back();
|
||||||
|
descriptorWrite.pBufferInfo = info;
|
||||||
|
|
||||||
|
info->buffer = m_renderer.dummyBuffer;
|
||||||
|
info->range = 655360;
|
||||||
|
} break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
j++;
|
||||||
|
}
|
||||||
|
|
||||||
|
vkUpdateDescriptorSets(m_renderer.device, writes.size(), writes.data(), 0, nullptr);
|
||||||
|
|
||||||
|
return set;
|
||||||
|
}
|
Loading…
Add table
Reference in a new issue