2024-04-20 17:29:29 -04:00
|
|
|
// 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>
|
|
|
|
|
2024-04-21 09:01:02 -04:00
|
|
|
#include <glm/ext/matrix_clip_space.hpp>
|
|
|
|
|
2024-04-21 11:52:30 -04:00
|
|
|
// TODO: maybe need UV?
|
|
|
|
const std::vector<glm::vec4> planeVertices = {
|
2024-04-21 13:04:25 -04:00
|
|
|
{-1.0f, -1.0f, 0.0f, 1.0f},
|
|
|
|
{1.0f, -1.0f, 0.0f, 1.0f},
|
|
|
|
{1.0f, 1.0f, 0.0f, 1.0f},
|
2024-04-21 11:52:30 -04:00
|
|
|
|
2024-04-21 13:04:25 -04:00
|
|
|
{-1.0f, 1.0f, 0.0f, 1.0f},
|
|
|
|
{-1.0f, -1.0f, 0.0f, 1.0f},
|
|
|
|
{1.0f, 1.0f, 0.0f, 1.0f},
|
2024-04-21 11:52:30 -04:00
|
|
|
};
|
|
|
|
|
2024-04-20 17:29:29 -04:00
|
|
|
dxvk::Logger dxvk::Logger::s_instance("dxbc.log");
|
|
|
|
|
2024-04-21 10:30:51 -04:00
|
|
|
const std::array<std::string, 14> passes = {
|
2024-04-20 17:29:29 -04:00
|
|
|
// Shadows?
|
|
|
|
"PASS_0",
|
2024-04-21 13:04:25 -04:00
|
|
|
// Z "prepass"
|
2024-04-20 17:29:29 -04:00
|
|
|
"PASS_Z_OPAQUE",
|
2024-04-21 13:04:25 -04:00
|
|
|
// computes and stores normals (TODO: denote how these normals are special)
|
2024-04-20 17:29:29 -04:00
|
|
|
"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"};
|
|
|
|
|
2024-04-21 10:30:51 -04:00
|
|
|
const int INVALID_PASS = 255;
|
2024-04-20 17:29:29 -04:00
|
|
|
|
|
|
|
RenderSystem::RenderSystem(Renderer &renderer, GameData *data)
|
|
|
|
: m_renderer(renderer)
|
|
|
|
, m_data(data)
|
|
|
|
{
|
2024-04-21 12:00:13 -04:00
|
|
|
normalGBuffer = createImage(640, 480, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT);
|
2024-04-21 13:17:40 -04:00
|
|
|
viewPositionBuffer = createImage(640, 480, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT);
|
2024-04-21 12:00:13 -04:00
|
|
|
|
2024-04-21 11:52:30 -04:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2024-04-21 10:25:52 -04:00
|
|
|
directionalLightningShpk = physis_parse_shpk(physis_gamedata_extract_file(m_data, "shader/sm5/shpk/directionallighting.shpk"));
|
2024-04-21 13:17:40 -04:00
|
|
|
createViewPositionShpk = physis_parse_shpk(physis_gamedata_extract_file(m_data, "shader/sm5/shpk/createviewposition.shpk"));
|
2024-04-21 10:25:52 -04:00
|
|
|
|
2024-04-21 09:01:02 -04:00
|
|
|
// camera data
|
|
|
|
{
|
|
|
|
g_CameraParameter = createUniformBuffer(sizeof(CameraParameter));
|
|
|
|
}
|
|
|
|
|
|
|
|
// joint matrix data
|
|
|
|
{
|
|
|
|
g_JointMatrixArray = createUniformBuffer(sizeof(JointMatrixArray));
|
|
|
|
JointMatrixArray jointMatrixArray{};
|
|
|
|
for (int i = 0; i < 64; i++) {
|
|
|
|
jointMatrixArray.g_JointMatrixArray[i] = glm::mat3x4(1.0f);
|
|
|
|
}
|
|
|
|
copyDataToUniform(g_JointMatrixArray, &jointMatrixArray, sizeof(JointMatrixArray));
|
|
|
|
}
|
|
|
|
|
|
|
|
// instance data
|
|
|
|
{
|
|
|
|
g_InstanceParameter = createUniformBuffer(sizeof(InstanceParameter));
|
|
|
|
|
|
|
|
InstanceParameter instanceParameter{};
|
|
|
|
copyDataToUniform(g_InstanceParameter, &instanceParameter, sizeof(InstanceParameter));
|
|
|
|
}
|
|
|
|
|
|
|
|
// model data
|
|
|
|
{
|
|
|
|
g_ModelParameter = createUniformBuffer(sizeof(ModelParameter));
|
|
|
|
|
|
|
|
ModelParameter modelParameter{};
|
|
|
|
copyDataToUniform(g_ModelParameter, &modelParameter, sizeof(ModelParameter));
|
|
|
|
}
|
|
|
|
|
|
|
|
// material data
|
|
|
|
{
|
|
|
|
g_MaterialParameter = createUniformBuffer(sizeof(MaterialParameter));
|
|
|
|
|
|
|
|
MaterialParameter materialParameter{};
|
|
|
|
materialParameter.g_AlphaThreshold = 0.0f;
|
|
|
|
materialParameter.g_DiffuseColor = glm::vec3(1.0f);
|
|
|
|
copyDataToUniform(g_MaterialParameter, &materialParameter, sizeof(MaterialParameter));
|
|
|
|
}
|
2024-04-21 13:04:25 -04:00
|
|
|
|
|
|
|
// light data
|
|
|
|
{
|
|
|
|
g_LightParam = createUniformBuffer(sizeof(LightParam));
|
|
|
|
|
|
|
|
LightParam lightParam{};
|
|
|
|
lightParam.m_Position = glm::vec4(5);
|
|
|
|
lightParam.m_Direction = glm::normalize(glm::vec4(0) - lightParam.m_Position);
|
|
|
|
lightParam.m_DiffuseColor = glm::vec4(1);
|
|
|
|
lightParam.m_SpecularColor = glm::vec4(1);
|
|
|
|
lightParam.m_Attenuation = glm::vec4(5.0f);
|
|
|
|
/*lightParam.m_ClipMin = glm::vec4(0.0f);
|
|
|
|
lightParam.m_ClipMax = glm::vec4(5.0f);*/
|
|
|
|
|
|
|
|
copyDataToUniform(g_LightParam, &lightParam, sizeof(LightParam));
|
|
|
|
}
|
|
|
|
|
|
|
|
// common data
|
|
|
|
{
|
|
|
|
g_CommonParameter = createUniformBuffer(sizeof(CommonParameter));
|
|
|
|
|
|
|
|
CommonParameter commonParam{};
|
|
|
|
commonParam.m_RenderTarget = {640.0f, 480.0f, 0.0f, 0.0f}; // used to convert screen-space coordinates back into 0.0-1.0
|
|
|
|
|
|
|
|
copyDataToUniform(g_CommonParameter, &commonParam, sizeof(CommonParameter));
|
|
|
|
}
|
2024-04-20 17:29:29 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
void RenderSystem::testInit(::RenderModel *m)
|
|
|
|
{
|
2024-04-21 07:02:34 -04:00
|
|
|
RenderModel model{.shpk = physis_parse_shpk(physis_gamedata_extract_file(m_data, "shader/sm5/shpk/character.shpk")),
|
|
|
|
.internal_model = new ::RenderModel(*m)};
|
2024-04-20 17:29:29 -04:00
|
|
|
m_renderModels.push_back(model);
|
|
|
|
}
|
|
|
|
|
|
|
|
void RenderSystem::render(uint32_t imageIndex, VkCommandBuffer commandBuffer)
|
|
|
|
{
|
2024-04-21 09:01:02 -04:00
|
|
|
// TODO: this shouldn't be here
|
|
|
|
CameraParameter cameraParameter{};
|
|
|
|
|
|
|
|
glm::mat4 projectionMatrix = glm::perspective(glm::radians(45.0f), 640.0f / 480.0f, 0.1f, 1000.0f);
|
|
|
|
glm::mat4 viewMatrix = m_renderer.view;
|
|
|
|
glm::mat4 viewProjectionMatrix = projectionMatrix * viewMatrix;
|
|
|
|
|
2024-04-21 13:29:30 -04:00
|
|
|
cameraParameter.m_ViewMatrix = glm::transpose(viewMatrix);
|
|
|
|
cameraParameter.m_InverseViewMatrix = glm::transpose(glm::inverse(viewMatrix));
|
2024-04-21 09:01:02 -04:00
|
|
|
cameraParameter.m_ViewProjectionMatrix = glm::transpose(viewProjectionMatrix);
|
2024-04-21 13:29:30 -04:00
|
|
|
cameraParameter.m_InverseViewProjectionMatrix = glm::transpose(glm::inverse(viewProjectionMatrix));
|
|
|
|
cameraParameter.m_InverseProjectionMatrix = glm::transpose(glm::inverse(projectionMatrix));
|
|
|
|
cameraParameter.m_ProjectionMatrix = cameraParameter.m_ViewProjectionMatrix;
|
|
|
|
cameraParameter.m_MainViewToProjectionMatrix = cameraParameter.m_InverseViewProjectionMatrix;
|
2024-04-21 09:01:02 -04:00
|
|
|
cameraParameter.m_EyePosition = glm::vec3(5.0f); // placeholder
|
2024-04-21 13:29:30 -04:00
|
|
|
cameraParameter.m_LookAtVector = glm::vec3(0.0f); // placeholder
|
2024-04-21 09:01:02 -04:00
|
|
|
|
|
|
|
copyDataToUniform(g_CameraParameter, &cameraParameter, sizeof(CameraParameter));
|
|
|
|
|
2024-04-20 17:29:29 -04:00
|
|
|
int i = 0;
|
|
|
|
for (const auto pass : passes) {
|
|
|
|
// hardcoded to the known pass for now
|
2024-04-21 13:04:25 -04:00
|
|
|
if (pass == "PASS_G_OPAQUE" || pass == "PASS_Z_OPAQUE") {
|
2024-04-21 13:17:40 -04:00
|
|
|
beginPass(imageIndex, commandBuffer, pass);
|
|
|
|
|
2024-04-20 17:29:29 -04:00
|
|
|
for (auto &model : m_renderModels) {
|
2024-04-21 10:08:55 -04:00
|
|
|
std::vector<uint32_t> systemKeys;
|
|
|
|
std::vector<uint32_t> sceneKeys = {
|
|
|
|
physis_shpk_crc("TransformViewSkin"),
|
|
|
|
physis_shpk_crc("GetAmbientLight_SH"),
|
|
|
|
physis_shpk_crc("GetReflectColor_Texture"),
|
|
|
|
physis_shpk_crc("GetAmbientOcclusion_None"),
|
|
|
|
physis_shpk_crc("ApplyDitherClipOff"),
|
|
|
|
};
|
|
|
|
std::vector<uint32_t> materialKeys;
|
|
|
|
for (int j = 0; j < model.shpk.num_material_keys; j++) {
|
2024-04-21 11:52:30 -04:00
|
|
|
auto value = model.shpk.material_keys[j].default_value;
|
|
|
|
// Replace MODE_DEFAULT with MODE_SIMPLE for now
|
|
|
|
if (value != 0x5CC605B5) {
|
|
|
|
materialKeys.push_back(model.shpk.material_keys[j].default_value);
|
|
|
|
} else {
|
|
|
|
materialKeys.push_back(0x22A4AABF);
|
|
|
|
}
|
2024-04-21 10:08:55 -04:00
|
|
|
}
|
2024-04-21 11:52:30 -04:00
|
|
|
std::vector<uint32_t> subviewKeys = {physis_shpk_crc("Default"), physis_shpk_crc("SUB_VIEW_MAIN")};
|
2024-04-21 10:08:55 -04:00
|
|
|
|
|
|
|
const u_int32_t selector = physis_shpk_build_selector_from_all_keys(systemKeys.data(),
|
|
|
|
systemKeys.size(),
|
|
|
|
sceneKeys.data(),
|
|
|
|
sceneKeys.size(),
|
|
|
|
materialKeys.data(),
|
|
|
|
materialKeys.size(),
|
|
|
|
subviewKeys.data(),
|
|
|
|
subviewKeys.size());
|
2024-04-20 17:29:29 -04:00
|
|
|
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];
|
2024-04-21 10:30:51 -04:00
|
|
|
if (passIndice != INVALID_PASS) {
|
2024-04-20 17:29:29 -04:00
|
|
|
const Pass currentPass = node.passes[passIndice];
|
|
|
|
|
|
|
|
const uint32_t vertexShaderIndice = currentPass.vertex_shader;
|
2024-04-21 11:52:30 -04:00
|
|
|
const uint32_t pixelShaderIndice = currentPass.pixel_shader;
|
2024-04-20 17:29:29 -04:00
|
|
|
|
|
|
|
physis_Shader vertexShader = model.shpk.vertex_shaders[vertexShaderIndice];
|
|
|
|
physis_Shader pixelShader = model.shpk.pixel_shaders[pixelShaderIndice];
|
|
|
|
|
2024-04-21 11:52:30 -04:00
|
|
|
bindPipeline(commandBuffer, pass, vertexShader, pixelShader);
|
2024-04-20 17:29:29 -04:00
|
|
|
|
|
|
|
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);
|
|
|
|
|
|
|
|
vkCmdDrawIndexed(commandBuffer, part.numIndices, 1, 0, 0, 0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2024-04-21 13:17:40 -04:00
|
|
|
|
|
|
|
endPass(commandBuffer, pass);
|
2024-04-21 12:00:13 -04:00
|
|
|
} else if (pass == "PASS_LIGHTING_OPAQUE") {
|
2024-04-21 13:17:40 -04:00
|
|
|
// first we need to generate the view positions with createviewpositions
|
|
|
|
beginPass(imageIndex, commandBuffer, "PASS_LIGHTING_OPAQUE_VIEWPOSITION");
|
|
|
|
{
|
|
|
|
std::vector<uint32_t> systemKeys = {
|
|
|
|
physis_shpk_crc("DecodeDepthBuffer_RAWZ"),
|
|
|
|
};
|
|
|
|
std::vector<uint32_t> subviewKeys = {
|
|
|
|
physis_shpk_crc("Default"),
|
|
|
|
physis_shpk_crc("SUB_VIEW_MAIN"),
|
|
|
|
};
|
|
|
|
|
|
|
|
const u_int32_t selector = physis_shpk_build_selector_from_all_keys(systemKeys.data(),
|
|
|
|
systemKeys.size(),
|
|
|
|
nullptr,
|
|
|
|
0,
|
|
|
|
nullptr,
|
|
|
|
0,
|
|
|
|
subviewKeys.data(),
|
|
|
|
subviewKeys.size());
|
|
|
|
const physis_SHPKNode node = physis_shpk_get_node(&createViewPositionShpk, selector);
|
|
|
|
|
|
|
|
// check if invalid
|
|
|
|
if (node.pass_count == 0) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
const int passIndice = node.pass_indices[i];
|
|
|
|
if (passIndice != INVALID_PASS) {
|
|
|
|
const Pass currentPass = node.passes[passIndice];
|
|
|
|
|
|
|
|
const uint32_t vertexShaderIndice = currentPass.vertex_shader;
|
|
|
|
const uint32_t pixelShaderIndice = currentPass.pixel_shader;
|
|
|
|
|
|
|
|
physis_Shader vertexShader = createViewPositionShpk.vertex_shaders[vertexShaderIndice];
|
|
|
|
physis_Shader pixelShader = createViewPositionShpk.pixel_shaders[pixelShaderIndice];
|
|
|
|
|
|
|
|
bindPipeline(commandBuffer, "PASS_LIGHTING_OPAQUE_VIEWPOSITION", vertexShader, pixelShader);
|
|
|
|
|
|
|
|
VkDeviceSize offsets[] = {0};
|
|
|
|
vkCmdBindVertexBuffers(commandBuffer, 0, 1, &m_planeVertexBuffer, offsets);
|
|
|
|
|
|
|
|
vkCmdDraw(commandBuffer, 6, 1, 0, 0);
|
|
|
|
}
|
2024-04-21 10:25:52 -04:00
|
|
|
}
|
2024-04-21 13:17:40 -04:00
|
|
|
endPass(commandBuffer, pass);
|
|
|
|
|
|
|
|
beginPass(imageIndex, commandBuffer, pass);
|
|
|
|
// then run the directionallighting shader
|
|
|
|
{
|
|
|
|
std::vector<uint32_t> systemKeys = {
|
|
|
|
physis_shpk_crc("DecodeDepthBuffer_RAWZ"),
|
|
|
|
};
|
|
|
|
std::vector<uint32_t> sceneKeys = {
|
|
|
|
physis_shpk_crc("GetDirectionalLight_Enable"),
|
|
|
|
physis_shpk_crc("GetFakeSpecular_Disable"),
|
|
|
|
physis_shpk_crc("GetUnderWaterLighting_Disable"),
|
|
|
|
};
|
|
|
|
std::vector<uint32_t> subviewKeys = {
|
|
|
|
physis_shpk_crc("Default"),
|
|
|
|
physis_shpk_crc("SUB_VIEW_MAIN"),
|
|
|
|
};
|
|
|
|
|
|
|
|
const u_int32_t selector = physis_shpk_build_selector_from_all_keys(systemKeys.data(),
|
|
|
|
systemKeys.size(),
|
|
|
|
sceneKeys.data(),
|
|
|
|
sceneKeys.size(),
|
|
|
|
nullptr,
|
|
|
|
0,
|
|
|
|
subviewKeys.data(),
|
|
|
|
subviewKeys.size());
|
|
|
|
const physis_SHPKNode node = physis_shpk_get_node(&directionalLightningShpk, selector);
|
|
|
|
|
|
|
|
// check if invalid
|
|
|
|
if (node.pass_count == 0) {
|
|
|
|
continue;
|
|
|
|
}
|
2024-04-21 10:25:52 -04:00
|
|
|
|
2024-04-21 13:17:40 -04:00
|
|
|
const int passIndice = node.pass_indices[i];
|
|
|
|
if (passIndice != INVALID_PASS) {
|
|
|
|
const Pass currentPass = node.passes[passIndice];
|
2024-04-21 10:25:52 -04:00
|
|
|
|
2024-04-21 13:17:40 -04:00
|
|
|
const uint32_t vertexShaderIndice = currentPass.vertex_shader;
|
|
|
|
const uint32_t pixelShaderIndice = currentPass.pixel_shader;
|
2024-04-21 10:25:52 -04:00
|
|
|
|
2024-04-21 13:17:40 -04:00
|
|
|
physis_Shader vertexShader = directionalLightningShpk.vertex_shaders[vertexShaderIndice];
|
|
|
|
physis_Shader pixelShader = directionalLightningShpk.pixel_shaders[pixelShaderIndice];
|
2024-04-21 10:25:52 -04:00
|
|
|
|
2024-04-21 13:17:40 -04:00
|
|
|
bindPipeline(commandBuffer, pass, vertexShader, pixelShader);
|
2024-04-21 11:52:30 -04:00
|
|
|
|
2024-04-21 13:17:40 -04:00
|
|
|
VkDeviceSize offsets[] = {0};
|
|
|
|
vkCmdBindVertexBuffers(commandBuffer, 0, 1, &m_planeVertexBuffer, offsets);
|
2024-04-21 11:52:30 -04:00
|
|
|
|
2024-04-21 13:17:40 -04:00
|
|
|
vkCmdDraw(commandBuffer, 6, 1, 0, 0);
|
|
|
|
}
|
2024-04-21 10:25:52 -04:00
|
|
|
}
|
2024-04-21 13:17:40 -04:00
|
|
|
endPass(commandBuffer, pass);
|
2024-04-20 17:29:29 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void RenderSystem::setSize(uint32_t width, uint32_t height)
|
|
|
|
{
|
|
|
|
m_extent = {width, height};
|
2024-04-21 13:17:40 -04:00
|
|
|
// 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();
|
|
|
|
}
|
2024-04-20 17:29:29 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
void RenderSystem::beginPass(uint32_t imageIndex, VkCommandBuffer commandBuffer, const std::string_view passName)
|
|
|
|
{
|
2024-04-21 11:52:30 -04:00
|
|
|
VkRenderingInfo renderingInfo{VK_STRUCTURE_TYPE_RENDERING_INFO};
|
2024-04-20 17:29:29 -04:00
|
|
|
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};
|
2024-04-21 12:00:13 -04:00
|
|
|
attachmentInfo.imageView = normalGBuffer.imageView;
|
2024-04-21 11:52:30 -04:00
|
|
|
attachmentInfo.imageLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; // VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL
|
2024-04-20 17:29:29 -04:00
|
|
|
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;
|
|
|
|
}
|
2024-04-21 11:52:30 -04:00
|
|
|
} else if (passName == "PASS_LIGHTING_OPAQUE") {
|
|
|
|
// normals, it seems like
|
|
|
|
{
|
|
|
|
VkRenderingAttachmentInfo attachmentInfo{VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO};
|
|
|
|
attachmentInfo.imageView = m_renderer.swapchainViews[imageIndex];
|
|
|
|
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;
|
|
|
|
|
|
|
|
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
|
|
|
|
{
|
|
|
|
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;
|
|
|
|
|
2024-04-21 13:17:40 -04:00
|
|
|
colorAttachments.push_back(attachmentInfo);
|
|
|
|
}
|
|
|
|
} else if (passName == "PASS_LIGHTING_OPAQUE_VIEWPOSITION") {
|
|
|
|
// 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.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;
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
2024-04-21 11:52:30 -04:00
|
|
|
colorAttachments.push_back(attachmentInfo);
|
|
|
|
}
|
2024-04-21 13:04:25 -04:00
|
|
|
} else if (passName == "PASS_Z_OPAQUE") {
|
|
|
|
// normals, it seems like
|
|
|
|
{
|
|
|
|
VkRenderingAttachmentInfo attachmentInfo{VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO};
|
|
|
|
attachmentInfo.imageView = m_renderer.swapchainViews[imageIndex];
|
|
|
|
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;
|
|
|
|
|
|
|
|
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
|
|
|
|
{
|
|
|
|
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);
|
|
|
|
}
|
2024-04-20 17:29:29 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
renderingInfo.layerCount = 1;
|
|
|
|
renderingInfo.pColorAttachments = colorAttachments.data();
|
|
|
|
renderingInfo.colorAttachmentCount = colorAttachments.size();
|
|
|
|
|
|
|
|
if (depthStencilAttachment.imageView != VK_NULL_HANDLE) {
|
|
|
|
renderingInfo.pDepthAttachment = &depthStencilAttachment;
|
|
|
|
}
|
|
|
|
|
|
|
|
vkCmdBeginRendering(commandBuffer, &renderingInfo);
|
|
|
|
}
|
|
|
|
|
2024-04-21 11:52:30 -04:00
|
|
|
void RenderSystem::endPass(VkCommandBuffer commandBuffer, std::string_view passName)
|
2024-04-20 17:29:29 -04:00
|
|
|
{
|
|
|
|
vkCmdEndRendering(commandBuffer);
|
|
|
|
}
|
|
|
|
|
2024-04-21 11:52:30 -04:00
|
|
|
void RenderSystem::bindPipeline(VkCommandBuffer commandBuffer, std::string_view passName, physis_Shader &vertexShader, physis_Shader &pixelShader)
|
2024-04-20 17:29:29 -04:00
|
|
|
{
|
2024-04-21 11:52:30 -04:00
|
|
|
const uint32_t hash = vertexShader.len + pixelShader.len + physis_shpk_crc(passName.data());
|
2024-04-20 17:29:29 -04:00
|
|
|
if (!m_cachedPipelines.contains(hash)) {
|
|
|
|
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;
|
2024-04-21 11:52:30 -04:00
|
|
|
fragmentShaderStageInfo.module = fragmentShaderModule; // m_renderer.loadShaderFromDisk(":/shaders/dummy.frag.spv");
|
2024-04-20 17:29:29 -04:00
|
|
|
fragmentShaderStageInfo.pName = "main";
|
|
|
|
|
|
|
|
std::array<VkPipelineShaderStageCreateInfo, 2> shaderStages = {vertexShaderStageInfo, fragmentShaderStageInfo};
|
|
|
|
|
|
|
|
VkVertexInputBindingDescription binding = {};
|
2024-04-21 11:52:30 -04:00
|
|
|
|
|
|
|
// TODO: temporary
|
2024-04-21 13:04:25 -04:00
|
|
|
if (passName == "PASS_G_OPAQUE" || passName == "PASS_Z_OPAQUE") {
|
2024-04-21 11:52:30 -04:00
|
|
|
binding.stride = sizeof(Vertex);
|
2024-04-21 13:17:40 -04:00
|
|
|
} else if (passName == "PASS_LIGHTING_OPAQUE" || passName == "PASS_LIGHTING_OPAQUE_VIEWPOSITION") {
|
2024-04-21 11:52:30 -04:00
|
|
|
binding.stride = sizeof(glm::vec4);
|
|
|
|
}
|
2024-04-20 17:29:29 -04:00
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
std::vector<VkVertexInputAttributeDescription> attributeDescs;
|
|
|
|
|
|
|
|
for (auto texture : vertex_resources.stage_inputs) {
|
|
|
|
unsigned binding = vertex_glsl.get_decoration(texture.id, spv::DecorationLocation);
|
|
|
|
|
2024-04-21 09:01:02 -04:00
|
|
|
auto name = vertex_glsl.get_name(texture.id);
|
|
|
|
|
2024-04-20 17:29:29 -04:00
|
|
|
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:
|
2024-04-21 09:01:02 -04:00
|
|
|
uv0Attribute.format = VK_FORMAT_R8G8B8A8_UINT; // supposed to be VK_FORMAT_R32G32B32A32_SINT, but our bone_id is uint8_t currently
|
2024-04-20 17:29:29 -04:00
|
|
|
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;
|
2024-04-21 09:01:02 -04:00
|
|
|
|
|
|
|
// TODO: temporary
|
|
|
|
if (name == "v0") {
|
|
|
|
uv0Attribute.offset = offsetof(Vertex, position);
|
|
|
|
} else if (name == "v1") {
|
|
|
|
uv0Attribute.offset = offsetof(Vertex, color);
|
|
|
|
} else if (name == "v2") {
|
|
|
|
uv0Attribute.offset = offsetof(Vertex, normal);
|
|
|
|
} else if (name == "v3") {
|
|
|
|
uv0Attribute.offset = offsetof(Vertex, uv0);
|
|
|
|
} else if (name == "v4") {
|
|
|
|
uv0Attribute.offset = offsetof(Vertex, bitangent); // FIXME: should be tangent
|
|
|
|
} else if (name == "v5") {
|
|
|
|
uv0Attribute.offset = offsetof(Vertex, bitangent);
|
|
|
|
} else if (name == "v6") {
|
|
|
|
uv0Attribute.offset = offsetof(Vertex, bone_weight);
|
|
|
|
} else if (name == "v7") {
|
|
|
|
uv0Attribute.offset = offsetof(Vertex, bone_id);
|
|
|
|
}
|
2024-04-20 17:29:29 -04:00
|
|
|
|
|
|
|
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;
|
2024-04-21 13:04:25 -04:00
|
|
|
rasterizer.cullMode = VK_CULL_MODE_NONE; // TODO: implement cull mode
|
2024-04-20 17:29:29 -04:00
|
|
|
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;
|
|
|
|
|
2024-04-21 11:52:30 -04:00
|
|
|
std::vector<VkPipelineColorBlendAttachmentState> colorBlendAttachments;
|
|
|
|
|
|
|
|
int colorAttachmentCount = 1;
|
|
|
|
// TODO: hardcoded, should be a reusable function to get the color attachments
|
|
|
|
if (passName == "PASS_G_OPAQUE") {
|
|
|
|
colorAttachmentCount = 3;
|
|
|
|
} else if (passName == "PASS_LIGHTING_OPAQUE") {
|
|
|
|
colorAttachmentCount = 2;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (int i = 0; i < colorAttachmentCount; i++) {
|
|
|
|
colorBlendAttachments.push_back(colorBlendAttachment);
|
|
|
|
}
|
2024-04-20 17:29:29 -04:00
|
|
|
|
|
|
|
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;
|
2024-04-21 09:01:02 -04:00
|
|
|
m_cachedPipelines[hash] = CachedPipeline{.pipeline = pipeline,
|
|
|
|
.pipelineLayout = pipelineLayout,
|
|
|
|
.setLayouts = setLayouts,
|
|
|
|
.requestedSets = requestedSets,
|
|
|
|
.vertexShader = vertexShader,
|
|
|
|
.pixelShader = pixelShader};
|
2024-04-20 17:29:29 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
auto &pipeline = m_cachedPipelines[hash];
|
|
|
|
vkCmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline.pipeline); // TODO: return CachedPipeline&
|
2024-04-21 11:52:30 -04:00
|
|
|
|
|
|
|
int i = 0;
|
|
|
|
for (auto setLayout : pipeline.setLayouts) {
|
|
|
|
if (!pipeline.cachedDescriptors.count(i)) {
|
|
|
|
if (auto descriptor = createDescriptorFor(pipeline, i); descriptor != VK_NULL_HANDLE) {
|
|
|
|
pipeline.cachedDescriptors[i] = descriptor;
|
|
|
|
} else {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// TODO: we can pass all descriptors in one function call
|
|
|
|
vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline.pipelineLayout, i, 1, &pipeline.cachedDescriptors[i], 0, nullptr);
|
|
|
|
|
|
|
|
i++;
|
|
|
|
}
|
2024-04-20 17:29:29 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
2024-04-21 09:01:02 -04:00
|
|
|
// TODO: for debug only
|
|
|
|
spirv_cross::CompilerGLSL glsl(result.code.data(), result.code.dwords());
|
|
|
|
|
|
|
|
auto resources = glsl.get_shader_resources();
|
|
|
|
|
|
|
|
int i = 0;
|
|
|
|
for (auto texture : resources.stage_inputs) {
|
|
|
|
// glsl.set_name(texture.id, shader.)
|
|
|
|
// qInfo() << shader.resource_parameters[i].name << texture.id;
|
|
|
|
// qInfo() << "stage input" << i << texture.name << glsl.get_type(texture.type_id).width;
|
|
|
|
i++;
|
|
|
|
// glsl.set_name(remap.combined_id, "SPIRV_Cross_Combined");
|
|
|
|
}
|
|
|
|
|
|
|
|
// Here you can also set up decorations if you want (binding = #N).
|
|
|
|
i = 0;
|
|
|
|
for (auto texture : resources.separate_images) {
|
|
|
|
glsl.set_name(texture.id, shader.resource_parameters[i].name);
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
|
|
|
|
i = 0;
|
|
|
|
for (auto buffer : resources.uniform_buffers) {
|
|
|
|
glsl.set_name(buffer.id, shader.scalar_parameters[i].name);
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
|
|
|
|
spirv_cross::CompilerGLSL::Options options;
|
|
|
|
options.vulkan_semantics = true;
|
|
|
|
options.enable_420pack_extension = false;
|
|
|
|
glsl.set_common_options(options);
|
|
|
|
glsl.set_entry_point("main", executionModel);
|
|
|
|
|
|
|
|
qInfo() << "Compiled GLSL:" << glsl.compile().c_str();
|
|
|
|
|
2024-04-20 17:29:29 -04:00
|
|
|
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());
|
|
|
|
}
|
|
|
|
|
2024-04-21 11:52:30 -04:00
|
|
|
VkDescriptorSet RenderSystem::createDescriptorFor(const CachedPipeline &pipeline, int i)
|
2024-04-20 17:29:29 -04:00
|
|
|
{
|
|
|
|
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;
|
2024-04-21 09:01:02 -04:00
|
|
|
int z = 0;
|
2024-04-21 13:04:25 -04:00
|
|
|
int p = 0;
|
|
|
|
VkShaderStageFlags currentStageFlags;
|
2024-04-20 17:29:29 -04:00
|
|
|
for (auto binding : pipeline.requestedSets[i].bindings) {
|
|
|
|
if (binding.used) {
|
2024-04-21 13:04:25 -04:00
|
|
|
// a giant hack
|
|
|
|
if (currentStageFlags != binding.stageFlags) {
|
|
|
|
z = 0;
|
|
|
|
p = 0;
|
|
|
|
currentStageFlags = binding.stageFlags;
|
|
|
|
}
|
|
|
|
|
2024-04-20 17:29:29 -04:00
|
|
|
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;
|
|
|
|
|
2024-04-21 13:04:25 -04:00
|
|
|
if (binding.stageFlags == VK_SHADER_STAGE_FRAGMENT_BIT && p < 4) {
|
|
|
|
auto name = pipeline.pixelShader.resource_parameters[p].name;
|
|
|
|
qInfo() << "Requesting image" << name << "at" << j;
|
|
|
|
if (strcmp(name, "g_SamplerGBuffer") == 0) {
|
|
|
|
info->imageView = normalGBuffer.imageView;
|
|
|
|
} else if (strcmp(name, "g_SamplerViewPosition") == 0) {
|
2024-04-21 13:17:40 -04:00
|
|
|
info->imageView = viewPositionBuffer.imageView;
|
|
|
|
} else if (strcmp(name, "g_SamplerDepth") == 0) {
|
|
|
|
info->imageView = m_renderer.depthView;
|
2024-04-21 13:04:25 -04:00
|
|
|
} else {
|
|
|
|
info->imageView = m_renderer.dummyView;
|
|
|
|
}
|
|
|
|
|
|
|
|
p++;
|
|
|
|
} else {
|
|
|
|
info->imageView = m_renderer.dummyView;
|
|
|
|
}
|
|
|
|
|
2024-04-20 17:29:29 -04:00
|
|
|
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;
|
|
|
|
|
2024-04-21 09:01:02 -04:00
|
|
|
auto useUniformBuffer = [&info](UniformBuffer &buffer) {
|
|
|
|
info->buffer = buffer.buffer;
|
|
|
|
info->range = buffer.size;
|
|
|
|
};
|
|
|
|
|
2024-04-21 13:04:25 -04:00
|
|
|
auto bindBuffer = [this, &useUniformBuffer, &info, j](const char *name) {
|
2024-04-21 09:01:02 -04:00
|
|
|
qInfo() << "Requesting" << name << "at" << j;
|
|
|
|
|
|
|
|
if (strcmp(name, "g_CameraParameter") == 0) {
|
|
|
|
useUniformBuffer(g_CameraParameter);
|
|
|
|
} else if (strcmp(name, "g_JointMatrixArray") == 0) {
|
|
|
|
useUniformBuffer(g_JointMatrixArray);
|
|
|
|
} else if (strcmp(name, "g_InstanceParameter") == 0) {
|
|
|
|
useUniformBuffer(g_InstanceParameter);
|
|
|
|
} else if (strcmp(name, "g_ModelParameter") == 0) {
|
|
|
|
useUniformBuffer(g_ModelParameter);
|
2024-04-21 13:04:25 -04:00
|
|
|
} else if (strcmp(name, "g_MaterialParameter") == 0) {
|
|
|
|
useUniformBuffer(g_MaterialParameter);
|
|
|
|
} else if (strcmp(name, "g_LightParam") == 0) {
|
|
|
|
useUniformBuffer(g_LightParam);
|
|
|
|
} else if (strcmp(name, "g_CommonParameter") == 0) {
|
|
|
|
useUniformBuffer(g_CommonParameter);
|
2024-04-21 09:01:02 -04:00
|
|
|
} else {
|
|
|
|
qInfo() << "Unknown resource:" << name;
|
|
|
|
info->buffer = m_renderer.dummyBuffer;
|
|
|
|
info->range = 655360;
|
|
|
|
}
|
2024-04-21 13:04:25 -04:00
|
|
|
};
|
|
|
|
|
|
|
|
if (binding.stageFlags == VK_SHADER_STAGE_VERTEX_BIT) {
|
|
|
|
auto name = pipeline.vertexShader.scalar_parameters[z].name;
|
|
|
|
|
|
|
|
bindBuffer(name);
|
|
|
|
z++;
|
|
|
|
} else if (binding.stageFlags == VK_SHADER_STAGE_FRAGMENT_BIT) {
|
|
|
|
auto name = pipeline.pixelShader.scalar_parameters[z].name;
|
2024-04-21 09:01:02 -04:00
|
|
|
|
2024-04-21 13:04:25 -04:00
|
|
|
bindBuffer(name);
|
2024-04-21 09:01:02 -04:00
|
|
|
z++;
|
|
|
|
} else {
|
|
|
|
// placeholder buffer so it at least doesn't crash
|
|
|
|
info->buffer = m_renderer.dummyBuffer;
|
|
|
|
info->range = 655360;
|
|
|
|
}
|
2024-04-20 17:29:29 -04:00
|
|
|
} break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
j++;
|
|
|
|
}
|
|
|
|
|
|
|
|
vkUpdateDescriptorSets(m_renderer.device, writes.size(), writes.data(), 0, nullptr);
|
|
|
|
|
|
|
|
return set;
|
2024-04-21 09:01:02 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
RenderSystem::UniformBuffer RenderSystem::createUniformBuffer(size_t size)
|
|
|
|
{
|
|
|
|
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);
|
|
|
|
}
|
2024-04-21 12:00:13 -04:00
|
|
|
|
|
|
|
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};
|
|
|
|
}
|