2024-04-20 17:29:29 -04:00
// SPDX-FileCopyrightText: 2024 Joshua Goins <josh@redstrate.com>
// SPDX-License-Identifier: GPL-3.0-or-later
2024-04-21 17:35:48 -04:00
# include "gamerenderer.h"
2024-04-20 17:29:29 -04:00
# include <array>
# include <QDebug>
2024-04-21 17:35:48 -04:00
# include <glm/ext/matrix_clip_space.hpp>
2024-04-20 17:29:29 -04:00
# include <physis.hpp>
2024-04-21 17:35:48 -04:00
# include <spirv_glsl.hpp>
2024-04-20 17:29:29 -04:00
2024-04-21 17:35:48 -04:00
# include "camera.h"
2024-04-20 17:29:29 -04:00
# include "dxbc_module.h"
# include "dxbc_reader.h"
2024-04-21 17:35:48 -04:00
# include "rendermanager.h"
# include "swapchain.h"
2024-04-21 09:01:02 -04:00
2024-04-21 11:52:30 -04:00
// TODO: maybe need UV?
2024-04-21 14:12:56 -04:00
// note: SQEX passes the vertice positions as UV coordinates (yes, -1 to 1.) the shaders then transform them back with the g_CommonParameter.m_RenderTarget vec4
2024-04-21 11:52:30 -04:00
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
2024-04-21 17:35:48 -04:00
GameRenderer : : GameRenderer ( Device & device , GameData * data )
: m_device ( device )
2024-04-20 17:29:29 -04:00
, m_data ( data )
{
2024-04-21 17:35:48 -04:00
m_dummyTex = m_device . createDummyTexture ( ) ;
m_dummyBuffer = m_device . createDummyBuffer ( ) ;
2024-04-21 11:52:30 -04:00
2024-04-21 17:35:48 -04:00
size_t vertexSize = planeVertices . size ( ) * sizeof ( glm : : vec4 ) ;
m_planeVertexBuffer = m_device . createBuffer ( vertexSize , VK_BUFFER_USAGE_VERTEX_BUFFER_BIT ) ;
m_device . copyToBuffer ( m_planeVertexBuffer , ( void * ) planeVertices . data ( ) , vertexSize ) ;
2024-04-21 11:52:30 -04:00
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
{
2024-04-21 17:35:48 -04:00
g_CameraParameter = m_device . createBuffer ( sizeof ( CameraParameter ) , VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT ) ;
2024-04-21 09:01:02 -04:00
}
// instance data
{
2024-04-21 17:35:48 -04:00
g_InstanceParameter = m_device . createBuffer ( sizeof ( InstanceParameter ) , VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT ) ;
2024-04-21 09:01:02 -04:00
InstanceParameter instanceParameter { } ;
2024-04-21 17:35:48 -04:00
m_device . copyToBuffer ( g_InstanceParameter , & instanceParameter , sizeof ( InstanceParameter ) ) ;
2024-04-21 09:01:02 -04:00
}
// model data
{
2024-04-21 17:35:48 -04:00
g_ModelParameter = m_device . createBuffer ( sizeof ( ModelParameter ) , VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT ) ;
2024-04-21 09:01:02 -04:00
ModelParameter modelParameter { } ;
2024-04-21 17:35:48 -04:00
m_device . copyToBuffer ( g_ModelParameter , & modelParameter , sizeof ( ModelParameter ) ) ;
2024-04-21 09:01:02 -04:00
}
// material data
{
2024-04-21 17:35:48 -04:00
g_MaterialParameter = m_device . createBuffer ( sizeof ( MaterialParameter ) , VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT ) ;
2024-04-21 09:01:02 -04:00
MaterialParameter materialParameter { } ;
materialParameter . g_AlphaThreshold = 0.0f ;
materialParameter . g_DiffuseColor = glm : : vec3 ( 1.0f ) ;
2024-04-21 17:35:48 -04:00
m_device . copyToBuffer ( g_MaterialParameter , & materialParameter , sizeof ( MaterialParameter ) ) ;
2024-04-21 09:01:02 -04:00
}
2024-04-21 13:04:25 -04:00
// light data
{
2024-04-21 17:35:48 -04:00
g_LightParam = m_device . createBuffer ( sizeof ( LightParam ) , VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT ) ;
2024-04-21 13:04:25 -04:00
LightParam lightParam { } ;
2024-04-21 14:05:41 -04:00
lightParam . m_Position = glm : : vec4 ( - 5 ) ;
2024-04-21 13:04:25 -04:00
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 ) ; */
2024-04-21 17:35:48 -04:00
m_device . copyToBuffer ( g_LightParam , & lightParam , sizeof ( LightParam ) ) ;
2024-04-21 13:04:25 -04:00
}
// common data
{
2024-04-21 17:35:48 -04:00
g_CommonParameter = m_device . createBuffer ( sizeof ( CommonParameter ) , VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT ) ;
2024-04-21 13:04:25 -04:00
}
2024-04-21 14:11:40 -04:00
2024-04-21 17:35:48 -04:00
VkSamplerCreateInfo samplerInfo = { } ;
samplerInfo . sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO ;
samplerInfo . magFilter = VK_FILTER_LINEAR ;
samplerInfo . minFilter = VK_FILTER_LINEAR ;
samplerInfo . addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT ;
samplerInfo . addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT ;
samplerInfo . addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT ;
samplerInfo . mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR ;
samplerInfo . maxLod = 1.0f ;
vkCreateSampler ( m_device . device , & samplerInfo , nullptr , & m_sampler ) ;
2024-04-21 14:11:40 -04:00
createImageResources ( ) ;
2024-04-20 17:29:29 -04:00
}
2024-04-21 17:35:48 -04:00
void GameRenderer : : addDrawObject ( const DrawObject & drawObject )
2024-04-20 17:29:29 -04:00
{
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 " ) ) ,
2024-04-21 17:35:48 -04:00
. internal_model = new DrawObject ( drawObject ) } ;
2024-04-20 17:29:29 -04:00
m_renderModels . push_back ( model ) ;
}
2024-04-21 18:49:48 -04:00
void GameRenderer : : render ( VkCommandBuffer commandBuffer , uint32_t imageIndex , Camera & camera , const std : : vector < DrawObject > & models )
2024-04-20 17:29:29 -04:00
{
2024-04-21 09:01:02 -04:00
// TODO: this shouldn't be here
CameraParameter cameraParameter { } ;
2024-04-21 17:35:48 -04:00
const glm : : mat4 viewProjectionMatrix = camera . perspective * camera . view ;
2024-04-21 09:01:02 -04:00
2024-04-21 17:35:48 -04:00
cameraParameter . m_ViewMatrix = glm : : transpose ( camera . view ) ;
cameraParameter . m_InverseViewMatrix = glm : : transpose ( glm : : inverse ( camera . view ) ) ;
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 ) ) ;
2024-04-21 14:05:41 -04:00
// known params
cameraParameter . m_InverseProjectionMatrix = glm : : transpose ( glm : : inverse ( viewProjectionMatrix ) ) ;
cameraParameter . m_ProjectionMatrix = glm : : transpose ( viewProjectionMatrix ) ;
2024-04-21 17:35:48 -04:00
cameraParameter . m_MainViewToProjectionMatrix = glm : : transpose ( glm : : inverse ( camera . perspective ) ) ;
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
2024-04-21 17:35:48 -04:00
m_device . copyToBuffer ( g_CameraParameter , & cameraParameter , sizeof ( CameraParameter ) ) ;
2024-04-21 09:01:02 -04:00
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-21 18:49:48 -04:00
for ( auto & model : models ) {
std : : optional < GameRenderer : : RenderModel > renderModel ;
// FIXME: this is terrible
auto it = std : : find_if ( m_renderModels . begin ( ) , m_renderModels . end ( ) , [ & model ] ( const RenderModel & a_model ) {
return model . model . p_ptr = = a_model . internal_model - > model . p_ptr ;
} ) ;
if ( it ! = m_renderModels . end ( ) ) {
renderModel = * it ;
}
if ( ! renderModel . has_value ( ) ) {
continue ;
}
// copy bone data
{
const size_t bufferSize = sizeof ( glm : : mat3x4 ) * 64 ;
void * mapped_data = nullptr ;
vkMapMemory ( m_device . device , model . boneInfoBuffer . memory , 0 , bufferSize , 0 , & mapped_data ) ;
std : : vector < glm : : mat3x4 > newBoneData ( model . boneData . size ( ) ) ;
for ( int i = 0 ; i < 64 ; i + + ) {
newBoneData [ i ] = model . boneData [ i ] ;
}
memcpy ( mapped_data , newBoneData . data ( ) , bufferSize ) ;
VkMappedMemoryRange range = { } ;
range . sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE ;
range . memory = model . boneInfoBuffer . memory ;
range . size = bufferSize ;
vkFlushMappedMemoryRanges ( m_device . device , 1 , & range ) ;
vkUnmapMemory ( m_device . device , model . boneInfoBuffer . memory ) ;
}
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 ;
2024-04-21 18:49:48 -04:00
for ( int j = 0 ; j < renderModel - > shpk . num_material_keys ; j + + ) {
auto value = renderModel - > shpk . material_keys [ j ] . default_value ;
2024-04-21 11:52:30 -04:00
// Replace MODE_DEFAULT with MODE_SIMPLE for now
if ( value ! = 0x5CC605B5 ) {
2024-04-21 18:49:48 -04:00
materialKeys . push_back ( renderModel - > shpk . material_keys [ j ] . default_value ) ;
2024-04-21 11:52:30 -04:00
} 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-21 18:49:48 -04:00
const physis_SHPKNode node = physis_shpk_get_node ( & renderModel - > shpk , selector ) ;
2024-04-20 17:29:29 -04:00
// 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
2024-04-21 18:49:48 -04:00
physis_Shader vertexShader = renderModel - > shpk . vertex_shaders [ vertexShaderIndice ] ;
physis_Shader pixelShader = renderModel - > shpk . pixel_shaders [ pixelShaderIndice ] ;
2024-04-20 17:29:29 -04:00
2024-04-21 18:49:48 -04:00
auto & pipeline = bindPipeline ( commandBuffer , pass , vertexShader , pixelShader ) ;
bindDescriptorSets ( commandBuffer , pipeline , & renderModel . value ( ) ) ;
2024-04-20 17:29:29 -04:00
2024-04-21 18:49:48 -04:00
for ( const auto & part : renderModel - > internal_model - > parts ) {
2024-04-20 17:29:29 -04:00
VkDeviceSize offsets [ ] = { 0 } ;
2024-04-21 17:35:48 -04:00
vkCmdBindVertexBuffers ( commandBuffer , 0 , 1 , & part . vertexBuffer . buffer , offsets ) ;
vkCmdBindIndexBuffer ( commandBuffer , part . indexBuffer . buffer , 0 , VK_INDEX_TYPE_UINT16 ) ;
2024-04-20 17:29:29 -04:00
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 ] ;
2024-04-21 18:49:48 -04:00
auto & pipeline = bindPipeline ( commandBuffer , " PASS_LIGHTING_OPAQUE_VIEWPOSITION " , vertexShader , pixelShader ) ;
bindDescriptorSets ( commandBuffer , pipeline , nullptr ) ;
2024-04-21 13:17:40 -04:00
VkDeviceSize offsets [ ] = { 0 } ;
2024-04-21 17:35:48 -04:00
vkCmdBindVertexBuffers ( commandBuffer , 0 , 1 , & m_planeVertexBuffer . buffer , offsets ) ;
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 ) ;
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 18:49:48 -04:00
auto & pipeline = bindPipeline ( commandBuffer , pass , vertexShader , pixelShader ) ;
bindDescriptorSets ( commandBuffer , pipeline , nullptr ) ;
2024-04-21 11:52:30 -04:00
2024-04-21 13:17:40 -04:00
VkDeviceSize offsets [ ] = { 0 } ;
2024-04-21 17:35:48 -04:00
vkCmdBindVertexBuffers ( commandBuffer , 0 , 1 , & m_planeVertexBuffer . buffer , 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 + + ;
}
}
2024-04-21 17:35:48 -04:00
void GameRenderer : : resize ( )
2024-04-20 17:29:29 -04:00
{
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-21 14:11:40 -04:00
createImageResources ( ) ;
2024-04-20 17:29:29 -04:00
}
2024-04-21 17:35:48 -04:00
void GameRenderer : : beginPass ( uint32_t imageIndex , VkCommandBuffer commandBuffer , const std : : string_view passName )
2024-04-20 17:29:29 -04:00
{
2024-04-21 11:52:30 -04:00
VkRenderingInfo renderingInfo { VK_STRUCTURE_TYPE_RENDERING_INFO } ;
2024-04-21 17:35:48 -04:00
renderingInfo . renderArea . extent = m_device . swapChain - > extent ;
2024-04-20 17:29:29 -04:00
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 17:35:48 -04:00
attachmentInfo . imageView = m_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 } ;
2024-04-21 17:35:48 -04:00
attachmentInfo . imageView = m_depthBuffer . imageView ;
2024-04-20 17:29:29 -04:00
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 } ;
2024-04-21 17:35:48 -04:00
attachmentInfo . imageView = m_compositeBuffer . imageView ;
2024-04-21 11:52:30 -04:00
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 } ;
2024-04-21 17:35:48 -04:00
attachmentInfo . imageView = m_viewPositionBuffer . imageView ;
2024-04-21 13:17:40 -04:00
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 } ;
2024-04-21 17:35:48 -04:00
attachmentInfo . imageView = m_compositeBuffer . imageView ;
2024-04-21 13:04:25 -04:00
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 17:35:48 -04:00
void GameRenderer : : endPass ( VkCommandBuffer commandBuffer , std : : string_view passName )
2024-04-20 17:29:29 -04:00
{
vkCmdEndRendering ( commandBuffer ) ;
}
2024-04-21 18:49:48 -04:00
GameRenderer : : CachedPipeline &
GameRenderer : : 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 ( ) ;
2024-04-21 17:35:48 -04:00
vkCreateDescriptorSetLayout ( m_device . device , & layoutInfo , nullptr , & set . layout ) ;
2024-04-20 17:29:29 -04:00
}
}
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 ;
VkPipelineViewportStateCreateInfo viewportState = { } ;
viewportState . sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO ;
viewportState . viewportCount = 1 ;
viewportState . scissorCount = 1 ;
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 ( ) ;
2024-04-21 14:11:40 -04:00
std : : vector < VkDynamicState > dynamicStates = { VK_DYNAMIC_STATE_VIEWPORT , VK_DYNAMIC_STATE_SCISSOR } ;
2024-04-20 17:29:29 -04:00
VkPipelineDynamicStateCreateInfo dynamicState = { } ;
dynamicState . sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO ;
2024-04-21 14:11:40 -04:00
dynamicState . dynamicStateCount = dynamicStates . size ( ) ;
dynamicState . pDynamicStates = dynamicStates . data ( ) ;
2024-04-20 17:29:29 -04:00
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 ;
2024-04-21 17:35:48 -04:00
vkCreatePipelineLayout ( m_device . device , & pipelineLayoutInfo , nullptr , & pipelineLayout ) ;
2024-04-20 17:29:29 -04:00
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 ;
2024-04-21 17:35:48 -04:00
vkCreateGraphicsPipelines ( m_device . device , VK_NULL_HANDLE , 1 , & createInfo , nullptr , & pipeline ) ;
2024-04-20 17:29:29 -04:00
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 ] ;
2024-04-21 18:49:48 -04:00
vkCmdBindPipeline ( commandBuffer , VK_PIPELINE_BIND_POINT_GRAPHICS , pipeline . pipeline ) ;
2024-04-21 14:11:40 -04:00
VkViewport viewport = { } ;
2024-04-21 17:35:48 -04:00
viewport . width = m_device . swapChain - > extent . width ;
viewport . height = m_device . swapChain - > extent . height ;
2024-04-21 14:11:40 -04:00
viewport . maxDepth = 1.0f ;
VkRect2D scissor = { } ;
2024-04-21 17:35:48 -04:00
scissor . extent = m_device . swapChain - > extent ;
2024-04-21 14:11:40 -04:00
vkCmdSetViewport ( commandBuffer , 0 , 1 , & viewport ) ;
vkCmdSetScissor ( commandBuffer , 0 , 1 , & scissor ) ;
2024-04-21 18:49:48 -04:00
return pipeline ;
2024-04-20 17:29:29 -04:00
}
2024-04-21 17:35:48 -04:00
VkShaderModule GameRenderer : : convertShaderModule ( const physis_Shader & shader , spv : : ExecutionModel executionModel )
2024-04-20 17:29:29 -04:00
{
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 ;
2024-04-21 17:35:48 -04:00
vkCreateShaderModule ( m_device . device , & createInfo , nullptr , & shaderModule ) ;
2024-04-20 17:29:29 -04:00
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 ;
}
2024-04-21 17:35:48 -04:00
spirv_cross : : CompilerGLSL GameRenderer : : getShaderModuleResources ( const physis_Shader & shader )
2024-04-20 17:29:29 -04:00
{
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 18:49:48 -04:00
VkDescriptorSet GameRenderer : : createDescriptorFor ( const RenderModel * object , 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 ;
2024-04-21 17:35:48 -04:00
allocateInfo . descriptorPool = m_device . descriptorPool ;
2024-04-20 17:29:29 -04:00
allocateInfo . descriptorSetCount = 1 ;
allocateInfo . pSetLayouts = & pipeline . setLayouts [ i ] ;
2024-04-21 17:35:48 -04:00
vkAllocateDescriptorSets ( m_device . device , & allocateInfo , & set ) ;
2024-04-20 17:29:29 -04:00
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 ) {
2024-04-21 17:35:48 -04:00
info - > imageView = m_normalGBuffer . imageView ;
2024-04-21 13:04:25 -04:00
} else if ( strcmp ( name , " g_SamplerViewPosition " ) = = 0 ) {
2024-04-21 17:35:48 -04:00
info - > imageView = m_viewPositionBuffer . imageView ;
2024-04-21 13:17:40 -04:00
} else if ( strcmp ( name , " g_SamplerDepth " ) = = 0 ) {
2024-04-21 17:35:48 -04:00
info - > imageView = m_depthBuffer . imageView ;
2024-04-21 13:04:25 -04:00
} else {
2024-04-21 17:35:48 -04:00
info - > imageView = m_dummyTex . imageView ;
2024-04-21 13:04:25 -04:00
}
p + + ;
} else {
2024-04-21 17:35:48 -04:00
info - > imageView = m_dummyTex . imageView ;
2024-04-21 13:04:25 -04:00
}
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 ;
2024-04-21 17:35:48 -04:00
info - > sampler = m_sampler ;
2024-04-20 17:29:29 -04:00
} break ;
case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER : {
auto info = & bufferInfo . emplace_back ( ) ;
descriptorWrite . pBufferInfo = info ;
2024-04-21 18:49:48 -04:00
auto useUniformBuffer = [ & info ] ( const Buffer & buffer ) {
2024-04-21 09:01:02 -04:00
info - > buffer = buffer . buffer ;
info - > range = buffer . size ;
} ;
2024-04-21 18:49:48 -04:00
auto bindBuffer = [ this , & useUniformBuffer , & info , j , & object ] ( 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 ) {
2024-04-21 18:49:48 -04:00
Q_ASSERT ( object ! = nullptr ) ;
useUniformBuffer ( object - > internal_model - > boneInfoBuffer ) ;
2024-04-21 09:01:02 -04:00
} 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 ;
2024-04-21 17:35:48 -04:00
info - > buffer = m_dummyBuffer . buffer ;
2024-04-21 09:01:02 -04:00
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
2024-04-21 17:35:48 -04:00
info - > buffer = m_dummyBuffer . buffer ;
2024-04-21 09:01:02 -04:00
info - > range = 655360 ;
}
2024-04-20 17:29:29 -04:00
} break ;
}
}
j + + ;
}
2024-04-21 17:35:48 -04:00
vkUpdateDescriptorSets ( m_device . device , writes . size ( ) , writes . data ( ) , 0 , nullptr ) ;
2024-04-20 17:29:29 -04:00
return set ;
2024-04-21 09:01:02 -04:00
}
2024-04-21 17:35:48 -04:00
void GameRenderer : : createImageResources ( )
2024-04-21 09:01:02 -04:00
{
2024-04-21 17:35:48 -04:00
m_normalGBuffer = m_device . createTexture ( m_device . swapChain - > extent . width ,
m_device . swapChain - > extent . height ,
VK_FORMAT_R8G8B8A8_UNORM ,
VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT ) ;
m_viewPositionBuffer = m_device . createTexture ( m_device . swapChain - > extent . width ,
m_device . swapChain - > extent . height ,
VK_FORMAT_R8G8B8A8_UNORM ,
VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT ) ;
m_compositeBuffer = m_device . createTexture ( m_device . swapChain - > extent . width ,
m_device . swapChain - > extent . height ,
VK_FORMAT_R8G8B8A8_UNORM ,
VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT ) ;
m_depthBuffer = m_device . createTexture ( m_device . swapChain - > extent . width ,
m_device . swapChain - > extent . height ,
VK_FORMAT_D32_SFLOAT ,
VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT ) ;
2024-04-21 09:01:02 -04:00
2024-04-21 17:35:48 -04:00
CommonParameter commonParam { } ;
commonParam . m_RenderTarget = { 1.0f / m_device . swapChain - > extent . width ,
1.0f / m_device . swapChain - > extent . height ,
0.0f ,
0.0f } ; // used to convert screen-space coordinates back into 0.0-1.0
2024-04-21 09:01:02 -04:00
2024-04-21 17:35:48 -04:00
m_device . copyToBuffer ( g_CommonParameter , & commonParam , sizeof ( CommonParameter ) ) ;
2024-04-21 09:01:02 -04:00
}
2024-04-21 12:00:13 -04:00
2024-04-21 17:35:48 -04:00
Texture & GameRenderer : : getCompositeTexture ( )
2024-04-21 12:00:13 -04:00
{
2024-04-21 17:35:48 -04:00
return m_compositeBuffer ;
2024-04-21 14:11:40 -04:00
}
2024-04-21 18:49:48 -04:00
void GameRenderer : : bindDescriptorSets ( VkCommandBuffer commandBuffer , GameRenderer : : CachedPipeline & pipeline , const RenderModel * object )
{
int i = 0 ;
for ( auto setLayout : pipeline . setLayouts ) {
if ( ! pipeline . cachedDescriptors . count ( i ) ) {
if ( auto descriptor = createDescriptorFor ( object , 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 + + ;
}
}