diff --git a/.gitattributes b/.gitattributes index 777757fb..8430d034 100644 --- a/.gitattributes +++ b/.gitattributes @@ -3,4 +3,5 @@ **/*.lib filter=lfs diff=lfs merge=lfs -text **/*.pdb filter=lfs diff=lfs merge=lfs -text **/*.so filter=lfs diff=lfs merge=lfs -text -**/linux-x64/** filter=lfs diff=lfs merge=lfs -text \ No newline at end of file +**/linux-x64/** filter=lfs diff=lfs merge=lfs -text +resources/texture/*.jpg filter=lfs diff=lfs merge=lfs -text diff --git a/resources/texture/grid.jpg b/resources/texture/grid.jpg new file mode 100644 index 00000000..282145d7 --- /dev/null +++ b/resources/texture/grid.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c7cae23ffecc5e679169be1dedbb2b3238aa893449bf3a8b6e1a8fc879ac01d6 +size 13558 diff --git a/resources/texture/sample.jpg b/resources/texture/sample.jpg index 975e3380..b4983568 100644 Binary files a/resources/texture/sample.jpg and b/resources/texture/sample.jpg differ diff --git a/src/Graphics/Instance.cpp b/src/Graphics/Instance.cpp index e918f677..0762465d 100644 --- a/src/Graphics/Instance.cpp +++ b/src/Graphics/Instance.cpp @@ -89,11 +89,7 @@ Instance::Instance(App* app) : #endif // Instance Creation -#ifdef VK_API_VERSION_1_1 - m_ApiVersion = m_Context.enumerateInstanceVersion(); // TODO: potential crash -#else - m_ApiVersion = VK_API_VERSION_1_0; -#endif + m_ApiVersion = VK_API_VERSION_1_3; std::vector enabledInstanceExtensions = BuildEnabledExtensions(instanceExtensionProperties, m_EnabledInstanceExtensions); diff --git a/src/Rendering/BindGroup.h b/src/Rendering/BindGroup.h index 5ad7720b..bfe27922 100644 --- a/src/Rendering/BindGroup.h +++ b/src/Rendering/BindGroup.h @@ -33,6 +33,15 @@ struct TextureBinding final SamplerHandle samplerHandle = {}; }; +/// @brief Texture binding for bindless textures +struct ArrayTexturesBinding final +{ + uint32_t binding = 0; + uint32_t count = 0; + std::vector handles = {}; + TextureUsageBits usage = TextureUsageBits::Sampled; +}; + /// @brief Buffer handle with byte offset struct BufferBinding final { diff --git a/src/Rendering/BindLayout.h b/src/Rendering/BindLayout.h index e1902544..720dcb87 100644 --- a/src/Rendering/BindLayout.h +++ b/src/Rendering/BindLayout.h @@ -25,7 +25,7 @@ struct Binding final { uint8_t binding = 0; BindType type = BindType::UniformBuffer; - uint8_t descriptorCount = 1; + uint16_t descriptorCount = 1; ShaderStage stage = ShaderStage::Vertex; }; diff --git a/src/Rendering/GraphicsCaps.cpp b/src/Rendering/GraphicsCaps.cpp index ad6be596..20b48bc5 100644 --- a/src/Rendering/GraphicsCaps.cpp +++ b/src/Rendering/GraphicsCaps.cpp @@ -1,10 +1,18 @@ #include "GraphicsCaps.h" +#include "Graphics/Graphics.h" namespace gore::gfx { -void InitVulkanGraphicsCaps(GraphicsCaps& caps, vk::Instance instance, vk::PhysicalDevice physicalDevice) +void InitVulkanGraphicsCaps(GraphicsCaps& caps, Instance& instance, Device& device) { - vk::PhysicalDeviceProperties deviceProperties = physicalDevice.getProperties(); + uint32_t vulkanMinorVersion = VK_API_VERSION_MINOR(instance.Version()); + + vk::PhysicalDeviceProperties deviceProperties = device.GetPhysicalDevice().Get().getProperties(); caps.minUniformBufferOffsetAlignment = deviceProperties.limits.minUniformBufferOffsetAlignment; + + // Check for bindless support, which is available in Vulkan 1.2 and later + // Note: This is a simplified check. In a real application, you would want to check for specific features + // but if the device cannot support vulkan 1.2, it cannot support bindless. + caps.supportsBindless = vulkanMinorVersion >= 2; } } // namespace gore::gfx \ No newline at end of file diff --git a/src/Rendering/GraphicsCaps.h b/src/Rendering/GraphicsCaps.h index 6071e997..7eb16587 100644 --- a/src/Rendering/GraphicsCaps.h +++ b/src/Rendering/GraphicsCaps.h @@ -3,10 +3,15 @@ namespace gore::gfx { +class Instance; +class Device; + struct GraphicsCaps { size_t minUniformBufferOffsetAlignment = 0; + + bool supportsBindless = false; }; -void InitVulkanGraphicsCaps(GraphicsCaps& caps, vk::Instance instance, vk::PhysicalDevice physicalDevice); +void InitVulkanGraphicsCaps(GraphicsCaps& caps, Instance& instance, Device& device); } // namespace gore::gfx \ No newline at end of file diff --git a/src/Rendering/RenderContext.cpp b/src/Rendering/RenderContext.cpp index 82a80796..56377729 100644 --- a/src/Rendering/RenderContext.cpp +++ b/src/Rendering/RenderContext.cpp @@ -64,8 +64,10 @@ BindLayout RenderContext::GetOrCreateBindLayout(const BindLayoutCreateInfo& crea return it->second; } - BindLayout bindLayout; + bool isBindless = false; + std::vector bindings; + std::vector bindingFlags; for (const auto& binding : createInfo.bindings) { vk::DescriptorSetLayoutBinding layoutBinding( @@ -76,9 +78,26 @@ BindLayout RenderContext::GetOrCreateBindLayout(const BindLayoutCreateInfo& crea nullptr); bindings.push_back(layoutBinding); + + isBindless |= (binding.descriptorCount > 1); + bindingFlags.push_back(binding.descriptorCount > 1 ? vk::DescriptorBindingFlagBits::ePartiallyBound : vk::DescriptorBindingFlags()); } + + auto layoutCreateInfo = vk::DescriptorSetLayoutCreateInfo() + .setBindingCount(static_cast(bindings.size())) + .setPBindings(bindings.data()); + + auto layoutBindingCreateFlagsInfo = vk::DescriptorSetLayoutBindingFlagsCreateInfo() + .setBindingCount(static_cast(bindingFlags.size())) + .setPBindingFlags(bindingFlags.data()); - bindLayout.layout = VULKAN_DEVICE.createDescriptorSetLayout({{}, static_cast(bindings.size()), bindings.data()}); + if (isBindless) + { + layoutCreateInfo.setPNext(&layoutBindingCreateFlagsInfo); + } + + BindLayout bindLayout; + bindLayout.layout = VULKAN_DEVICE.createDescriptorSetLayout(layoutCreateInfo); SetObjectDebugName(bindLayout.layout, createInfo.name != nullptr ? createInfo.name : "NoName_BindLayout"); diff --git a/src/Rendering/RenderSystem.cpp b/src/Rendering/RenderSystem.cpp index 09aa58d6..558e7584 100644 --- a/src/Rendering/RenderSystem.cpp +++ b/src/Rendering/RenderSystem.cpp @@ -108,7 +108,7 @@ void RenderSystem::Initialize() m_Swapchain = m_Device.CreateSwapchain(window->GetNativeHandle(), swapchainCount, static_cast(width), static_cast(height)); m_Device.SetName(m_Swapchain.Get(), "Main Swapchain"); - InitVulkanGraphicsCaps(m_GraphicsCaps, *m_Instance.Get(), *m_Device.GetPhysicalDevice().Get()); + InitVulkanGraphicsCaps(m_GraphicsCaps, m_Instance, m_Device); RenderContextCreateInfo renderContextCreateInfo = {}; renderContextCreateInfo.device = &m_Device; @@ -148,6 +148,7 @@ void RenderSystem::Initialize() CreateTextureObjects(); CreateGlobalDescriptorSets(); + CreateMaterialDescriptorSets(); CreateShadowPassObject(); CreateUVQuadDescriptorSets(); CreateDynamicUniformBuffer(); @@ -1184,6 +1185,39 @@ void RenderSystem::CreateGlobalDescriptorSets() }); } +void RenderSystem::CreateMaterialDescriptorSets() +{ + std::vector bindings { + {0, BindType::SampledImage, 256, ShaderStage::Fragment}, + {1, BindType::Sampler, 1, ShaderStage::Fragment} + }; + + BindLayoutCreateInfo bindLayoutCreateInfo = + { + .name = "Bindless Material Descriptor Set Layout", + .bindings = bindings + }; + + m_BindlessMaterialBinding.bindLayout = m_RenderContext->GetOrCreateBindLayout(bindLayoutCreateInfo); + + m_BindlessMaterialBinding.albedoSampler = m_RenderContext->CreateSampler({ + .debugName = "Bindless Material Sampler" + }); + + m_BindlessMaterialBinding.bindGroup = m_RenderContext->CreateBindGroup({ + .debugName = "Bindless Material BindGroup", + .updateFrequency = UpdateFrequency::Persistent, + .textures = { + {0, m_DefaultResources.whiteTexture, TextureUsageBits::Sampled, 0}, + {0, m_DefaultResources.blackTexture, TextureUsageBits::Sampled, 1}, + {0, m_DefaultResources.gridTexture, TextureUsageBits::Sampled, 2}, + {0, m_UVCheckTextureHandle, TextureUsageBits::Sampled, 3}}, + .buffers = {}, + .samplers = {{1, m_BindlessMaterialBinding.albedoSampler}}, + .bindLayout = &m_BindlessMaterialBinding.bindLayout, + }); +} + void RenderSystem:: CreateUVQuadDescriptorSets() { std::vector bindings { @@ -1551,7 +1585,7 @@ void RenderSystem::CreateRpsPipelines() {.byteOffset = 0, .format = GraphicsFormat::RGB32_FLOAT}, {.byteOffset = 12, .format = GraphicsFormat::RG32_FLOAT}, {.byteOffset = 20, .format = GraphicsFormat::RGB32_FLOAT}}}}, - .bindLayouts = { m_GlobalBindLayout, m_ShadowPassBindLayout }, + .bindLayouts = { m_GlobalBindLayout, m_ShadowPassBindLayout, m_BindlessMaterialBinding.bindLayout }, .dynamicBuffer = m_DynamicBufferHandle, .renderPass = forwardPass.GetRenderPass().renderPass, .subpassIndex = 0 @@ -1601,11 +1635,13 @@ void RenderSystem::CreateRpsPipelines() .bindGroup = {m_GlobalBindGroup}, }); - forwardMat.AddPass(Pass{ - .name = "ForwardPass", - .shader = m_RpsPipelines.forwardPipeline, - .bindGroup = {m_GlobalBindGroup}, - }); + Pass forwardOpaquePass; + forwardOpaquePass.name = "ForwardPass"; + forwardOpaquePass.shader = m_RpsPipelines.forwardPipeline; + forwardOpaquePass.bindGroup[0] = m_GlobalBindGroup; + forwardOpaquePass.bindGroup[2] = m_BindlessMaterialBinding.bindGroup; + + forwardMat.AddPass(forwardOpaquePass); } void RenderSystem::CreateDefaultResources() @@ -1632,6 +1668,8 @@ void RenderSystem::CreateDefaultResources() .data = whiteTextureData.data(), .dataSize = 4, }); + + m_DefaultResources.gridTexture = m_RenderContext->CreateTextureHandle("grid.jpg"); } void RenderSystem::UpdateGlobalConstantBuffer() @@ -1718,4 +1756,3 @@ void RenderSystem::ResetPerFrameDescriptorPool() m_RenderContext->ResetDescriptorPool(UpdateFrequency::PerFrame); } } // namespace gore - diff --git a/src/Rendering/RenderSystem.h b/src/Rendering/RenderSystem.h index f7951b08..06b5a8a6 100644 --- a/src/Rendering/RenderSystem.h +++ b/src/Rendering/RenderSystem.h @@ -200,6 +200,7 @@ ENGINE_CLASS(RenderSystem) final : System { TextureHandle whiteTexture; TextureHandle blackTexture; + TextureHandle gridTexture; } m_DefaultResources; void CreateDefaultResources(); @@ -241,6 +242,15 @@ ENGINE_CLASS(RenderSystem) final : System BindGroupHandle m_GlobalBindGroup; BufferHandle m_GlobalConstantBuffer; + // Material Binding + struct MaterialBinding + { + SamplerHandle albedoSampler; + + BindLayout bindLayout; + BindGroupHandle bindGroup; + } m_BindlessMaterialBinding; + // Pass Binding BindLayout m_ShadowPassBindLayout; SamplerHandle m_ShadowmapSamplerHandler; @@ -276,6 +286,7 @@ ENGINE_CLASS(RenderSystem) final : System void CreateSwapchain(uint32_t imageCount, uint32_t width, uint32_t height); void CreateDepthBuffer(); void CreateGlobalDescriptorSets(); + void CreateMaterialDescriptorSets(); void CreateShadowPassObject(); void CreateUVQuadDescriptorSets(); void CreateDynamicUniformBuffer(); diff --git a/src/Shaders/ShaderLibrary/BindlessMaterial.hlsl b/src/Shaders/ShaderLibrary/BindlessMaterial.hlsl new file mode 100644 index 00000000..76d9f5d8 --- /dev/null +++ b/src/Shaders/ShaderLibrary/BindlessMaterial.hlsl @@ -0,0 +1,8 @@ +#pragma once +#include "Core/Common.hlsl" + + +ARRAY_TEXTURES(MATERIAL, 0, _Albedo, float4); +SAMPLER(MATERIAL, 1, _AlbedoSampler); +// ARRAY_TEXTURES(MATERIAL, 1, _Normal, float4); +// ARRAY_TEXTURES(MATERIAL, 2, _Mask, float4); \ No newline at end of file diff --git a/src/Shaders/ShaderLibrary/Core/Common.hlsl b/src/Shaders/ShaderLibrary/Core/Common.hlsl index 768bd3c5..d6d25b2f 100644 --- a/src/Shaders/ShaderLibrary/Core/Common.hlsl +++ b/src/Shaders/ShaderLibrary/Core/Common.hlsl @@ -1,5 +1,6 @@ // WORKAROUND: would add api macro to shader compiler in the future #define VULKAN_API (1) +#define SUPPORT_BINDLESS (1) #ifndef GORE_COMMON #define GORE_COMMON diff --git a/src/Shaders/ShaderLibrary/Core/Shadow.hlsl b/src/Shaders/ShaderLibrary/Core/Shadow.hlsl deleted file mode 100644 index 7b9637ef..00000000 --- a/src/Shaders/ShaderLibrary/Core/Shadow.hlsl +++ /dev/null @@ -1 +0,0 @@ -#pragma once \ No newline at end of file diff --git a/src/Shaders/ShaderLibrary/Core/VulkanBinding.hlsl b/src/Shaders/ShaderLibrary/Core/VulkanBinding.hlsl index 784aae6e..7c00add8 100644 --- a/src/Shaders/ShaderLibrary/Core/VulkanBinding.hlsl +++ b/src/Shaders/ShaderLibrary/Core/VulkanBinding.hlsl @@ -25,4 +25,5 @@ COMBINED_IMAGE_SAMPLER DESCRIPTOR_SET_BINDING(Binding, Region##_BINDING_DESCRIPT #define SAMPLER(Region, Binding, SamplerName) DESCRIPTOR_SET_BINDING(Binding, Region##_BINDING_DESCRIPTOR_SET) HLSL_SAMPLER(SamplerName) +#define ARRAY_TEXTURES(Region, Binding, ArrayTextureName, Format) DESCRIPTOR_SET_BINDING(Binding, Region##_BINDING_DESCRIPTOR_SET) HLSL_ARRAY_TEXTURES(ArrayTextureName, Format) #endif \ No newline at end of file diff --git a/src/Shaders/ShaderLibrary/Core/VulkanVariables.hlsl b/src/Shaders/ShaderLibrary/Core/VulkanVariables.hlsl index 4ca2f47a..2bef1530 100644 --- a/src/Shaders/ShaderLibrary/Core/VulkanVariables.hlsl +++ b/src/Shaders/ShaderLibrary/Core/VulkanVariables.hlsl @@ -10,4 +10,12 @@ #define SAMPLE_TEXTURE_2D(TextureName, UV) TextureName.Sample(TextureName##Sampler, UV) #define SAMPLE_TEXTURE_2D_SAMPLER(TextureName, SamplerName, UV) TextureName.Sample(SamplerName, UV) +#if SUPPORT_BINDLESS + #define HLSL_ARRAY_TEXTURES(ArrayTextureName, Format) Texture2D ArrayTextureName[] + #define LOAD_ARRAY_TEXTURES(ArrayTextureName, Index) ArrayTextureName[Index] +#else + #define HLSL_ARRAY_TEXTURES(ArrayTextureName, Format) Texture2D ArrayTextureName + #define LOAD_ARRAY_TEXTURES(ArrayTextureName, Index) ArrayTextureName +#endif + #endif \ No newline at end of file diff --git a/src/Shaders/sample/SimpleLit.hlsl b/src/Shaders/sample/SimpleLit.hlsl index 58e230cb..a7198667 100644 --- a/src/Shaders/sample/SimpleLit.hlsl +++ b/src/Shaders/sample/SimpleLit.hlsl @@ -1,5 +1,6 @@ #include "../ShaderLibrary/GlobalBinding.hlsl" #include "../ShaderLibrary/ShadowPassBinding.hlsl" +#include "../ShaderLibrary/BindlessMaterial.hlsl" struct Attributes { @@ -48,6 +49,7 @@ float4 ps(Varyings v) : SV_Target0 float shadowMapDepth = _DirectionalShadowmap.Sample(_DirectionalShadowmapSampler, shadowCoord.xy).r; float shadowFactor = shadowCoord.z < shadowMapDepth ? 1.0f : 0.0f; - // Return the shadow factor as the output color - return float4(shadowFactor, shadowFactor, shadowFactor, 1.0f); + Texture2D albedo = LOAD_ARRAY_TEXTURES(_Albedo, 3); + + return albedo.Sample(_AlbedoSampler, uv); } \ No newline at end of file