diff --git a/.github/workflows/Build_Win64_DX12.yml b/.github/workflows/Build_Win64_DX12.yml index 577c65ee5..16b300a17 100644 --- a/.github/workflows/Build_Win64_DX12.yml +++ b/.github/workflows/Build_Win64_DX12.yml @@ -151,4 +151,64 @@ jobs: git add -f "bin\x64\Final_DX12\renderer.dll" git commit -m "$commitMessage" - git push \ No newline at end of file + git push + + - name: Send Discord Notification + env: + DISCORD_WEBHOOK_URL: ${{ secrets.DISCORD_WEBHOOK_URL }} + run: | + $versionContent = Get-Content "src/version.h" + $major, $minor, $patch = "", "", "" + + foreach ($line in $versionContent) { + if ($line -match '#define VG_FRAMEWORK_VERSION_MAJOR (\d+)') { + $major = $matches[1] + } elseif ($line -match '#define VG_FRAMEWORK_VERSION_MINOR (\d+)') { + $minor = $matches[1] + } elseif ($line -match '#define VG_FRAMEWORK_VERSION_PATCH (\d+)') { + $patch = $matches[1] + } + } + + $fullVersion = "$major.$minor.$patch" + + $commitContent = Get-Content "src/commit.h" + $gitRevision = "" + + foreach ($line in $commitContent) { + if ($line -like '*#define GIT_REVISION*') { + $parts = $line -split '"' + $gitRevision = $parts[1] + break + } + } + + $jsonPayload = @" + { + "username": "GitHub", + "content": "", + "embeds": [ + { + "type": "rich", + "title": "VGFramework $fullVersion ($gitRevision)", + "description": "A new version of VGFramework is available", + "color": 15579707, + "thumbnail": { + "url": "https://github.com/vimontgames/vgframework/blob/master/doc/img/newversion.png?raw=true" + }, + "author": { + "name": "$($env:GITHUB_ACTOR)", + "url": "https://github.com/$($env:GITHUB_ACTOR)", + "icon_url": "https://avatars.githubusercontent.com/u/$($env:GITHUB_ACTOR_ID)?v=4" + }, + "url": "https://github.com/vimontgames/vgframework" + } + ] + } + "@ + + # Send the notification using curl + $RESPONSE = curl -H "Content-Type: application/json" -X POST -d $jsonPayload $WEBHOOK_URL + + # Output the response from the server + Write-Output "Webhook server response: $RESPONSE" diff --git a/doc/img/newversion.png b/doc/img/newversion.png new file mode 100644 index 000000000..d0ca26296 Binary files /dev/null and b/doc/img/newversion.png differ diff --git a/src/engine/World/World.cpp b/src/engine/World/World.cpp index 9e764d72d..b34835dfb 100644 --- a/src/engine/World/World.cpp +++ b/src/engine/World/World.cpp @@ -52,6 +52,8 @@ namespace vg::engine VG_SAFE_RELEASE(m_physicsWorld); VG_SAFE_RELEASE(m_environmentCubemap); + VG_SAFE_RELEASE(m_irradianceCubemap); + VG_SAFE_RELEASE(m_specularReflectionCubemap); VG_SAFE_DELETE(m_debugDrawData); for (uint j = 0; j < enumCount(); ++j) @@ -419,8 +421,8 @@ namespace vg::engine // Reset cubemap VG_SAFE_RELEASE_ASYNC(m_environmentCubemap); - VG_SAFE_RELEASE_ASYNC(m_irradianceCubemap); - VG_SAFE_RELEASE_ASYNC(m_specularReflectionCubemap); + //VG_SAFE_RELEASE_ASYNC(m_irradianceCubemap); + //VG_SAFE_RELEASE_ASYNC(m_specularReflectionCubemap); // Use default ambient m_irradianceIntensity = options->GetDefaultIrradianceIntensity(); diff --git a/src/gfx/Resource/Texture.h b/src/gfx/Resource/Texture.h index aa02b58ef..490f612e3 100644 --- a/src/gfx/Resource/Texture.h +++ b/src/gfx/Resource/Texture.h @@ -49,8 +49,9 @@ namespace vg::gfx gfx::BindlessTextureHandle m_stencilTextureHandle; }; }; - - gfx::BindlessRWTextureHandle m_rwTextureHandle; + + // [slice][mip] + core::vector> m_rwTextureHandles; }; } } diff --git a/src/gfx/Resource/Texture.hpp b/src/gfx/Resource/Texture.hpp index 7359814c2..9570ac416 100644 --- a/src/gfx/Resource/Texture.hpp +++ b/src/gfx/Resource/Texture.hpp @@ -186,7 +186,14 @@ namespace vg::gfx bindlessTable->freeBindlessTextureHandle(m_textureHandle); } - if (m_rwTextureHandle.isValid()) - bindlessTable->freeBindlessRWTextureHandle(m_rwTextureHandle); + for (uint s = 0; s < m_rwTextureHandles.size(); ++s) + { + for (uint m = 0; m < m_rwTextureHandles[s].size(); ++m) + { + auto & rwTextureHandle = m_rwTextureHandles[s][m]; + if (rwTextureHandle.isValid()) + bindlessTable->freeBindlessRWTextureHandle(rwTextureHandle); + } + } } } \ No newline at end of file diff --git a/src/gfx/Resource/Texture.inl b/src/gfx/Resource/Texture.inl index 3462f4ae7..456d1976f 100644 --- a/src/gfx/Resource/Texture.inl +++ b/src/gfx/Resource/Texture.inl @@ -47,8 +47,9 @@ namespace vg::gfx //-------------------------------------------------------------------------------------- VG_INLINE const gfx::BindlessRWTextureHandle Texture::getRWTextureHandle() const { - VG_ASSERT(m_rwTextureHandle.isValid()); - return m_rwTextureHandle; + const auto & rwTextureHandle = m_rwTextureHandles[0][0]; + VG_ASSERT(rwTextureHandle.isValid()); + return rwTextureHandle; } //-------------------------------------------------------------------------------------- diff --git a/src/gfx/Resource/dx12/Texture_dx12.hpp b/src/gfx/Resource/dx12/Texture_dx12.hpp index 77130489d..73e94f7c9 100644 --- a/src/gfx/Resource/dx12/Texture_dx12.hpp +++ b/src/gfx/Resource/dx12/Texture_dx12.hpp @@ -433,19 +433,57 @@ namespace vg::gfx::dx12 VG_ASSERT_ENUM_NOT_IMPLEMENTED(_texDesc.type); break; + case TextureType::TextureCube: + { + VG_ASSERT(_texDesc.slices == 6); + + m_rwTextureHandles.resize(_texDesc.slices); + for (uint s = 0; s < _texDesc.slices; ++s) + m_rwTextureHandles[s].resize(_texDesc.mipmaps); + + for (uint s = 0; s < _texDesc.slices; ++s) + { + for (uint m = 0; m < _texDesc.mipmaps; ++m) + { + BindlessTable * bindlessTable = device->getBindlessTable(); + auto rwTextureHandle = bindlessTable->allocBindlessRWTextureHandle(static_cast(this)); + D3D12_CPU_DESCRIPTOR_HANDLE d3d12RWTextureDescriptorHandle = bindlessTable->getd3d12CPUDescriptorHandle(rwTextureHandle); + + D3D12_UNORDERED_ACCESS_VIEW_DESC uavDesc; + uavDesc.Format = getd3d12ResourceFormat(_texDesc.format); + uavDesc.ViewDimension = D3D12_UAV_DIMENSION_TEXTURE2D; + uavDesc.Texture2D.MipSlice = m; + uavDesc.Texture2D.PlaneSlice = 0; + d3d12device->CreateUnorderedAccessView(m_resource.getd3d12TextureResource(), nullptr, &uavDesc, d3d12RWTextureDescriptorHandle); + bindlessTable->updated3d12descriptor(rwTextureHandle); + + m_rwTextureHandles[s][m] = rwTextureHandle; + } + } + } + break; + case TextureType::Texture2D: { - BindlessTable * bindlessTable = device->getBindlessTable(); - m_rwTextureHandle = bindlessTable->allocBindlessRWTextureHandle(static_cast(this)); - D3D12_CPU_DESCRIPTOR_HANDLE d3d12RWTextureDescriptorHandle = bindlessTable->getd3d12CPUDescriptorHandle(m_rwTextureHandle); - - D3D12_UNORDERED_ACCESS_VIEW_DESC uavDesc; - uavDesc.Format = getd3d12ResourceFormat(_texDesc.format); - uavDesc.ViewDimension = D3D12_UAV_DIMENSION_TEXTURE2D; - uavDesc.Texture2D.MipSlice = 0; - uavDesc.Texture2D.PlaneSlice = 0; - d3d12device->CreateUnorderedAccessView(m_resource.getd3d12TextureResource(), nullptr, &uavDesc, d3d12RWTextureDescriptorHandle); - bindlessTable->updated3d12descriptor(getRWTextureHandle()); + m_rwTextureHandles.resize(1); // 1 slice + m_rwTextureHandles[0].resize(_texDesc.mipmaps); + + for (uint m = 0; m < _texDesc.mipmaps; ++m) + { + BindlessTable * bindlessTable = device->getBindlessTable(); + auto rwTextureHandle = bindlessTable->allocBindlessRWTextureHandle(static_cast(this)); + D3D12_CPU_DESCRIPTOR_HANDLE d3d12RWTextureDescriptorHandle = bindlessTable->getd3d12CPUDescriptorHandle(rwTextureHandle); + + D3D12_UNORDERED_ACCESS_VIEW_DESC uavDesc; + uavDesc.Format = getd3d12ResourceFormat(_texDesc.format); + uavDesc.ViewDimension = D3D12_UAV_DIMENSION_TEXTURE2D; + uavDesc.Texture2D.MipSlice = m; + uavDesc.Texture2D.PlaneSlice = 0; + d3d12device->CreateUnorderedAccessView(m_resource.getd3d12TextureResource(), nullptr, &uavDesc, d3d12RWTextureDescriptorHandle); + bindlessTable->updated3d12descriptor(rwTextureHandle); + + m_rwTextureHandles[0][m] = rwTextureHandle; + } } break; } diff --git a/src/gfx/Resource/vulkan/Texture_vulkan.h b/src/gfx/Resource/vulkan/Texture_vulkan.h index 7db85ced2..3a46a10cd 100644 --- a/src/gfx/Resource/vulkan/Texture_vulkan.h +++ b/src/gfx/Resource/vulkan/Texture_vulkan.h @@ -19,6 +19,7 @@ namespace vg::gfx::vulkan static VkImageViewType getVulkanImageViewType (TextureType _texType); private: - VkImageView m_vkImageView; + VkImageView m_vkImageView; // This is the default image view with all slices/mipmaps (used for ShaderResourceView) + core::vector> m_vkSliceMipImageViews; // Separate image view for each slice/mip level (used for RWTextures) }; } \ No newline at end of file diff --git a/src/gfx/Resource/vulkan/Texture_vulkan.hpp b/src/gfx/Resource/vulkan/Texture_vulkan.hpp index 3e553d700..71e6a31eb 100644 --- a/src/gfx/Resource/vulkan/Texture_vulkan.hpp +++ b/src/gfx/Resource/vulkan/Texture_vulkan.hpp @@ -194,12 +194,12 @@ namespace vg::gfx::vulkan m_resource.setVulkanImage(vkImage, vmaAlloc); } - if (_texDesc.isShaderResource() || _texDesc.isBackbuffer()) + VkImageViewCreateInfo vkImageViewDesc = {}; + + if (_texDesc.isShaderResource() || _texDesc.isBackbuffer() || asBool(BindFlags::UnorderedAccess & _texDesc.resource.m_bindFlags)) { auto createVulkanShaderResourceView = [&](const TextureDesc & _texDesc, bool _stencil = false) { - VkImageViewCreateInfo vkImageViewDesc = {}; - vkImageViewDesc.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; vkImageViewDesc.pNext = nullptr; vkImageViewDesc.format = getVulkanPixelFormat(_texDesc.format); @@ -307,24 +307,103 @@ namespace vg::gfx::vulkan if (asBool(BindFlags::UnorderedAccess & _texDesc.resource.m_bindFlags)) { - BindlessTable * bindlessTable = device->getBindlessTable(); - m_rwTextureHandle = bindlessTable->allocBindlessRWTextureHandle(static_cast(this)); - - VkDescriptorImageInfo tex_descs = {}; - tex_descs.imageView = m_vkImageView; - tex_descs.imageLayout = VK_IMAGE_LAYOUT_GENERAL; - tex_descs.sampler = nullptr; - - VkWriteDescriptorSet writes = {}; - writes.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; - writes.dstBinding = BINDLESS_RWTEXTURE_BINDING; - writes.descriptorCount = 1; - writes.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE; - writes.pImageInfo = &tex_descs; - writes.dstSet = device->getVulkanBindlessDescriptors(); - writes.dstArrayElement = m_rwTextureHandle - BINDLESS_RWTEXTURE_START; - - vkUpdateDescriptorSets(device->getVulkanDevice(), 1, &writes, 0, nullptr); + switch (_texDesc.type) + { + default: + VG_ASSERT_ENUM_NOT_IMPLEMENTED(_texDesc.type); + break; + + case TextureType::TextureCube: + { + VG_ASSERT(_texDesc.slices == 6); + + m_vkSliceMipImageViews.resize(_texDesc.slices); + m_rwTextureHandles.resize(_texDesc.slices); + + for (uint s = 0; s < _texDesc.slices; ++s) + { + m_vkSliceMipImageViews[s].resize(_texDesc.mipmaps); + m_rwTextureHandles[s].resize(_texDesc.mipmaps); + } + + for (uint s = 0; s < _texDesc.slices; ++s) + { + for (uint m = 0; m < _texDesc.mipmaps; ++m) + { + BindlessTable * bindlessTable = device->getBindlessTable(); + auto rwTextureHandle = bindlessTable->allocBindlessRWTextureHandle(static_cast(this)); + + VkImageViewCreateInfo vkMipImageViewDesc = vkImageViewDesc; + vkMipImageViewDesc.viewType = VK_IMAGE_VIEW_TYPE_2D; + vkMipImageViewDesc.subresourceRange.baseMipLevel = m; + vkMipImageViewDesc.subresourceRange.levelCount = 1; + vkMipImageViewDesc.subresourceRange.baseArrayLayer = s; + vkMipImageViewDesc.subresourceRange.layerCount = 1; + + VG_VERIFY_VULKAN(vkCreateImageView(device->getVulkanDevice(), &vkMipImageViewDesc, nullptr, &m_vkSliceMipImageViews[s][m])); + + VkDescriptorImageInfo tex_descs = {}; + tex_descs.imageView = m_vkSliceMipImageViews[s][m]; + tex_descs.imageLayout = VK_IMAGE_LAYOUT_GENERAL; + tex_descs.sampler = nullptr; + + VkWriteDescriptorSet writes = {}; + writes.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + writes.dstBinding = BINDLESS_RWTEXTURE_BINDING; + writes.descriptorCount = 1; + writes.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE; + writes.pImageInfo = &tex_descs; + writes.dstSet = device->getVulkanBindlessDescriptors(); + writes.dstArrayElement = rwTextureHandle - BINDLESS_RWTEXTURE_START; + + vkUpdateDescriptorSets(device->getVulkanDevice(), 1, &writes, 0, nullptr); + + m_rwTextureHandles[s][m] = rwTextureHandle; + } + } + } + break; + + case TextureType::Texture2D: + { + m_vkSliceMipImageViews.resize(1); + m_vkSliceMipImageViews[0].resize(_texDesc.mipmaps); + + m_rwTextureHandles.resize(1); + m_rwTextureHandles[0].resize(_texDesc.mipmaps); + + for (uint m = 0; m < _texDesc.mipmaps; ++m) + { + BindlessTable * bindlessTable = device->getBindlessTable(); + auto rwTextureHandle = bindlessTable->allocBindlessRWTextureHandle(static_cast(this)); + + VkImageViewCreateInfo vkMipImageViewDesc = vkImageViewDesc; + vkMipImageViewDesc.subresourceRange.baseMipLevel = m; + vkMipImageViewDesc.subresourceRange.levelCount = 1; + + VG_VERIFY_VULKAN(vkCreateImageView(device->getVulkanDevice(), &vkMipImageViewDesc, nullptr, &m_vkSliceMipImageViews[0][m])); + + VkDescriptorImageInfo tex_descs = {}; + tex_descs.imageView = m_vkSliceMipImageViews[0][m]; + tex_descs.imageLayout = VK_IMAGE_LAYOUT_GENERAL; + tex_descs.sampler = nullptr; + + VkWriteDescriptorSet writes = {}; + writes.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + writes.dstBinding = BINDLESS_RWTEXTURE_BINDING; + writes.descriptorCount = 1; + writes.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE; + writes.pImageInfo = &tex_descs; + writes.dstSet = device->getVulkanBindlessDescriptors(); + writes.dstArrayElement = rwTextureHandle - BINDLESS_RWTEXTURE_START; + + vkUpdateDescriptorSets(device->getVulkanDevice(), 1, &writes, 0, nullptr); + + m_rwTextureHandles[0][m] = rwTextureHandle; + } + } + break; + } } } } @@ -333,9 +412,18 @@ namespace vg::gfx::vulkan Texture::~Texture() { auto * device = gfx::Device::get(); + auto & vkDevice = device->getVulkanDevice(); // Swapchain must be destroyed using PFN_vkDestroySwapchainKHR if (!getTexDesc().isBackbuffer()) - vkDestroyImageView(device->getVulkanDevice(), m_vkImageView, nullptr); + { + vkDestroyImageView(vkDevice, m_vkImageView, nullptr); + + for (uint s = 0; s < m_vkSliceMipImageViews.size(); ++s) + { + for (uint m = 0; m < m_vkSliceMipImageViews[s].size(); ++m) + vkDestroyImageView(vkDevice, m_vkSliceMipImageViews[s][m], nullptr); + } + } } } \ No newline at end of file diff --git a/src/renderer/Renderer.cpp b/src/renderer/Renderer.cpp index d878ee8e8..20c007561 100644 --- a/src/renderer/Renderer.cpp +++ b/src/renderer/Renderer.cpp @@ -473,7 +473,7 @@ namespace vg::renderer if (nullptr == m_hdrOutput || m_hdrOutput->getTexDesc() != hdrOutputDesc) { VG_SAFE_RELEASE(m_hdrOutput); - m_hdrOutput = (Texture*)CreateTexture(hdrOutputDesc, "HDROutput"); + m_hdrOutput = (Texture *)CreateTexture(hdrOutputDesc, "HDROutput"); } m_frameGraph.importRenderTarget("HDROutput", m_hdrOutput, float4(0, 0, 0, 1), FrameGraphResource::InitState::Clear); @@ -481,7 +481,7 @@ namespace vg::renderer // Register passes not linked to views (e.g. skinning, or BLAS updates) RenderPassContext mainViewRenderPassContext; - mainViewRenderPassContext.setView(nullptr); + mainViewRenderPassContext.setView(nullptr); m_frameGraph.addUserPass(mainViewRenderPassContext, m_gpuDebugUpdatePass, "GPU Debug"); @@ -497,6 +497,7 @@ namespace vg::renderer if (nullptr == m_generatedSpecularBRDF) { TextureDesc specularBRDFDesc = TextureDesc(Usage::Default, BindFlags::ShaderResource | BindFlags::UnorderedAccess, CPUAccessFlags::None, TextureType::Texture2D, PixelFormat::R16G16_float, TextureFlags::None, 256, 256, 1, 1, MSAA::None); + //specularBRDFDesc.mipmaps = 2; // test m_generatedSpecularBRDF = m_device.createTexture(specularBRDFDesc, "SpecularBRDF_LUT"); m_computeSpecularBRDFPass->setSpecularBRDFTexture(m_generatedSpecularBRDF); @@ -531,6 +532,9 @@ namespace vg::renderer } } + // Gather worlds from all visible views + vector visibleWorlds; + // Register view passes for (uint j = 0; j < core::enumCount(); ++j) { @@ -545,20 +549,49 @@ namespace vg::renderer auto & views = m_views[j]; for (uint i = 0; i < views.size(); ++i) { - auto * view = (View*)views[i]; + auto * view = (View *)views[i]; if (nullptr != view) { if (!view->IsRender()) continue; gfx::RenderPassContext rc; - rc.setView(view); + rc.setView(view); + + if (IWorld * world = view->GetWorld()) + { + if (!vector_helper::exists(visibleWorlds, world)) + visibleWorlds.push_back(world); + } view->RegisterFrameGraph(rc, m_frameGraph); } } } + if (asBool((PBRFlags::GenerateIrradianceCubemap | PBRFlags::GenerateSpecularReflectionCubemap) & options->getPBRFlags())) + { + for (uint i = 0; i < visibleWorlds.size(); ++i) + { + auto * world = visibleWorlds[i]; + + Texture * environmentCubemap = (Texture*)world->GetEnvironmentCubemap(); + if (nullptr != environmentCubemap) + { + Texture * irradianceCubemap = (Texture *)world->GetIrradianceCubemap(); + if (nullptr == irradianceCubemap) + { + TextureDesc irradianceCubemapDesc = environmentCubemap->getTexDesc(); + irradianceCubemapDesc.resource.m_bindFlags = BindFlags::ShaderResource | BindFlags::UnorderedAccess; + irradianceCubemapDesc.format = PixelFormat::R16G16B16A16_float; + irradianceCubemap = m_device.createTexture(irradianceCubemapDesc, "Irradiance_Cubemap"); + world->SetIrradianceCubemap(irradianceCubemap); + VG_SAFE_RELEASE(irradianceCubemap); + } + } + } + } + // Additional preview passes m_imgui->RegisterFrameGraph(mainViewRenderPassContext, m_frameGraph); diff --git a/src/version.h b/src/version.h index 40f410dbd..125a2cc20 100644 --- a/src/version.h +++ b/src/version.h @@ -2,4 +2,4 @@ #define VG_FRAMEWORK_VERSION_MAJOR 0 #define VG_FRAMEWORK_VERSION_MINOR 41 -#define VG_FRAMEWORK_VERSION_PATCH 3 \ No newline at end of file +#define VG_FRAMEWORK_VERSION_PATCH 4 \ No newline at end of file