diff --git a/src/Brixelizer.cpp b/src/Brixelizer.cpp new file mode 100644 index 000000000..491e3047a --- /dev/null +++ b/src/Brixelizer.cpp @@ -0,0 +1,252 @@ +#include "Brixelizer.h" + +#include +#include + +#include "Deferred.h" +#include "Util.h" + +#include "Brixelizer/BrixelizerContext.h" +#include "Brixelizer/BrixelizerGIContext.h" + +void Brixelizer::CacheFramebuffer() +{ + auto frameBuffer = (FrameBuffer*)mappedFrameBuffer->pData; + frameBufferCached = *frameBuffer; + mappedFrameBuffer = nullptr; +} + +void Brixelizer::DrawSettings() +{ + //ImGui::Text("Debug capture requires that PIX is attached."); + //if (ImGui::Button("Take Debug Capture") && !debugCapture) { + // debugCapture = true; + //} + //ImGui::SliderInt("Debug Mode", (int*)&m_DebugMode, 0, FFX_BRIXELIZER_TRACE_DEBUG_MODE_CASCADE_ID, "%d", ImGuiSliderFlags_AlwaysClamp); + //if (auto _tt = Util::HoverTooltipWrapper()) + // ImGui::Text("%s", magic_enum::enum_name(m_DebugMode).data()); + + //ImGui::SliderInt("Start Cascade", &m_StartCascadeIdx, 0, NUM_BRIXELIZER_CASCADES - 1); + //ImGui::SliderInt("End Cascade", &m_EndCascadeIdx, 0, NUM_BRIXELIZER_CASCADES - 1); + + //ImGui::SliderFloat("SDF Solve Epsilon", &m_SdfSolveEps, 1e-6f, 1.0f); + + //ImGui::Checkbox("Show Static Instance AABBs", &m_ShowStaticInstanceAABBs); + //ImGui::Checkbox("Show Dynamic Instance AABBs", &m_ShowDynamicInstanceAABBs); + //ImGui::Checkbox("Show Cascade AABBs", &m_ShowCascadeAABBs); + //ImGui::SliderInt("Show AABB Tree Index", &m_ShowAABBTreeIndex, -1, NUM_BRIXELIZER_CASCADES - 1); + + //static FfxBrixelizerStats statsFirstCascade{}; + + //if (stats.cascadeIndex == 0) { + // statsFirstCascade = stats; + //} + + //ImGui::NewLine(); + //ImGui::Text("Stats:"); + //ImGui::Text(std::format(" cascadeIndex : {}", statsFirstCascade.cascadeIndex).c_str()); + //ImGui::Text(" staticCascadeStats:"); + //ImGui::Text(std::format(" bricksAllocated : {}", statsFirstCascade.staticCascadeStats.bricksAllocated).c_str()); + //ImGui::Text(std::format(" referencesAllocated : {}", statsFirstCascade.staticCascadeStats.referencesAllocated).c_str()); + //ImGui::Text(std::format(" trianglesAllocated : {}", statsFirstCascade.staticCascadeStats.trianglesAllocated).c_str()); + + //ImGui::Text(" dynamicCascadeStats:"); + //ImGui::Text(std::format(" bricksAllocated : {}", statsFirstCascade.dynamicCascadeStats.bricksAllocated).c_str()); + //ImGui::Text(std::format(" referencesAllocated : {}", statsFirstCascade.dynamicCascadeStats.referencesAllocated).c_str()); + //ImGui::Text(std::format(" trianglesAllocated : {}", statsFirstCascade.dynamicCascadeStats.trianglesAllocated).c_str()); + + //ImGui::Text(" contextStats:"); + //ImGui::Text(std::format(" brickAllocationsAttempted : {}", statsFirstCascade.contextStats.brickAllocationsAttempted).c_str()); + //ImGui::Text(std::format(" brickAllocationsSucceeded : {}", statsFirstCascade.contextStats.brickAllocationsSucceeded).c_str()); + //ImGui::Text(std::format(" bricksCleared : {}", statsFirstCascade.contextStats.bricksCleared).c_str()); + //ImGui::Text(std::format(" bricksMerged : {}", statsFirstCascade.contextStats.bricksMerged).c_str()); + //ImGui::Text(std::format(" freeBricks : {}", statsFirstCascade.contextStats.freeBricks).c_str()); +} + +void Brixelizer::InitD3D12(IDXGIAdapter* a_adapter) +{ + DX::ThrowIfFailed(D3D12CreateDevice(a_adapter, D3D_FEATURE_LEVEL_12_2, IID_PPV_ARGS(&d3d12Device))); + + D3D12_COMMAND_QUEUE_DESC queueDesc = {}; + queueDesc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT; + queueDesc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE; + + DX::ThrowIfFailed(d3d12Device->CreateCommandQueue(&queueDesc, IID_PPV_ARGS(&commandQueue))); + + DX::ThrowIfFailed(d3d12Device->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(&commandAllocator))); + + DX::ThrowIfFailed(d3d12Device->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, commandAllocator.get(), nullptr, IID_PPV_ARGS(&commandList))); + DX::ThrowIfFailed(commandList->Close()); + + InitFenceAndEvent(); + + debugAvailable = DXGIGetDebugInterface1(0, IID_PPV_ARGS(&ga)) == S_OK; +} + +void Brixelizer::InitBrixelizer() +{ + auto manager = RE::BSGraphics::Renderer::GetSingleton(); + auto context = reinterpret_cast(manager->GetRuntimeData().context); + + stl::detour_vfunc<14, Brixelizer::Hooks::ID3D11DeviceContext_Map>(context); + stl::detour_vfunc<15, Brixelizer::Hooks::ID3D11DeviceContext_Unmap>(context); + + OpenSharedHandles(); + BrixelizerContext::GetSingleton()->InitBrixelizerContext(); + BrixelizerGIContext::GetSingleton()->InitBrixelizerGIContext(); +} + +void Brixelizer::CreatedWrappedResource(D3D11_TEXTURE2D_DESC a_texDesc, Brixelizer::WrappedResource& a_resource) +{ + auto manager = RE::BSGraphics::Renderer::GetSingleton(); + auto d3d11Device = reinterpret_cast(manager->GetRuntimeData().forwarder); + + DX::ThrowIfFailed(d3d11Device->CreateTexture2D(&a_texDesc, nullptr, &a_resource.resource11)); + + IDXGIResource1* dxgiResource = nullptr; + DX::ThrowIfFailed(a_resource.resource11->QueryInterface(IID_PPV_ARGS(&dxgiResource))); + + HANDLE sharedHandle = nullptr; + DX::ThrowIfFailed(dxgiResource->CreateSharedHandle( + nullptr, + DXGI_SHARED_RESOURCE_READ | DXGI_SHARED_RESOURCE_WRITE, + nullptr, + &sharedHandle)); + + DX::ThrowIfFailed(GetSingleton()->d3d12Device->OpenSharedHandle( + sharedHandle, + IID_PPV_ARGS(&a_resource.resource))); + + CloseHandle(sharedHandle); + + if (a_texDesc.BindFlags & D3D11_BIND_SHADER_RESOURCE) { + D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc = {}; + srvDesc.Format = a_texDesc.Format; + srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D; + srvDesc.Texture2D.MostDetailedMip = 0; + srvDesc.Texture2D.MipLevels = 1; + + DX::ThrowIfFailed(d3d11Device->CreateShaderResourceView(a_resource.resource11, &srvDesc, &a_resource.srv)); + } + + if (a_texDesc.BindFlags & D3D11_BIND_UNORDERED_ACCESS) { + D3D11_UNORDERED_ACCESS_VIEW_DESC uavDesc = {}; + uavDesc.Format = a_texDesc.Format; + uavDesc.ViewDimension = D3D11_UAV_DIMENSION_TEXTURE2D; + uavDesc.Texture2D.MipSlice = 0; + + DX::ThrowIfFailed(d3d11Device->CreateUnorderedAccessView(a_resource.resource11, &uavDesc, &a_resource.uav)); + } +} + +// Function to check for shared NT handle support and convert to D3D12 resource +Brixelizer::RenderTargetDataD3D12 Brixelizer::ConvertD3D11TextureToD3D12(RE::BSGraphics::RenderTargetData* rtData) +{ + RenderTargetDataD3D12 renderTargetData{}; + + if (!rtData->texture) + return renderTargetData; + + D3D11_TEXTURE2D_DESC texDesc{}; + rtData->texture->GetDesc(&texDesc); + + if (!(texDesc.MiscFlags & D3D11_RESOURCE_MISC_SHARED_NTHANDLE)) + return renderTargetData; + + // Query the DXGIResource1 interface to access shared NT handle + winrt::com_ptr dxgiResource1; + DX::ThrowIfFailed(rtData->texture->QueryInterface(IID_PPV_ARGS(&dxgiResource1))); + + // Create the shared NT handle + HANDLE sharedNtHandle = nullptr; + DX::ThrowIfFailed(dxgiResource1->CreateSharedHandle(nullptr, DXGI_SHARED_RESOURCE_READ | DXGI_SHARED_RESOURCE_WRITE, nullptr, &sharedNtHandle)); + + // Open the shared handle in D3D12 + DX::ThrowIfFailed(d3d12Device->OpenSharedHandle(sharedNtHandle, IID_PPV_ARGS(&renderTargetData.d3d12Resource))); + CloseHandle(sharedNtHandle); // Close the handle after opening it in D3D12 + + return renderTargetData; +} + +void Brixelizer::OpenSharedHandles() +{ + auto renderer = RE::BSGraphics::Renderer::GetSingleton(); + + for (int i = 0; i < RE::RENDER_TARGET::kTOTAL; i++) { + renderTargetsD3D12[i] = ConvertD3D11TextureToD3D12(&renderer->GetRuntimeData().renderTargets[i]); + } +} + +void Brixelizer::ClearShaderCache() +{ +} + +void Brixelizer::InitFenceAndEvent() +{ + HRESULT hr = d3d12Device->CreateFence(0, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(&fence)); + if (FAILED(hr)) { + throw std::runtime_error("Failed to create fence."); + } + + fenceEvent = CreateEvent(nullptr, FALSE, FALSE, nullptr); + if (!fenceEvent) { + throw std::runtime_error("Failed to create fence event."); + } +} + +void Brixelizer::WaitForD3D11() +{ + auto state = State::GetSingleton(); + + D3D11_QUERY_DESC queryDesc = { .Query = D3D11_QUERY_EVENT, .MiscFlags = 0 }; + winrt::com_ptr query; + DX::ThrowIfFailed(state->device->CreateQuery(&queryDesc, query.put())); + + // https://github.com/niessner/VoxelHashing/blob/master/DepthSensingCUDA/Source/GlobalAppState.cpp + state->context->Flush(); + state->context->End(query.get()); + state->context->Flush(); + + while (state->context->GetData(query.get(), nullptr, 0, 0) != S_OK) {} +} + +// WaitForD3D12 Function +void Brixelizer::WaitForD3D12() +{ + // Increment the fence value + const UINT64 currentFenceValue = fenceValue; + DX::ThrowIfFailed(commandQueue->Signal(fence.get(), currentFenceValue)); + fenceValue++; + + // Check if the fence has been reached + if (fence->GetCompletedValue() < currentFenceValue) { + DX::ThrowIfFailed(fence->SetEventOnCompletion(currentFenceValue, fenceEvent)); + WaitForSingleObject(fenceEvent, INFINITE); + } +} + +void Brixelizer::FrameUpdate() +{ + WaitForD3D11(); + + if (debugAvailable && debugCapture) + ga->BeginCapture(); + + DX::ThrowIfFailed(commandAllocator->Reset()); + DX::ThrowIfFailed(commandList->Reset(commandAllocator.get(), nullptr)); + + BrixelizerContext::GetSingleton()->UpdateBrixelizerContext(); + //BrixelizerGIContext::GetSingleton()->UpdateBrixelizerGIContext(); + + DX::ThrowIfFailed(commandList->Close()); + + ID3D12CommandList* ppCommandLists[] = { commandList.get() }; + commandQueue->ExecuteCommandLists(1, ppCommandLists); + + if (debugAvailable && debugCapture) + ga->EndCapture(); + + WaitForD3D12(); + + debugCapture = false; +} \ No newline at end of file diff --git a/src/Raytracing.h b/src/Brixelizer.h similarity index 54% rename from src/Raytracing.h rename to src/Brixelizer.h index a32213d73..6c4614e1d 100644 --- a/src/Raytracing.h +++ b/src/Brixelizer.h @@ -40,12 +40,12 @@ interface DECLSPEC_UUID("9f251514-9d4d-4902-9d60-18988ab7d4b5") DECLSPEC_NOVTABL // value should be tuned to what is required by Brixelizer. constexpr UINT64 GPU_SCRATCH_BUFFER_SIZE = 1ull << 30; -class Raytracing +class Brixelizer { public: - static Raytracing* GetSingleton() + static Brixelizer* GetSingleton() { - static Raytracing singleton; + static Brixelizer singleton; return &singleton; } @@ -86,23 +86,6 @@ class Raytracing UINT64 fenceValue = 0; HANDLE fenceEvent = nullptr; - FfxBrixelizerContextDescription initializationParameters = {}; - FfxBrixelizerContext brixelizerContext = {}; - FfxBrixelizerBakedUpdateDescription brixelizerBakedUpdateDesc = {}; - FfxBrixelizerStats stats = {}; - FfxBrixelizerBakedUpdateDescription bakedUpdateDesc = {}; - - winrt::com_ptr sdfAtlas; - winrt::com_ptr brickAABBs; - winrt::com_ptr gpuScratchBuffer; - - winrt::com_ptr cascadeAABBTrees[FFX_BRIXELIZER_MAX_CASCADES]; - winrt::com_ptr cascadeBrickMaps[FFX_BRIXELIZER_MAX_CASCADES]; - - FfxBrixelizerGIContextDescription giInitializationParameters = {}; - FfxBrixelizerGIDispatchDescription giDispatchDesc = {}; - FfxBrixelizerGIContext brixelizerGIContext = {}; - struct WrappedResource { ID3D11Texture2D* resource11; @@ -111,127 +94,23 @@ class Raytracing winrt::com_ptr resource; }; - WrappedResource debugRenderTarget; - - WrappedResource diffuseGi; - WrappedResource specularGi; - - WrappedResource depth; - WrappedResource normal; - - WrappedResource historyDepth; - WrappedResource historyNormal; - WrappedResource prevLitOutput; - - winrt::com_ptr noiseTextures[16]; - - FfxBrixelizerTraceDebugModes m_DebugMode = FFX_BRIXELIZER_TRACE_DEBUG_MODE_GRAD; - - int m_StartCascadeIdx = 0; - int m_EndCascadeIdx = NUM_BRIXELIZER_CASCADES - 1; - - float m_TMin = 0.0f; - float m_TMax = 10000.0f; - float m_SdfSolveEps = 0.5f; - - bool m_ShowStaticInstanceAABBs = false; - bool m_ShowDynamicInstanceAABBs = false; - bool m_ShowCascadeAABBs = false; - int m_ShowAABBTreeIndex = -1; - - float m_RayPushoff = 0.25f; - void DrawSettings(); - void InitD3D12(IDXGIAdapter* a_adapter); - winrt::com_ptr CreateBuffer(UINT64 size, D3D12_RESOURCE_STATES resourceState, D3D12_RESOURCE_FLAGS flags); - - inline void Init() - { - InitBrixelizer(); - InitBrixelizerGI(); - } + void InitD3D12(IDXGIAdapter* a_adapter); void InitBrixelizer(); - void CreatedWrappedResource(D3D11_TEXTURE2D_DESC a_texDesc, Raytracing::WrappedResource& a_resource); - void CreateMiscTextures(); - void CreateNoiseTextures(); - void InitBrixelizerGI(); - - void OpenSharedHandles(); - - struct Vertex - { - float4 position; - }; - - struct BufferData - { - winrt::com_ptr buffer; - bool registered = false; - uint width; - uint index; - }; - - BufferData AllocateBuffer(const D3D11_BUFFER_DESC* pDesc, const D3D11_SUBRESOURCE_DATA* pInitialData); - - eastl::hash_map vertexBuffers; - eastl::hash_map indexBuffers; - bool visibleState = true; + static void CreatedWrappedResource(D3D11_TEXTURE2D_DESC a_texDesc, Brixelizer::WrappedResource& a_resource); - struct InstanceData - { - FfxBrixelizerInstanceID instanceID; - bool state = false; - }; - - eastl::hash_set queuedInstances; - eastl::hash_map instances; - - uint GetBufferIndex(BufferData& a_bufferData); - - void AddInstance(RE::BSTriShape* geometry); - void SeenInstance(RE::BSTriShape* geometry); - void RemoveInstance(RE::BSTriShape* a_geometry); - - void RegisterVertexBuffer(const D3D11_BUFFER_DESC* pDesc, const D3D11_SUBRESOURCE_DATA* pInitialData, ID3D11Buffer** ppBuffer); - void RegisterIndexBuffer(const D3D11_BUFFER_DESC* pDesc, const D3D11_SUBRESOURCE_DATA* pInitialData, ID3D11Buffer** ppBuffer); - - void RegisterInputLayout(ID3D11InputLayout* ppInputLayout, D3D11_INPUT_ELEMENT_DESC* pInputElementDescs, UINT NumElements); - - void UnregisterVertexBuffer(ID3D11Buffer* ppBuffer); - void UnregisterIndexBuffer(ID3D11Buffer* ppBuffer); - - void TransitionResources(D3D12_RESOURCE_STATES stateBefore, D3D12_RESOURCE_STATES stateAfter); - - ID3D11ComputeShader* copyToSharedBufferCS; - ID3D11ComputeShader* GetCopyToSharedBufferCS(); + void OpenSharedHandles(); void ClearShaderCache(); - void CopyResourcesToSharedBuffers(); void InitFenceAndEvent(); + void WaitForD3D11(); void WaitForD3D12(); - FfxBrixelizerDebugVisualizationDescription GetDebugVisualization(); - void FrameUpdate(); - void PostFrameUpdate(); - void UpdateBrixelizerContext(); - void UpdateBrixelizerGIContext(); - - void CopyHistoryResources(); - - struct InputLayoutData - { - uint32_t vertexStride; - uint32_t vertexBufferOffset; - FfxSurfaceFormat vertexFormat; - }; - - eastl::hash_map inputLayouts; - eastl::hash_map vertexDescToInputLayout; struct RenderTargetDataD3D12 { @@ -239,33 +118,39 @@ class Raytracing winrt::com_ptr d3d12Resource; }; - std::shared_mutex mutex; - RenderTargetDataD3D12 renderTargetsD3D12[RE::RENDER_TARGET::kTOTAL]; RenderTargetDataD3D12 renderTargetsCubemapD3D12[RE::RENDER_TARGETS_CUBEMAP::kTOTAL]; RenderTargetDataD3D12 ConvertD3D11TextureToD3D12(RE::BSGraphics::RenderTargetData* rtData); - void BSTriShape_UpdateWorldData(RE::BSTriShape* This, RE::NiUpdateData* a_data); - struct Hooks - { - struct BSTriShape_UpdateWorldData + { + struct ID3D11DeviceContext_Map { - static void thunk(RE::BSTriShape* This, RE::NiUpdateData* a_data) + static HRESULT thunk(ID3D11DeviceContext* This, ID3D11Resource* pResource, UINT Subresource, D3D11_MAP MapType, UINT MapFlags, D3D11_MAPPED_SUBRESOURCE* pMappedResource) { - GetSingleton()->BSTriShape_UpdateWorldData(This, a_data); + HRESULT hr = func(This, pResource, Subresource, MapType, MapFlags, pMappedResource); + + static REL::Relocation perFrame{ REL::RelocationID(524768, 411384) }; + + if (*perFrame.get() == pResource) + GetSingleton()->mappedFrameBuffer = pMappedResource; + + return hr; } static inline REL::Relocation func; }; - struct DirtyStates_CreateInputLayoutFromVertexDesc + struct ID3D11DeviceContext_Unmap { - static ID3D11InputLayout* thunk(uint64_t a_vertexDesc) + static void thunk(ID3D11DeviceContext* This, ID3D11Resource* pResource, UINT Subresource) { - auto inputLayout = func(a_vertexDesc); - GetSingleton()->vertexDescToInputLayout.insert({ a_vertexDesc, inputLayout }); - return inputLayout; + static REL::Relocation perFrame{ REL::RelocationID(524768, 411384) }; + + if (*perFrame.get() == pResource && GetSingleton()->mappedFrameBuffer) + GetSingleton()->CacheFramebuffer(); + + func(This, pResource, Subresource); } static inline REL::Relocation func; }; @@ -359,14 +244,13 @@ class Raytracing static void Install() { - if (REL::Module::IsAE()) { - stl::write_vfunc<0x31, BSTriShape_UpdateWorldData>(RE::VTABLE_BSTriShape[0]); - } else { - stl::write_vfunc<0x30, BSTriShape_UpdateWorldData>(RE::VTABLE_BSTriShape[0]); - } - stl::write_thunk_call(REL::RelocationID(75580, 75580).address() + REL::Relocate(0x465, 0x465)); PatchCreateRenderTarget(); - logger::info("[Raytracing] Installed hooks"); + + //static REL::Relocation func{ REL::VariantID(75471, 77257, 0xDBCCD0) }; // D6B0C0, DA69B0, DBCCD0 + //auto offset = REL::VariantOffset(0x7B, 0x7B, 0x73); + //REL::safe_write(func.address() + offset.offset(), 0x8); // add the D3D11_RESOURCE_MISC_SHARED_NTHANDLE flag + + logger::info("[Brixelizer] Installed hooks"); } }; }; diff --git a/src/Brixelizer/BrixelizerContext.cpp b/src/Brixelizer/BrixelizerContext.cpp new file mode 100644 index 000000000..1917e723a --- /dev/null +++ b/src/Brixelizer/BrixelizerContext.cpp @@ -0,0 +1,650 @@ +#include "BrixelizerContext.h" + +#include +#include + +#include "Deferred.h" +#include "Util.h" + +void BrixelizerContext::InitBrixelizerContext() +{ + auto manager = RE::BSGraphics::Renderer::GetSingleton(); + auto device = reinterpret_cast(manager->GetRuntimeData().forwarder); + + stl::detour_vfunc<3, BrixelizerContext::Hooks::ID3D11Device_CreateBuffer>(device); + stl::detour_vfunc<11, BrixelizerContext::Hooks::ID3D11Device_CreateInputLayout>(device); + + auto ffxDevice = ffxGetDeviceDX12(Brixelizer::GetSingleton()->d3d12Device.get()); + + size_t scratchBufferSize = ffxGetScratchMemorySizeDX12(2); + void* scratchBuffer = calloc(scratchBufferSize, 1); + memset(scratchBuffer, 0, scratchBufferSize); + + if (ffxGetInterfaceDX12(&initializationParameters.backendInterface, ffxDevice, scratchBuffer, scratchBufferSize, FFX_FSR3UPSCALER_CONTEXT_COUNT) != FFX_OK) + logger::critical("[Brixelizer] Failed to initialize Brixelizer backend interface!"); + + initializationParameters.sdfCenter[0] = 0.0f; + initializationParameters.sdfCenter[1] = 0.0f; + initializationParameters.sdfCenter[2] = 0.0f; + initializationParameters.flags = FFX_BRIXELIZER_CONTEXT_FLAG_ALL_DEBUG; + initializationParameters.numCascades = NUM_BRIXELIZER_CASCADES; + + float voxelSize = 10.f; + for (uint32_t i = 0; i < NUM_BRIXELIZER_CASCADES; ++i) { + FfxBrixelizerCascadeDescription* cascadeDesc = &initializationParameters.cascadeDescs[i]; + cascadeDesc->flags = FfxBrixelizerCascadeFlag(FFX_BRIXELIZER_CASCADE_DYNAMIC | FFX_BRIXELIZER_CASCADE_STATIC); + cascadeDesc->voxelSize = voxelSize; + voxelSize *= 2.0f; + } + + FfxErrorCode error = ffxBrixelizerContextCreate(&initializationParameters, &brixelizerContext); + if (error != FFX_OK) { + logger::critical("[Brixelizer] Failed to initialize Brixelizer context!"); + } + + D3D12_RESOURCE_DESC sdfAtlasDesc = {}; + sdfAtlasDesc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE3D; + sdfAtlasDesc.Width = FFX_BRIXELIZER_STATIC_CONFIG_SDF_ATLAS_SIZE; + sdfAtlasDesc.Height = FFX_BRIXELIZER_STATIC_CONFIG_SDF_ATLAS_SIZE; + sdfAtlasDesc.DepthOrArraySize = FFX_BRIXELIZER_STATIC_CONFIG_SDF_ATLAS_SIZE; + sdfAtlasDesc.MipLevels = 1; + sdfAtlasDesc.Format = DXGI_FORMAT_R8_UNORM; + sdfAtlasDesc.SampleDesc.Count = 1; + sdfAtlasDesc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN; + sdfAtlasDesc.Flags = D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS; + + { + CD3DX12_HEAP_PROPERTIES heapProperties(D3D12_HEAP_TYPE_DEFAULT); + DX::ThrowIfFailed(Brixelizer::GetSingleton()->d3d12Device->CreateCommittedResource( + &heapProperties, + D3D12_HEAP_FLAG_NONE, + &sdfAtlasDesc, + D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE, + nullptr, + IID_PPV_ARGS(&sdfAtlas))); + } + + brickAABBs = CreateBuffer(FFX_BRIXELIZER_BRICK_AABBS_SIZE, D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE, D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS); + + gpuScratchBuffer = CreateBuffer(GPU_SCRATCH_BUFFER_SIZE, D3D12_RESOURCE_STATE_UNORDERED_ACCESS, D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS); + + for (int i = 0; i < FFX_BRIXELIZER_MAX_CASCADES; i++) { + cascadeAABBTrees[i] = CreateBuffer(FFX_BRIXELIZER_CASCADE_AABB_TREE_SIZE, D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE, D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS); + cascadeBrickMaps[i] = CreateBuffer(FFX_BRIXELIZER_CASCADE_BRICK_MAP_SIZE, D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE, D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS); + } + + { + auto state = State::GetSingleton(); + + D3D11_TEXTURE2D_DESC texDesc; + texDesc.Width = (uint)state->screenSize.x; + texDesc.Height = (uint)state->screenSize.y; + texDesc.MipLevels = 1; + texDesc.ArraySize = 1; + texDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM; + texDesc.SampleDesc.Count = 1; + texDesc.SampleDesc.Quality = 0; + texDesc.Usage = D3D11_USAGE_DEFAULT; + texDesc.BindFlags = D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_UNORDERED_ACCESS; + texDesc.CPUAccessFlags = 0; + texDesc.MiscFlags = D3D11_RESOURCE_MISC_SHARED_NTHANDLE | D3D11_RESOURCE_MISC_SHARED; + + Brixelizer::CreatedWrappedResource(texDesc, debugRenderTarget); + } +} + +winrt::com_ptr BrixelizerContext::CreateBuffer(UINT64 size, D3D12_RESOURCE_STATES resourceState = D3D12_RESOURCE_STATE_COMMON, D3D12_RESOURCE_FLAGS flags = D3D12_RESOURCE_FLAG_NONE) +{ + winrt::com_ptr buffer; + CD3DX12_HEAP_PROPERTIES heapProperties(D3D12_HEAP_TYPE_DEFAULT); + CD3DX12_RESOURCE_DESC bufferDesc = CD3DX12_RESOURCE_DESC::Buffer(size, flags); + + DX::ThrowIfFailed(Brixelizer::GetSingleton()->d3d12Device->CreateCommittedResource( + &heapProperties, + D3D12_HEAP_FLAG_NONE, + &bufferDesc, + resourceState, + nullptr, + IID_PPV_ARGS(&buffer))); + + return buffer; +} + +void BrixelizerContext::BSTriShape_UpdateWorldData(RE::BSTriShape* This, RE::NiUpdateData* a_data) +{ + std::lock_guard lock{ mutex }; + + RE::NiPoint3 pointA = This->world * RE::NiPoint3{ 1.0f, 1.0f, 1.0f }; + + Hooks::BSTriShape_UpdateWorldData::func(This, a_data); + + RE::NiPoint3 pointB = This->world * RE::NiPoint3{ 1.0f, 1.0f, 1.0f }; + + if (pointA.GetDistance(pointB) > 0.1f) { + auto it = instances.find(This); + if (it != instances.end()) { + auto& instanceData = (*it).second; + auto error = ffxBrixelizerDeleteInstances(&brixelizerContext, &instanceData.instanceID, 1); + if (error != FFX_OK) + logger::critical("error"); + instances.erase(it); + } + } +} + +uint BrixelizerContext::GetBufferIndex(BufferData& a_bufferData) +{ + if (a_bufferData.registered) + return a_bufferData.index; + + FfxResource ffxResource = ffxGetResourceDX12(a_bufferData.buffer.get(), ffxGetResourceDescriptionDX12(a_bufferData.buffer.get(), FFX_RESOURCE_USAGE_READ_ONLY), nullptr, FFX_RESOURCE_STATE_PIXEL_COMPUTE_READ); + + FfxBrixelizerBufferDescription brixelizerBufferDesc = {}; + brixelizerBufferDesc.buffer = ffxResource; + brixelizerBufferDesc.outIndex = &a_bufferData.index; + auto error = ffxBrixelizerRegisterBuffers(&brixelizerContext, &brixelizerBufferDesc, 1); + if (error != FFX_OK) + logger::critical("error"); + + a_bufferData.registered = true; + + return a_bufferData.index; +} + +DirectX::XMMATRIX GetXMFromNiTransform(const RE::NiTransform& Transform) +{ + DirectX::XMMATRIX temp; + + const RE::NiMatrix3& m = Transform.rotate; + const float scale = Transform.scale; + + temp.r[0] = DirectX::XMVectorScale(DirectX::XMVectorSet( + m.entry[0][0], + m.entry[1][0], + m.entry[2][0], + 0.0f), + scale); + + temp.r[1] = DirectX::XMVectorScale(DirectX::XMVectorSet( + m.entry[0][1], + m.entry[1][1], + m.entry[2][1], + 0.0f), + scale); + + temp.r[2] = DirectX::XMVectorScale(DirectX::XMVectorSet( + m.entry[0][2], + m.entry[1][2], + m.entry[2][2], + 0.0f), + scale); + + temp.r[3] = DirectX::XMVectorSet( + Transform.translate.x, + Transform.translate.y, + Transform.translate.z, + 1.0f); + + return temp; +} + +void BrixelizerContext::AddInstance(RE::BSTriShape* a_geometry) +{ + const auto& transform = a_geometry->world; + const auto& modelData = a_geometry->GetModelData().modelBound; + if (a_geometry->worldBound.radius == 0) + return; + + auto effect = a_geometry->GetGeometryRuntimeData().properties[RE::BSGeometry::States::kEffect]; + auto lightingShader = netimmerse_cast(effect.get()); + + if (!lightingShader) + return; + + if (!lightingShader->flags.all(RE::BSShaderProperty::EShaderPropertyFlag::kZBufferWrite, RE::BSShaderProperty::EShaderPropertyFlag::kZBufferTest)) + return; + + if (lightingShader->flags.any(RE::BSShaderProperty::EShaderPropertyFlag::kLODObjects, RE::BSShaderProperty::EShaderPropertyFlag::kLODLandscape, RE::BSShaderProperty::EShaderPropertyFlag::kHDLODObjects)) + return; + + if (lightingShader->flags.any(RE::BSShaderProperty::EShaderPropertyFlag::kSkinned)) + return; + + // TODO: FIX THIS + if (lightingShader->flags.any(RE::BSShaderProperty::EShaderPropertyFlag::kMultiTextureLandscape, RE::BSShaderProperty::EShaderPropertyFlag::kMultipleTextures, RE::BSShaderProperty::EShaderPropertyFlag::kMultiIndexSnow)) + return; + + const RE::NiPoint3 c = { modelData.center.x, modelData.center.y, modelData.center.z }; + const RE::NiPoint3 r = { modelData.radius, modelData.radius, modelData.radius }; + const RE::NiPoint3 aabbMinVec = c - r; + const RE::NiPoint3 aabbMaxVec = c + r; + const RE::NiPoint3 extents = aabbMaxVec - aabbMinVec; + + const RE::NiPoint3 aabbCorners[8] = { + aabbMinVec + RE::NiPoint3(0.0f, 0.0f, 0.0f), + aabbMinVec + RE::NiPoint3(extents.x, 0.0f, 0.0f), + aabbMinVec + RE::NiPoint3(0.0f, 0.0f, extents.z), + aabbMinVec + RE::NiPoint3(extents.x, 0.0f, extents.z), + aabbMinVec + RE::NiPoint3(0.0f, extents.y, 0.0f), + aabbMinVec + RE::NiPoint3(extents.x, extents.y, 0.0f), + aabbMinVec + RE::NiPoint3(0.0f, extents.y, extents.z), + aabbMinVec + RE::NiPoint3(extents.x, extents.y, extents.z), + }; + + float4 minExtents = float4(FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX); + float4 maxExtents = float4(-FLT_MAX, -FLT_MAX, -FLT_MAX, -FLT_MAX); + + for (uint i = 0; i < 8; i++) { + auto transformed = transform * aabbCorners[i]; + float4 transformedF = { transformed.x, transformed.y, transformed.z, 0 }; + + minExtents = (float4)_mm_min_ps(minExtents, transformedF); + maxExtents = (float4)_mm_max_ps(maxExtents, transformedF); + } + + auto rendererData = a_geometry->GetGeometryRuntimeData().rendererData; + + if (!rendererData || !rendererData->vertexBuffer || !rendererData->indexBuffer) + return; + + BufferData* vertexBuffer; + BufferData* indexBuffer; + + { + auto it2 = vertexBuffers.find((ID3D11Buffer*)rendererData->vertexBuffer); + if (it2 == vertexBuffers.end()) + return; + vertexBuffer = &it2->second; + } + + { + auto it2 = indexBuffers.find((ID3D11Buffer*)rendererData->indexBuffer); + if (it2 == indexBuffers.end()) + return; + indexBuffer = &it2->second; + } + + auto vertexDesc = *(uint64_t*)&rendererData->vertexDesc; + + InputLayoutData* inputLayoutData; + + { + auto it2 = vertexDescToInputLayout.find(vertexDesc); + if (it2 == vertexDescToInputLayout.end()) + return; + auto inputLayout = it2->second; + auto it3 = inputLayouts.find(inputLayout); + if (it3 == inputLayouts.end()) + return; + inputLayoutData = &it3->second; + } + + FfxBrixelizerInstanceDescription instanceDesc = {}; + + { + instanceDesc.aabb.min[0] = minExtents.x; + instanceDesc.aabb.max[0] = maxExtents.x; + + instanceDesc.aabb.min[1] = minExtents.y; + instanceDesc.aabb.max[1] = maxExtents.y; + + instanceDesc.aabb.min[2] = minExtents.z; + instanceDesc.aabb.max[2] = maxExtents.z; + } + + float4x4 xmmTransform = GetXMFromNiTransform(transform); + + for (uint row = 0; row < 3; ++row) { + for (uint col = 0; col < 4; ++col) { + instanceDesc.transform[row * 4 + col] = xmmTransform.m[col][row]; + } + } + + instanceDesc.indexFormat = FFX_INDEX_TYPE_UINT16; + instanceDesc.indexBuffer = GetBufferIndex(*indexBuffer); + instanceDesc.indexBufferOffset = 0; + instanceDesc.triangleCount = a_geometry->GetTrishapeRuntimeData().triangleCount; + + instanceDesc.vertexBuffer = GetBufferIndex(*vertexBuffer); + instanceDesc.vertexStride = ((*(uint64_t*)&rendererData->vertexDesc) << 2) & 0x3C; + instanceDesc.vertexBufferOffset = rendererData->vertexDesc.GetAttributeOffset(RE::BSGraphics::Vertex::Attribute::VA_POSITION); + instanceDesc.vertexCount = a_geometry->GetTrishapeRuntimeData().vertexCount; + instanceDesc.vertexFormat = FFX_SURFACE_FORMAT_R32G32B32_FLOAT; + + instanceDesc.vertexStride = inputLayoutData->vertexStride; + instanceDesc.vertexBufferOffset = inputLayoutData->vertexBufferOffset; + instanceDesc.vertexCount = a_geometry->GetTrishapeRuntimeData().vertexCount; + instanceDesc.vertexFormat = inputLayoutData->vertexFormat; + + InstanceData instanceData{}; + instanceDesc.outInstanceID = &instanceData.instanceID; + instanceDesc.flags = FFX_BRIXELIZER_INSTANCE_FLAG_NONE; + + FfxErrorCode error = ffxBrixelizerCreateInstances(&brixelizerContext, &instanceDesc, 1); + if (error != FFX_OK) + logger::critical("error"); + + instances.insert({ a_geometry, instanceData }); +} + +RE::BSFadeNode* FindBSFadeNode(RE::NiNode* a_niNode) +{ + if (auto fadeNode = a_niNode->AsFadeNode()) { + return fadeNode; + } + return a_niNode->parent ? FindBSFadeNode(a_niNode->parent) : nullptr; +} + +void BrixelizerContext::SeenInstance(RE::BSTriShape* a_geometry) +{ + auto& flags = a_geometry->GetFlags(); + if (flags.none(RE::NiAVObject::Flag::kHidden) && flags.all(RE::NiAVObject::Flag::kRenderUse)) { + if (auto fadeNode = FindBSFadeNode((RE::NiNode*)a_geometry)) { + if (auto extraData = fadeNode->GetExtraData("BSX")) { + auto bsxFlags = (RE::BSXFlags*)extraData; + auto value = static_cast(bsxFlags->value); + if (value & (int32_t)RE::BSXFlags::Flag::kEditorMarker) + return; + } + } + + auto it = instances.find(a_geometry); + if (it != instances.end()) { + auto& instanceData = (*it).second; + instanceData.visibleState = visibleStateValue; + } else { + queuedInstances.insert(a_geometry); + } + } +} + +void BrixelizerContext::RemoveInstance(RE::BSTriShape* This) +{ + std::lock_guard lock{ mutex }; + + auto it = instances.find(This); + if (it != instances.end()) { + auto& instanceData = (*it).second; + auto error = ffxBrixelizerDeleteInstances(&brixelizerContext, &instanceData.instanceID, 1); + if (error != FFX_OK) + logger::critical("error"); + instances.erase(it); + } +} + +BrixelizerContext::BufferData BrixelizerContext::AllocateBuffer(const D3D11_BUFFER_DESC* pDesc, const D3D11_SUBRESOURCE_DATA* pInitialData) +{ + BufferData data; + + // Allocate the memory on the CPU and GPU + { + D3D12_HEAP_PROPERTIES heapProperties = {}; + heapProperties.Type = D3D12_HEAP_TYPE_UPLOAD; + + D3D12_RESOURCE_DESC bufferDesc = {}; + bufferDesc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER; + bufferDesc.Width = pDesc->ByteWidth; + bufferDesc.Height = 1; + bufferDesc.DepthOrArraySize = 1; + bufferDesc.MipLevels = 1; + bufferDesc.Format = DXGI_FORMAT_UNKNOWN; + bufferDesc.SampleDesc.Count = 1; + bufferDesc.SampleDesc.Quality = 0; + bufferDesc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR; + bufferDesc.Flags = D3D12_RESOURCE_FLAG_NONE; + + DX::ThrowIfFailed(Brixelizer::GetSingleton()->d3d12Device->CreateCommittedResource( + &heapProperties, + D3D12_HEAP_FLAG_NONE, + &bufferDesc, + D3D12_RESOURCE_STATE_GENERIC_READ, + nullptr, + IID_PPV_ARGS(&data.buffer))); + + data.width = pDesc->ByteWidth; + } + + // Map the buffer to CPU memory and copy the vertex data + { + void* pVertexData = nullptr; + data.buffer->Map(0, nullptr, &pVertexData); + memcpy(pVertexData, pInitialData->pSysMem, pDesc->ByteWidth); + data.buffer->Unmap(0, nullptr); + } + + return data; +} + +struct ID3D11Buffer_Release +{ + static void thunk(ID3D11Buffer* This) + { + BrixelizerContext::GetSingleton()->UnregisterVertexBuffer(This); + BrixelizerContext::GetSingleton()->UnregisterIndexBuffer(This); + func(This); + } + static inline REL::Relocation func; +}; + +bool hooked = false; + +void BrixelizerContext::RegisterVertexBuffer(const D3D11_BUFFER_DESC* pDesc, const D3D11_SUBRESOURCE_DATA* pInitialData, ID3D11Buffer** ppBuffer) +{ + BufferData data = AllocateBuffer(pDesc, pInitialData); + vertexBuffers.insert({ *ppBuffer, data }); + if (!hooked) { + stl::detour_vfunc<2, ID3D11Buffer_Release>(*ppBuffer); + hooked = true; + } +} + +void BrixelizerContext::RegisterIndexBuffer(const D3D11_BUFFER_DESC* pDesc, const D3D11_SUBRESOURCE_DATA* pInitialData, ID3D11Buffer** ppBuffer) +{ + BufferData data = AllocateBuffer(pDesc, pInitialData); + indexBuffers.insert({ *ppBuffer, data }); + if (!hooked) { + stl::detour_vfunc<2, ID3D11Buffer_Release>(*ppBuffer); + hooked = true; + } +} + +void BrixelizerContext::RegisterInputLayout(ID3D11InputLayout* ppInputLayout, D3D11_INPUT_ELEMENT_DESC* pInputElementDescs, UINT NumElements) +{ + InputLayoutData data = {}; + for (UINT i = 0; i < NumElements; i++) { + if (strcmp(pInputElementDescs[i].SemanticName, "POSITION") == 0) { + data.vertexStride = 0; + + for (UINT k = 0; k < NumElements; k++) { + data.vertexStride += (UINT)DirectX::BytesPerElement(pInputElementDescs[k].Format); + } + + data.vertexBufferOffset = 0; + + for (UINT k = 0; k < i; k++) { + data.vertexBufferOffset += (UINT)DirectX::BytesPerElement(pInputElementDescs[k].Format); + } + + auto format = pInputElementDescs[i].Format; + if (format == DXGI_FORMAT_R32G32B32A32_FLOAT || format == DXGI_FORMAT_R32G32B32_FLOAT) { + data.vertexFormat = FFX_SURFACE_FORMAT_R32G32B32_FLOAT; + } else if (format == DXGI_FORMAT_R16G16B16A16_FLOAT) { + data.vertexFormat = FFX_SURFACE_FORMAT_R16G16B16A16_FLOAT; + } else { + return; + } + + inputLayouts.insert({ ppInputLayout, data }); + } + } +} + +void BrixelizerContext::UnregisterVertexBuffer(ID3D11Buffer* ppBuffer) +{ + vertexBuffers.erase(ppBuffer); +} + +void BrixelizerContext::UnregisterIndexBuffer(ID3D11Buffer* ppBuffer) +{ + indexBuffers.erase(ppBuffer); +} + +void BrixelizerContext::TransitionResources(D3D12_RESOURCE_STATES stateBefore, D3D12_RESOURCE_STATES stateAfter) +{ + std::vector barriers; + + // Transition the SDF Atlas + barriers.push_back(CD3DX12_RESOURCE_BARRIER::Transition( + sdfAtlas.get(), + stateBefore, + stateAfter)); + + // Transition the Brick AABBs + barriers.push_back(CD3DX12_RESOURCE_BARRIER::Transition( + brickAABBs.get(), + stateBefore, + stateAfter)); + + // Transition each Cascade AABB Tree + for (const auto aabbTree : cascadeAABBTrees) { + barriers.push_back(CD3DX12_RESOURCE_BARRIER::Transition( + aabbTree.get(), + stateBefore, + stateAfter)); + } + + // Transition each Cascade Brick Map + for (const auto brickMap : cascadeBrickMaps) { + barriers.push_back(CD3DX12_RESOURCE_BARRIER::Transition( + brickMap.get(), + stateBefore, + stateAfter)); + } + + // Execute the resource barriers on the command list + Brixelizer::GetSingleton()->commandList->ResourceBarrier(static_cast(barriers.size()), barriers.data()); +} + +FfxBrixelizerDebugVisualizationDescription BrixelizerContext::GetDebugVisualization() +{ + auto state = State::GetSingleton(); + + FfxBrixelizerDebugVisualizationDescription debugVisDesc{}; + + auto frameBufferCached = Brixelizer::GetSingleton()->frameBufferCached; + + auto cameraViewInverseAdjusted = frameBufferCached.CameraViewInverse.Transpose(); + cameraViewInverseAdjusted._41 += frameBufferCached.CameraPosAdjust.x; + cameraViewInverseAdjusted._42 += frameBufferCached.CameraPosAdjust.y; + cameraViewInverseAdjusted._43 += frameBufferCached.CameraPosAdjust.z; + auto cameraProjInverse = frameBufferCached.CameraProjInverse.Transpose(); + + memcpy(&debugVisDesc.inverseViewMatrix, &cameraViewInverseAdjusted, sizeof(debugVisDesc.inverseViewMatrix)); + memcpy(&debugVisDesc.inverseProjectionMatrix, &cameraProjInverse, sizeof(debugVisDesc.inverseProjectionMatrix)); + + debugVisDesc.debugState = m_DebugMode; + + uint32_t cascadeIndexOffset = 0; + + debugVisDesc.startCascadeIndex = cascadeIndexOffset + m_StartCascadeIdx; + debugVisDesc.endCascadeIndex = cascadeIndexOffset + m_EndCascadeIdx; + + debugVisDesc.tMin = m_TMin; + debugVisDesc.tMax = m_TMax; + debugVisDesc.sdfSolveEps = m_SdfSolveEps; + debugVisDesc.renderWidth = (uint)state->screenSize.x; + debugVisDesc.renderHeight = (uint)state->screenSize.y; + debugVisDesc.output = ffxGetResourceDX12(debugRenderTarget.resource.get(), ffxGetResourceDescriptionDX12(debugRenderTarget.resource.get(), FFX_RESOURCE_USAGE_UAV), nullptr, FFX_RESOURCE_STATE_UNORDERED_ACCESS); + + return debugVisDesc; +} + +void BrixelizerContext::UpdateBrixelizerContext() +{ + std::lock_guard lock{ mutex }; + + static auto shadowSceneNode = RE::BSShaderManager::State::GetSingleton().shadowSceneNode[0]; + + RE::BSVisit::TraverseScenegraphGeometries(shadowSceneNode, [&](RE::BSGeometry* a_geometry) -> RE::BSVisit::BSVisitControl { + if (auto triShape = a_geometry->AsTriShape()) { + SeenInstance(triShape); + } + return RE::BSVisit::BSVisitControl::kContinue; + }); + + for (auto it = instances.begin(); it != instances.end();) { + if (it->second.visibleState != visibleStateValue) { + auto error = ffxBrixelizerDeleteInstances(&brixelizerContext, &it->second.instanceID, 1); + if (error != FFX_OK) + logger::critical("error"); + + it = instances.erase(it); + + } else { + ++it; + } + } + + for (auto& queuedInstance : queuedInstances) { + AddInstance(queuedInstance); + } + + // Transition all resources to resource state expected by Brixelizer + TransitionResources(D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE, D3D12_RESOURCE_STATE_UNORDERED_ACCESS); + + FfxBrixelizerDebugVisualizationDescription debugVisDesc = GetDebugVisualization(); + + size_t scratchBufferSize = 0; + + FfxBrixelizerPopulateDebugAABBsFlags populateDebugAABBFlags = FFX_BRIXELIZER_POPULATE_AABBS_NONE; + if (m_ShowStaticInstanceAABBs) + populateDebugAABBFlags = (FfxBrixelizerPopulateDebugAABBsFlags)(populateDebugAABBFlags | FFX_BRIXELIZER_POPULATE_AABBS_STATIC_INSTANCES); + if (m_ShowDynamicInstanceAABBs) + populateDebugAABBFlags = (FfxBrixelizerPopulateDebugAABBsFlags)(populateDebugAABBFlags | FFX_BRIXELIZER_POPULATE_AABBS_DYNAMIC_INSTANCES); + if (m_ShowCascadeAABBs) + populateDebugAABBFlags = (FfxBrixelizerPopulateDebugAABBsFlags)(populateDebugAABBFlags | FFX_BRIXELIZER_POPULATE_AABBS_CASCADE_AABBS); + + auto frameBufferCached = Brixelizer::GetSingleton()->frameBufferCached; + + FfxBrixelizerUpdateDescription updateDesc = { + .frameIndex = RE::BSGraphics::State::GetSingleton()->frameCount, + .sdfCenter = { frameBufferCached.CameraPosAdjust.x, frameBufferCached.CameraPosAdjust.y, frameBufferCached.CameraPosAdjust.z }, + .populateDebugAABBsFlags = populateDebugAABBFlags, + .debugVisualizationDesc = &debugVisDesc, + .maxReferences = 32 * (1 << 20), + .triangleSwapSize = 300 * (1 << 20), + .maxBricksPerBake = 1 << 14, + .outScratchBufferSize = &scratchBufferSize, + .outStats = &stats, + }; + + // Fill out the Brixelizer update description resources. + // Pass in the externally created output resources as FfxResource objects. + updateDesc.resources.sdfAtlas = ffxGetResourceDX12(sdfAtlas.get(), ffxGetResourceDescriptionDX12(sdfAtlas.get(), FFX_RESOURCE_USAGE_UAV), nullptr, FFX_RESOURCE_STATE_UNORDERED_ACCESS); + updateDesc.resources.brickAABBs = ffxGetResourceDX12(brickAABBs.get(), ffxGetResourceDescriptionDX12(brickAABBs.get(), FFX_RESOURCE_USAGE_UAV), nullptr, FFX_RESOURCE_STATE_UNORDERED_ACCESS); + + for (uint32_t i = 0; i < FFX_BRIXELIZER_MAX_CASCADES; ++i) { + updateDesc.resources.cascadeResources[i].aabbTree = ffxGetResourceDX12(cascadeAABBTrees[i].get(), ffxGetResourceDescriptionDX12(cascadeAABBTrees[i].get(), FFX_RESOURCE_USAGE_UAV), nullptr, FFX_RESOURCE_STATE_UNORDERED_ACCESS); + updateDesc.resources.cascadeResources[i].brickMap = ffxGetResourceDX12(cascadeBrickMaps[i].get(), ffxGetResourceDescriptionDX12(cascadeBrickMaps[i].get(), FFX_RESOURCE_USAGE_UAV), nullptr, FFX_RESOURCE_STATE_UNORDERED_ACCESS); + } + + FfxErrorCode error = ffxBrixelizerBakeUpdate(&brixelizerContext, &updateDesc, &bakedUpdateDesc); + if (error != FFX_OK) + logger::critical("error"); + + if (scratchBufferSize >= GPU_SCRATCH_BUFFER_SIZE) + logger::critical("Required Brixelizer scratch memory size larger than available GPU buffer."); + + FfxResource ffxGpuScratchBuffer = ffxGetResourceDX12(gpuScratchBuffer.get(), ffxGetResourceDescriptionDX12(gpuScratchBuffer.get(), FFX_RESOURCE_USAGE_UAV), nullptr, FFX_RESOURCE_STATE_UNORDERED_ACCESS); + ffxGpuScratchBuffer.description.stride = sizeof(uint32_t); + + // Call frame update + error = ffxBrixelizerUpdate(&brixelizerContext, &bakedUpdateDesc, ffxGpuScratchBuffer, ffxGetCommandListDX12(Brixelizer::GetSingleton()->commandList.get())); + if (error != FFX_OK) + logger::critical("error"); + + // Transition all resources to the Non-Pixel Shader Resource state after the Brixelizer + TransitionResources(D3D12_RESOURCE_STATE_UNORDERED_ACCESS, D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE); + + visibleStateValue = !visibleStateValue; +} \ No newline at end of file diff --git a/src/Brixelizer/BrixelizerContext.h b/src/Brixelizer/BrixelizerContext.h new file mode 100644 index 000000000..c4e1f4471 --- /dev/null +++ b/src/Brixelizer/BrixelizerContext.h @@ -0,0 +1,180 @@ +#pragma once + +#include +#include + +#include +#include + +#include "Brixelizer.h" + +class BrixelizerContext +{ +public: + static BrixelizerContext* GetSingleton() + { + static BrixelizerContext singleton; + return &singleton; + } + + FfxBrixelizerContextDescription initializationParameters = {}; + FfxBrixelizerContext brixelizerContext = {}; + FfxBrixelizerBakedUpdateDescription brixelizerBakedUpdateDesc = {}; + FfxBrixelizerStats stats = {}; + FfxBrixelizerBakedUpdateDescription bakedUpdateDesc = {}; + + std::shared_mutex mutex; + + winrt::com_ptr sdfAtlas; + winrt::com_ptr brickAABBs; + winrt::com_ptr gpuScratchBuffer; + + winrt::com_ptr cascadeAABBTrees[FFX_BRIXELIZER_MAX_CASCADES]; + winrt::com_ptr cascadeBrickMaps[FFX_BRIXELIZER_MAX_CASCADES]; + + Brixelizer::WrappedResource debugRenderTarget; + + FfxBrixelizerTraceDebugModes m_DebugMode = FFX_BRIXELIZER_TRACE_DEBUG_MODE_GRAD; + + int m_StartCascadeIdx = 0; + int m_EndCascadeIdx = NUM_BRIXELIZER_CASCADES - 1; + + float m_TMin = 0.0f; + float m_TMax = 10000.0f; + float m_SdfSolveEps = 0.5f; + + bool m_ShowStaticInstanceAABBs = false; + bool m_ShowDynamicInstanceAABBs = false; + bool m_ShowCascadeAABBs = false; + int m_ShowAABBTreeIndex = -1; + + float m_RayPushoff = 0.25f; + + winrt::com_ptr CreateBuffer(UINT64 size, D3D12_RESOURCE_STATES resourceState, D3D12_RESOURCE_FLAGS flags); + + void InitBrixelizerContext(); + + struct BufferData + { + winrt::com_ptr buffer; + bool registered = false; + uint width; + uint index; + }; + + eastl::hash_map vertexBuffers; + eastl::hash_map indexBuffers; + + struct InputLayoutData + { + uint32_t vertexStride; + uint32_t vertexBufferOffset; + FfxSurfaceFormat vertexFormat; + }; + + eastl::hash_map inputLayouts; + eastl::hash_map vertexDescToInputLayout; + + struct InstanceData + { + FfxBrixelizerInstanceID instanceID; + bool visibleState = false; + }; + + bool visibleStateValue = true; + + eastl::hash_set queuedInstances; + eastl::hash_map instances; + + BufferData AllocateBuffer(const D3D11_BUFFER_DESC* pDesc, const D3D11_SUBRESOURCE_DATA* pInitialData); + + void RegisterVertexBuffer(const D3D11_BUFFER_DESC* pDesc, const D3D11_SUBRESOURCE_DATA* pInitialData, ID3D11Buffer** ppBuffer); + void RegisterIndexBuffer(const D3D11_BUFFER_DESC* pDesc, const D3D11_SUBRESOURCE_DATA* pInitialData, ID3D11Buffer** ppBuffer); + void RegisterInputLayout(ID3D11InputLayout* ppInputLayout, D3D11_INPUT_ELEMENT_DESC* pInputElementDescs, UINT NumElements); + + void UnregisterVertexBuffer(ID3D11Buffer* ppBuffer); + void UnregisterIndexBuffer(ID3D11Buffer* ppBuffer); + + uint GetBufferIndex(BufferData& a_bufferData); + + void AddInstance(RE::BSTriShape* geometry); + void SeenInstance(RE::BSTriShape* geometry); + void RemoveInstance(RE::BSTriShape* a_geometry); + + void TransitionResources(D3D12_RESOURCE_STATES stateBefore, D3D12_RESOURCE_STATES stateAfter); + + FfxBrixelizerDebugVisualizationDescription GetDebugVisualization(); + + void UpdateBrixelizerContext(); + void UpdateScene(); + void BSTriShape_UpdateWorldData(RE::BSTriShape* This, RE::NiUpdateData* a_data); + + struct Hooks + { + struct ID3D11Device_CreateBuffer + { + static HRESULT thunk(ID3D11Device* This, const D3D11_BUFFER_DESC* pDesc, const D3D11_SUBRESOURCE_DATA* pInitialData, ID3D11Buffer** ppBuffer) + { + HRESULT hr = func(This, pDesc, pInitialData, ppBuffer); + + if (pInitialData) { + if (pDesc->BindFlags & D3D11_BIND_VERTEX_BUFFER) { + GetSingleton()->RegisterVertexBuffer(pDesc, pInitialData, ppBuffer); + } else if (pDesc->BindFlags & D3D11_BIND_INDEX_BUFFER) { + GetSingleton()->RegisterIndexBuffer(pDesc, pInitialData, ppBuffer); + } + } + + return hr; + } + static inline REL::Relocation func; + }; + + struct ID3D11Device_CreateInputLayout + { + static HRESULT thunk(ID3D11Device* This, D3D11_INPUT_ELEMENT_DESC* pInputElementDescs, UINT NumElements, void* pShaderBytecodeWithInputSignature, SIZE_T BytecodeLength, ID3D11InputLayout** ppInputLayout) + { + HRESULT hr = func(This, pInputElementDescs, NumElements, pShaderBytecodeWithInputSignature, BytecodeLength, ppInputLayout); + + if (pInputElementDescs && NumElements > 0) { + GetSingleton()->RegisterInputLayout(*ppInputLayout, pInputElementDescs, NumElements); + } + + return hr; + } + static inline REL::Relocation func; + }; + + struct BSTriShape_UpdateWorldData + { + static void thunk(RE::BSTriShape* This, RE::NiUpdateData* a_data) + { + GetSingleton()->BSTriShape_UpdateWorldData(This, a_data); + } + static inline REL::Relocation func; + }; + + struct DirtyStates_CreateInputLayoutFromVertexDesc + { + static ID3D11InputLayout* thunk(uint64_t a_vertexDesc) + { + auto inputLayout = func(a_vertexDesc); + GetSingleton()->vertexDescToInputLayout.insert({ a_vertexDesc, inputLayout }); + return inputLayout; + } + static inline REL::Relocation func; + }; + + static void Install() + { + if (REL::Module::IsAE()) { + stl::write_vfunc<0x31, BSTriShape_UpdateWorldData>(RE::VTABLE_BSTriShape[0]); + } else { + stl::write_vfunc<0x30, BSTriShape_UpdateWorldData>(RE::VTABLE_BSTriShape[0]); + } + stl::write_thunk_call(REL::RelocationID(75580, 75580).address() + REL::Relocate(0x465, 0x465)); + + logger::info("[BrixelizerContext] Installed hooks"); + } + }; +}; diff --git a/src/Brixelizer/BrixelizerGIContext.cpp b/src/Brixelizer/BrixelizerGIContext.cpp new file mode 100644 index 000000000..08584eeeb --- /dev/null +++ b/src/Brixelizer/BrixelizerGIContext.cpp @@ -0,0 +1,367 @@ +#include "BrixelizerGIContext.h" + +#include +#include + +#include "Deferred.h" +#include "Util.h" +#include "BrixelizerContext.h" + +void BrixelizerGIContext::CreateMiscTextures() +{ + const auto displaySize = State::GetSingleton()->screenSize; + + D3D11_TEXTURE2D_DESC texDesc; + texDesc.Width = (UINT)displaySize.x; + texDesc.Height = (UINT)displaySize.y; + texDesc.MipLevels = 1; + texDesc.ArraySize = 1; + texDesc.Format = DXGI_FORMAT_R32_FLOAT; + texDesc.SampleDesc.Count = 1; + texDesc.SampleDesc.Quality = 0; + texDesc.Usage = D3D11_USAGE_DEFAULT; + texDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_UNORDERED_ACCESS; + texDesc.CPUAccessFlags = 0; + texDesc.MiscFlags = D3D11_RESOURCE_MISC_SHARED_NTHANDLE | D3D11_RESOURCE_MISC_SHARED; + + CD3DX12_HEAP_PROPERTIES heapProperties(D3D12_HEAP_TYPE_DEFAULT); + + Brixelizer::CreatedWrappedResource(texDesc, depth); + Brixelizer::CreatedWrappedResource(texDesc, historyDepth); + + texDesc.Format = DXGI_FORMAT_R16G16B16A16_FLOAT; + + Brixelizer::CreatedWrappedResource(texDesc, normal); + Brixelizer::CreatedWrappedResource(texDesc, historyNormal); + + Brixelizer::CreatedWrappedResource(texDesc, prevLitOutput); + Brixelizer::CreatedWrappedResource(texDesc, diffuseGi); + Brixelizer::CreatedWrappedResource(texDesc, specularGi); +} + +void BrixelizerGIContext::CreateNoiseTextures() +{ + auto& device = State::GetSingleton()->device; + auto& context = State::GetSingleton()->context; + + for (int i = 0; i < 16; i++) { + winrt::com_ptr noiseTexture11; + + wchar_t filePath[128]; + swprintf(filePath, 128, L"Data\\Shaders\\Brixelizer\\Noise\\LDR_RG01_%d.dds", i); + + DirectX::CreateDDSTextureFromFileEx( + device, + context, + filePath, + SIZE_T_MAX, + D3D11_USAGE_DEFAULT, + D3D11_BIND_SHADER_RESOURCE, + 0u, + D3D11_RESOURCE_MISC_SHARED_NTHANDLE | D3D11_RESOURCE_MISC_SHARED, + DirectX::DDS_LOADER_FLAGS::DDS_LOADER_DEFAULT, + noiseTexture11.put(), + nullptr); + + // Query the DXGIResource1 interface to access shared NT handle + winrt::com_ptr dxgiResource1; + DX::ThrowIfFailed(noiseTexture11->QueryInterface(IID_PPV_ARGS(&dxgiResource1))); + + // Create the shared NT handle + HANDLE sharedNtHandle = nullptr; + DX::ThrowIfFailed(dxgiResource1->CreateSharedHandle(nullptr, DXGI_SHARED_RESOURCE_READ, nullptr, &sharedNtHandle)); + + // Open the shared handle in D3D12 + winrt::com_ptr d3d12Resource; + DX::ThrowIfFailed(Brixelizer::GetSingleton()->d3d12Device->OpenSharedHandle(sharedNtHandle, IID_PPV_ARGS(&d3d12Resource))); + CloseHandle(sharedNtHandle); // Close the handle after opening it in D3D12 + + winrt::com_ptr texture11; + DX::ThrowIfFailed(noiseTexture11->QueryInterface(IID_PPV_ARGS(&texture11))); + + D3D11_TEXTURE2D_DESC texDesc11{}; + texture11->GetDesc(&texDesc11); + + D3D12_RESOURCE_DESC texDesc = {}; + texDesc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D; + texDesc.Width = texDesc11.Width; + texDesc.Height = texDesc11.Height; + texDesc.DepthOrArraySize = 1; + texDesc.MipLevels = 1; + texDesc.Format = texDesc11.Format; + texDesc.SampleDesc.Count = 1; + texDesc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN; + texDesc.Flags = D3D12_RESOURCE_FLAG_NONE; + + CD3DX12_HEAP_PROPERTIES heapProperties(D3D12_HEAP_TYPE_DEFAULT); + DX::ThrowIfFailed(Brixelizer::GetSingleton()->d3d12Device->CreateCommittedResource( + &heapProperties, + D3D12_HEAP_FLAG_NONE, + &texDesc, + D3D12_RESOURCE_STATE_COPY_DEST, + nullptr, + IID_PPV_ARGS(&noiseTextures[i]))); + + { + std::vector barriers{ + CD3DX12_RESOURCE_BARRIER::Transition(d3d12Resource.get(), + D3D12_RESOURCE_STATE_COMMON, + D3D12_RESOURCE_STATE_COPY_SOURCE) + }; + Brixelizer::GetSingleton()->commandList->ResourceBarrier(static_cast(barriers.size()), barriers.data()); + } + + Brixelizer::GetSingleton()->commandList->CopyResource(noiseTextures[i].get(), d3d12Resource.get()); + + { + std::vector barriers{ + CD3DX12_RESOURCE_BARRIER::Transition(d3d12Resource.get(), + D3D12_RESOURCE_STATE_COPY_SOURCE, + D3D12_RESOURCE_STATE_COMMON), + CD3DX12_RESOURCE_BARRIER::Transition(noiseTextures[i].get(), + D3D12_RESOURCE_STATE_COPY_DEST, + D3D12_RESOURCE_STATE_COMMON), + }; + Brixelizer::GetSingleton()->commandList->ResourceBarrier(static_cast(barriers.size()), barriers.data()); + } + } +} + +void BrixelizerGIContext::InitBrixelizerGIContext() +{ + const auto displaySize = State::GetSingleton()->screenSize; + + // Context Creation + FfxBrixelizerGIContextDescription desc = { + .flags = FFX_BRIXELIZER_GI_FLAG_DEPTH_INVERTED, + .internalResolution = FFX_BRIXELIZER_GI_INTERNAL_RESOLUTION_50_PERCENT, + .displaySize = { static_cast(displaySize.x), static_cast(displaySize.y) }, + .backendInterface = BrixelizerContext::GetSingleton()->initializationParameters.backendInterface, + }; + if (ffxBrixelizerGIContextCreate(&brixelizerGIContext, &desc) != FFX_OK) + logger::critical("Failed to create Brixelizer GI context."); + if (ffxBrixelizerGIGetEffectVersion() == FFX_SDK_MAKE_VERSION(1, 0, 0)) + logger::critical("FidelityFX Brixelizer GI sample requires linking with a 1.0 version Brixelizer GI library."); + + // Resource Creation + D3D12_RESOURCE_DESC texDesc = { + .Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D, + .Width = static_cast(displaySize.x), + .Height = static_cast(displaySize.y), + .DepthOrArraySize = 1, + .MipLevels = 1, + .Format = DXGI_FORMAT_R16G16B16A16_FLOAT, + .SampleDesc = { .Count = 1 }, + .Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN, + .Flags = D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS | D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET, + }; + + CD3DX12_HEAP_PROPERTIES heapProperties(D3D12_HEAP_TYPE_DEFAULT); + + CreateMiscTextures(); + CreateNoiseTextures(); +} + +ID3D11ComputeShader* BrixelizerGIContext::GetCopyToSharedBufferCS() +{ + if (!copyToSharedBufferCS) + copyToSharedBufferCS = (ID3D11ComputeShader*)Util::CompileShader(L"Data\\Shaders\\Brixelizer\\CopyToSharedBufferCS.hlsl", {}, "cs_5_0"); + return copyToSharedBufferCS; +} + +void BrixelizerGIContext::ClearShaderCache() +{ + if (copyToSharedBufferCS) + copyToSharedBufferCS->Release(); + copyToSharedBufferCS = nullptr; +} + +void BrixelizerGIContext::CopyResourcesToSharedBuffers() +{ + auto& context = State::GetSingleton()->context; + auto renderer = RE::BSGraphics::Renderer::GetSingleton(); + + auto& depth11 = renderer->GetDepthStencilData().depthStencils[RE::RENDER_TARGETS_DEPTHSTENCIL::kPOST_ZPREPASS_COPY]; + auto& normalRoughness = renderer->GetRuntimeData().renderTargets[NORMALROUGHNESS]; + + { + auto dispatchCount = Util::GetScreenDispatchCount(true); + + ID3D11ShaderResourceView* views[2] = { depth11.depthSRV, normalRoughness.SRV }; + context->CSSetShaderResources(0, ARRAYSIZE(views), views); + + ID3D11UnorderedAccessView* uavs[2] = { depth.uav, normal.uav }; + context->CSSetUnorderedAccessViews(0, ARRAYSIZE(uavs), uavs, nullptr); + + context->CSSetShader(GetCopyToSharedBufferCS(), nullptr, 0); + + context->Dispatch(dispatchCount.x, dispatchCount.y, 1); + } + + ID3D11ShaderResourceView* views[2] = { nullptr, nullptr }; + context->CSSetShaderResources(0, ARRAYSIZE(views), views); + + ID3D11UnorderedAccessView* uavs[2] = { nullptr, nullptr }; + context->CSSetUnorderedAccessViews(0, ARRAYSIZE(uavs), uavs, nullptr); + + ID3D11ComputeShader* shader = nullptr; + context->CSSetShader(shader, nullptr, 0); +} + +void BrixelizerGIContext::UpdateBrixelizerGIContext() +{ + auto brixelizer = Brixelizer::GetSingleton(); + auto brixelizerContext = BrixelizerContext::GetSingleton(); + + auto& normalsRoughness = brixelizer->renderTargetsD3D12[NORMALROUGHNESS]; + auto& motionVectors = brixelizer->renderTargetsD3D12[RE::RENDER_TARGET::kMOTION_VECTOR]; + + auto& main = brixelizer->renderTargetsD3D12[Deferred::GetSingleton()->forwardRenderTargets[0]]; + + auto& environmentMap = brixelizer->renderTargetsCubemapD3D12[RE::RENDER_TARGET_CUBEMAP::kREFLECTIONS]; + + auto frameBufferCached = brixelizer->frameBufferCached; + + auto view = frameBufferCached.CameraView.Transpose(); + view._41 -= frameBufferCached.CameraPosAdjust.x; + view._42 -= frameBufferCached.CameraPosAdjust.y; + view._43 -= frameBufferCached.CameraPosAdjust.z; + + auto projection = frameBufferCached.CameraProj.Transpose(); + + static auto prevView = view; + static auto prevProjection = projection; + + uint noiseIndex = RE::BSGraphics::State::GetSingleton()->frameCount % 16u; + + { + std::vector barriers{ + CD3DX12_RESOURCE_BARRIER::Transition(depth.resource.get(), + D3D12_RESOURCE_STATE_COMMON, + D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE), + CD3DX12_RESOURCE_BARRIER::Transition(normal.resource.get(), + D3D12_RESOURCE_STATE_COMMON, + D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE), + CD3DX12_RESOURCE_BARRIER::Transition(normalsRoughness.d3d12Resource.get(), + D3D12_RESOURCE_STATE_COMMON, + D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE), + CD3DX12_RESOURCE_BARRIER::Transition(motionVectors.d3d12Resource.get(), + D3D12_RESOURCE_STATE_COMMON, + D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE), + CD3DX12_RESOURCE_BARRIER::Transition(historyDepth.resource.get(), + D3D12_RESOURCE_STATE_COMMON, + D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE), + CD3DX12_RESOURCE_BARRIER::Transition(historyNormal.resource.get(), + D3D12_RESOURCE_STATE_COMMON, + D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE), + CD3DX12_RESOURCE_BARRIER::Transition(main.d3d12Resource.get(), + D3D12_RESOURCE_STATE_COMMON, + D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE), + CD3DX12_RESOURCE_BARRIER::Transition(noiseTextures[noiseIndex].get(), + D3D12_RESOURCE_STATE_COMMON, + D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE), + CD3DX12_RESOURCE_BARRIER::Transition(diffuseGi.resource.get(), + D3D12_RESOURCE_STATE_COMMON, + D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE), + CD3DX12_RESOURCE_BARRIER::Transition(specularGi.resource.get(), + D3D12_RESOURCE_STATE_COMMON, + D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE) + }; + brixelizer->commandList->ResourceBarrier(static_cast(barriers.size()), barriers.data()); + } + + { + memcpy(&giDispatchDesc.view, &view, sizeof(giDispatchDesc.view)); + memcpy(&giDispatchDesc.projection, &projection, sizeof(giDispatchDesc.projection)); + memcpy(&giDispatchDesc.prevView, &prevView, sizeof(giDispatchDesc.prevView)); + memcpy(&giDispatchDesc.prevProjection, &prevProjection, sizeof(giDispatchDesc.prevProjection)); + + prevView = view; + prevProjection = projection; + + memcpy(&giDispatchDesc.cameraPosition, &frameBufferCached.CameraPosAdjust, sizeof(giDispatchDesc.cameraPosition)); + + giDispatchDesc.startCascade = brixelizerContext->m_StartCascadeIdx + (2 * NUM_BRIXELIZER_CASCADES); + giDispatchDesc.endCascade = brixelizerContext->m_EndCascadeIdx + (2 * NUM_BRIXELIZER_CASCADES); + giDispatchDesc.rayPushoff = brixelizerContext->m_RayPushoff; + giDispatchDesc.sdfSolveEps = brixelizerContext->m_SdfSolveEps; + giDispatchDesc.specularRayPushoff = brixelizerContext->m_RayPushoff; + giDispatchDesc.specularSDFSolveEps = brixelizerContext->m_SdfSolveEps; + giDispatchDesc.tMin = brixelizerContext->m_TMin; + giDispatchDesc.tMax = brixelizerContext->m_TMax; + + giDispatchDesc.normalsUnpackMul = 2.0f; + giDispatchDesc.normalsUnpackAdd = -1.0f; + giDispatchDesc.isRoughnessPerceptual = false; + giDispatchDesc.roughnessChannel = 1; + giDispatchDesc.roughnessThreshold = 0.9f; + giDispatchDesc.environmentMapIntensity = 0.0f; + giDispatchDesc.motionVectorScale = { 1.0f, 1.0f }; + + giDispatchDesc.depth = ffxGetResourceDX12(depth.resource.get(), ffxGetResourceDescriptionDX12(depth.resource.get(), FFX_RESOURCE_USAGE_READ_ONLY), L"Depth", FFX_RESOURCE_STATE_COMPUTE_READ); + + giDispatchDesc.normal = ffxGetResourceDX12(normal.resource.get(), ffxGetResourceDescriptionDX12(normal.resource.get(), FFX_RESOURCE_USAGE_READ_ONLY), L"Normal", FFX_RESOURCE_STATE_COMPUTE_READ); + giDispatchDesc.roughness = ffxGetResourceDX12(normalsRoughness.d3d12Resource.get(), ffxGetResourceDescriptionDX12(normalsRoughness.d3d12Resource.get(), FFX_RESOURCE_USAGE_READ_ONLY), L"Roughness", FFX_RESOURCE_STATE_COMPUTE_READ); + giDispatchDesc.motionVectors = ffxGetResourceDX12(motionVectors.d3d12Resource.get(), ffxGetResourceDescriptionDX12(motionVectors.d3d12Resource.get(), FFX_RESOURCE_USAGE_READ_ONLY), L"MotionVectors", FFX_RESOURCE_STATE_COMPUTE_READ); + + giDispatchDesc.historyDepth = ffxGetResourceDX12(historyDepth.resource.get(), ffxGetResourceDescriptionDX12(historyDepth.resource.get(), FFX_RESOURCE_USAGE_READ_ONLY), L"HistoryDepth", FFX_RESOURCE_STATE_COMPUTE_READ); + giDispatchDesc.historyNormal = ffxGetResourceDX12(historyNormal.resource.get(), ffxGetResourceDescriptionDX12(historyNormal.resource.get(), FFX_RESOURCE_USAGE_READ_ONLY), L"HistoryNormal", FFX_RESOURCE_STATE_COMPUTE_READ); + giDispatchDesc.prevLitOutput = ffxGetResourceDX12(main.d3d12Resource.get(), ffxGetResourceDescriptionDX12(main.d3d12Resource.get(), FFX_RESOURCE_USAGE_READ_ONLY), L"PrevLitOutput", FFX_RESOURCE_STATE_COMPUTE_READ); + + giDispatchDesc.noiseTexture = ffxGetResourceDX12(noiseTextures[noiseIndex].get(), ffxGetResourceDescriptionDX12(noiseTextures[noiseIndex].get(), FFX_RESOURCE_USAGE_READ_ONLY), L"Noise", FFX_RESOURCE_STATE_COMPUTE_READ); + giDispatchDesc.environmentMap = ffxGetResourceDX12(environmentMap.d3d12Resource.get(), ffxGetResourceDescriptionDX12(environmentMap.d3d12Resource.get(), FFX_RESOURCE_USAGE_READ_ONLY), L"EnvironmentMap", FFX_RESOURCE_STATE_COMPUTE_READ); + + giDispatchDesc.sdfAtlas = ffxGetResourceDX12(brixelizerContext->sdfAtlas.get(), ffxGetResourceDescriptionDX12(brixelizerContext->sdfAtlas.get(), FFX_RESOURCE_USAGE_READ_ONLY), nullptr, FFX_RESOURCE_STATE_COMPUTE_READ); + giDispatchDesc.bricksAABBs = ffxGetResourceDX12(brixelizerContext->brickAABBs.get(), ffxGetResourceDescriptionDX12(brixelizerContext->brickAABBs.get(), FFX_RESOURCE_USAGE_READ_ONLY), nullptr, FFX_RESOURCE_STATE_COMPUTE_READ); + + for (uint32_t i = 0; i < FFX_BRIXELIZER_MAX_CASCADES; ++i) { + giDispatchDesc.cascadeAABBTrees[i] = ffxGetResourceDX12(brixelizerContext->cascadeAABBTrees[i].get(), ffxGetResourceDescriptionDX12(brixelizerContext->cascadeAABBTrees[i].get(), FFX_RESOURCE_USAGE_READ_ONLY), nullptr, FFX_RESOURCE_STATE_COMPUTE_READ); + giDispatchDesc.cascadeBrickMaps[i] = ffxGetResourceDX12(brixelizerContext->cascadeBrickMaps[i].get(), ffxGetResourceDescriptionDX12(brixelizerContext->cascadeBrickMaps[i].get(), FFX_RESOURCE_USAGE_READ_ONLY), nullptr, FFX_RESOURCE_STATE_COMPUTE_READ); + } + + giDispatchDesc.outputDiffuseGI = ffxGetResourceDX12(diffuseGi.resource.get(), ffxGetResourceDescriptionDX12(diffuseGi.resource.get(), FFX_RESOURCE_USAGE_UAV), L"OutputDiffuseGI", FFX_RESOURCE_STATE_UNORDERED_ACCESS); + giDispatchDesc.outputSpecularGI = ffxGetResourceDX12(specularGi.resource.get(), ffxGetResourceDescriptionDX12(specularGi.resource.get(), FFX_RESOURCE_USAGE_UAV), L"OutputSpecularGI", FFX_RESOURCE_STATE_UNORDERED_ACCESS); + + if (ffxBrixelizerGetRawContext(&brixelizerContext->brixelizerContext, &giDispatchDesc.brixelizerContext) != FFX_OK) + logger::error("Failed to get Brixelizer context pointer."); + + if (ffxBrixelizerGIContextDispatch(&brixelizerGIContext, &giDispatchDesc, ffxGetCommandListDX12(brixelizer->commandList.get())) != FFX_OK) + logger::error("Failed to dispatch Brixelizer GI."); + } + + { + std::vector barriers{ + CD3DX12_RESOURCE_BARRIER::Transition(depth.resource.get(), + D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE, + D3D12_RESOURCE_STATE_COMMON), + CD3DX12_RESOURCE_BARRIER::Transition(normal.resource.get(), + D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE, + D3D12_RESOURCE_STATE_COMMON), + CD3DX12_RESOURCE_BARRIER::Transition(normalsRoughness.d3d12Resource.get(), + D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE, + D3D12_RESOURCE_STATE_COMMON), + CD3DX12_RESOURCE_BARRIER::Transition(motionVectors.d3d12Resource.get(), + D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE, + D3D12_RESOURCE_STATE_COMMON), + CD3DX12_RESOURCE_BARRIER::Transition(historyDepth.resource.get(), + D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE, + D3D12_RESOURCE_STATE_COMMON), + CD3DX12_RESOURCE_BARRIER::Transition(historyNormal.resource.get(), + D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE, + D3D12_RESOURCE_STATE_COMMON), + CD3DX12_RESOURCE_BARRIER::Transition(main.d3d12Resource.get(), + D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE, + D3D12_RESOURCE_STATE_COMMON), + CD3DX12_RESOURCE_BARRIER::Transition(noiseTextures[noiseIndex].get(), + D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE, + D3D12_RESOURCE_STATE_COMMON), + CD3DX12_RESOURCE_BARRIER::Transition(diffuseGi.resource.get(), + D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE, + D3D12_RESOURCE_STATE_COMMON), + CD3DX12_RESOURCE_BARRIER::Transition(specularGi.resource.get(), + D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE, + D3D12_RESOURCE_STATE_COMMON) + }; + brixelizer->commandList->ResourceBarrier(static_cast(barriers.size()), barriers.data()); + } +} diff --git a/src/Brixelizer/BrixelizerGIContext.h b/src/Brixelizer/BrixelizerGIContext.h new file mode 100644 index 000000000..d70790ed4 --- /dev/null +++ b/src/Brixelizer/BrixelizerGIContext.h @@ -0,0 +1,51 @@ +#pragma once + +#include +#include + +#include +#include + +#include "Brixelizer.h" + +class BrixelizerGIContext +{ +public: + static BrixelizerGIContext* GetSingleton() + { + static BrixelizerGIContext singleton; + return &singleton; + } + + FfxBrixelizerGIContextDescription giInitializationParameters = {}; + FfxBrixelizerGIDispatchDescription giDispatchDesc = {}; + FfxBrixelizerGIContext brixelizerGIContext = {}; + + Brixelizer::WrappedResource diffuseGi; + Brixelizer::WrappedResource specularGi; + + Brixelizer::WrappedResource depth; + Brixelizer::WrappedResource normal; + + Brixelizer::WrappedResource historyDepth; + Brixelizer::WrappedResource historyNormal; + Brixelizer::WrappedResource prevLitOutput; + + winrt::com_ptr noiseTextures[16]; + + ID3D11ComputeShader* copyToSharedBufferCS; + ID3D11ComputeShader* GetCopyToSharedBufferCS(); + + void ClearShaderCache(); + + void CopyResourcesToSharedBuffers(); + + void CreateMiscTextures(); + void CreateNoiseTextures(); + + void InitBrixelizerGIContext(); + + void UpdateBrixelizerGIContext(); + + void CopyHistoryResources(); +}; diff --git a/src/Deferred.cpp b/src/Deferred.cpp index b2237f3e7..2d6caed84 100644 --- a/src/Deferred.cpp +++ b/src/Deferred.cpp @@ -11,7 +11,9 @@ #include "Features/SubsurfaceScattering.h" #include "Features/TerrainBlending.h" -#include "Raytracing.h" +#include "Brixelizer.h" +#include "Brixelizer/BrixelizerContext.h" +#include "Brixelizer/BrixelizerGIContext.h" struct DepthStates { @@ -331,7 +333,7 @@ void Deferred::DeferredPasses() } } - Raytracing::GetSingleton()->FrameUpdate(); + Brixelizer::GetSingleton()->FrameUpdate(); auto specular = renderer->GetRuntimeData().renderTargets[SPECULAR]; auto albedo = renderer->GetRuntimeData().renderTargets[ALBEDO]; @@ -425,9 +427,9 @@ void Deferred::DeferredPasses() dynamicCubemaps->loaded && skylighting->loaded ? skylighting->texProbeArray->srv.get() : nullptr, ssgi_y, ssgi_cocg, - Raytracing::GetSingleton()->debugRenderTarget.srv, - Raytracing::GetSingleton()->diffuseGi.srv, - Raytracing::GetSingleton()->specularGi.srv, + BrixelizerContext::GetSingleton()->debugRenderTarget.srv, + BrixelizerGIContext::GetSingleton()->diffuseGi.srv, + BrixelizerGIContext::GetSingleton()->specularGi.srv, }; if (dynamicCubemaps->loaded) @@ -495,8 +497,6 @@ void Deferred::EndDeferred() deferredPass = false; ResetBlendStates(); - - Raytracing::GetSingleton()->PostFrameUpdate(); } void Deferred::OverrideBlendStates() diff --git a/src/Features/LightLimitFix.h b/src/Features/LightLimitFix.h index eb8560b0f..1dbe7ac2f 100644 --- a/src/Features/LightLimitFix.h +++ b/src/Features/LightLimitFix.h @@ -7,9 +7,8 @@ #include #include "Feature.h" -#include "Raytracing.h" #include "ShaderCache.h" -#include +#include "Features/LightLimitFix/ParticleLights.h" struct LightLimitFix : Feature { @@ -307,19 +306,6 @@ struct LightLimitFix : Feature static inline REL::Relocation func; }; - struct NiNode_Destroy - { - static void thunk(RE::NiNode* This) - { - GetSingleton()->CleanupParticleLights(This); - if (auto triShape = This->AsTriShape()) - Raytracing::GetSingleton()->RemoveInstance(triShape); - - func(This); - } - static inline REL::Relocation func; - }; - static void Install() { stl::write_thunk_call(REL::RelocationID(100877, 107673).address() + REL::Relocate(0x1E5, 0x1EE)); @@ -334,8 +320,6 @@ struct LightLimitFix : Feature stl::write_thunk_call(REL::RelocationID(100565, 107300).address() + REL::Relocate(0x523, 0xB0E, 0x5fe)); - stl::detour_thunk(REL::RelocationID(68937, 70288)); - logger::info("[LLF] Installed hooks"); } }; diff --git a/src/Hooks.cpp b/src/Hooks.cpp index d6e53d880..49e56c6ae 100644 --- a/src/Hooks.cpp +++ b/src/Hooks.cpp @@ -10,7 +10,10 @@ #include "Streamline.h" -#include "Raytracing.h" +#include "Brixelizer.h" +#include "Brixelizer/BrixelizerContext.h" + +#include "Features/LightLimitFix.h" std::unordered_map, size_t>> ShaderBytecodeMap; @@ -179,37 +182,6 @@ void Hooks::BSGraphics_SetDirtyStates::thunk(bool isCompute) State::GetSingleton()->Draw(); } -struct ID3D11DeviceContext_Map -{ - static HRESULT thunk(ID3D11DeviceContext* This, ID3D11Resource* pResource, UINT Subresource, D3D11_MAP MapType, UINT MapFlags, D3D11_MAPPED_SUBRESOURCE* pMappedResource) - { - HRESULT hr = func(This, pResource, Subresource, MapType, MapFlags, pMappedResource); - - static REL::Relocation perFrame{ REL::RelocationID(524768, 411384) }; - - if (*perFrame.get() == pResource) { - Raytracing::GetSingleton()->mappedFrameBuffer = pMappedResource; - } - - return hr; - } - static inline REL::Relocation func; -}; - -struct ID3D11DeviceContext_Unmap -{ - static void thunk(ID3D11DeviceContext* This, ID3D11Resource* pResource, UINT Subresource) - { - static REL::Relocation perFrame{ REL::RelocationID(524768, 411384) }; - - if (*perFrame.get() == pResource && Raytracing::GetSingleton()->mappedFrameBuffer) - Raytracing::GetSingleton()->CacheFramebuffer(); - - func(This, pResource, Subresource); - } - static inline REL::Relocation func; -}; - struct ID3D11Device_CreateVertexShader { static HRESULT thunk(ID3D11Device* This, const void* pShaderBytecode, SIZE_T BytecodeLength, ID3D11ClassLinkage* pClassLinkage, ID3D11VertexShader** ppVertexShader) @@ -245,40 +217,6 @@ HRESULT WINAPI hk_CreateDXGIFactory(REFIID, void** ppFactory) return Streamline::GetSingleton()->CreateDXGIFactory(__uuidof(IDXGIFactory1), ppFactory); } -struct ID3D11Device_CreateBuffer -{ - static HRESULT thunk(ID3D11Device* This, const D3D11_BUFFER_DESC* pDesc, const D3D11_SUBRESOURCE_DATA* pInitialData, ID3D11Buffer** ppBuffer) - { - HRESULT hr = func(This, pDesc, pInitialData, ppBuffer); - - if (pInitialData) { - if (pDesc->BindFlags & D3D11_BIND_VERTEX_BUFFER) { - Raytracing::GetSingleton()->RegisterVertexBuffer(pDesc, pInitialData, ppBuffer); - } else if (pDesc->BindFlags & D3D11_BIND_INDEX_BUFFER) { - Raytracing::GetSingleton()->RegisterIndexBuffer(pDesc, pInitialData, ppBuffer); - } - } - - return hr; - } - static inline REL::Relocation func; -}; - -struct ID3D11Device_CreateInputLayout -{ - static HRESULT thunk(ID3D11Device* This, D3D11_INPUT_ELEMENT_DESC* pInputElementDescs, UINT NumElements, void* pShaderBytecodeWithInputSignature, SIZE_T BytecodeLength, ID3D11InputLayout** ppInputLayout) - { - HRESULT hr = func(This, pInputElementDescs, NumElements, pShaderBytecodeWithInputSignature, BytecodeLength, ppInputLayout); - - if (pInputElementDescs && NumElements > 0) { - Raytracing::GetSingleton()->RegisterInputLayout(*ppInputLayout, pInputElementDescs, NumElements); - } - - return hr; - } - static inline REL::Relocation func; -}; - decltype(&D3D11CreateDeviceAndSwapChain) ptrD3D11CreateDeviceAndSwapChain; #include "d3d11on12.h" @@ -325,7 +263,7 @@ HRESULT WINAPI hk_D3D11CreateDeviceAndSwapChainNoStreamline( [[maybe_unused]] D3D_FEATURE_LEVEL* pFeatureLevel, ID3D11DeviceContext** ppImmediateContext) { - Raytracing::GetSingleton()->InitD3D12(pAdapter); + Brixelizer::GetSingleton()->InitD3D12(pAdapter); //winrt::com_ptr dxgiFactory; @@ -508,8 +446,6 @@ namespace Hooks auto swapchain = reinterpret_cast(manager->GetRuntimeData().renderWindows->swapChain); auto device = reinterpret_cast(manager->GetRuntimeData().forwarder); - Raytracing::GetSingleton()->Init(); - logger::info("Detouring virtual function tables"); stl::detour_vfunc<8, IDXGISwapChain_Present>(swapchain); @@ -518,12 +454,8 @@ namespace Hooks stl::detour_vfunc<12, ID3D11Device_CreateVertexShader>(device); stl::detour_vfunc<15, ID3D11Device_CreatePixelShader>(device); } - - stl::detour_vfunc<3, ID3D11Device_CreateBuffer>(device); - stl::detour_vfunc<11, ID3D11Device_CreateInputLayout>(device); - - stl::detour_vfunc<14, ID3D11DeviceContext_Map>(context); - stl::detour_vfunc<15, ID3D11DeviceContext_Unmap>(context); + + Brixelizer::GetSingleton()->InitBrixelizer(); Menu::GetSingleton()->Init(swapchain, device, context); } @@ -809,6 +741,18 @@ namespace Hooks }; } + struct NiNode_Destroy + { + static void thunk(RE::NiNode* This) + { + LightLimitFix::GetSingleton()->CleanupParticleLights(This); + if (auto triShape = This->AsTriShape()) + BrixelizerContext::GetSingleton()->RemoveInstance(triShape); + func(This); + } + static inline REL::Relocation func; + }; + void Install() { logger::info("Hooking BSInputDeviceManager::PollInputDevices"); @@ -861,6 +805,8 @@ namespace Hooks logger::info("Hooking BSEffectShader"); stl::write_vfunc<0x6, EffectExtensions::BSEffectShader_SetupGeometry>(RE::VTABLE_BSEffectShader[0]); + + stl::detour_thunk(REL::RelocationID(68937, 70288)); } void InstallD3DHooks() diff --git a/src/Menu.cpp b/src/Menu.cpp index 7371682cf..40998c7a4 100644 --- a/src/Menu.cpp +++ b/src/Menu.cpp @@ -18,7 +18,7 @@ #include "Deferred.h" #include "TruePBR.h" -#include "Raytracing.h" +#include "Brixelizer.h" #include "Streamline.h" #include "Upscaling.h" @@ -964,7 +964,7 @@ void Menu::DrawDisplaySettings() auto& themeSettings = Menu::GetSingleton()->settings.Theme; const std::vector>> features = { - { "Raytracing", []() { Raytracing::GetSingleton()->DrawSettings(); } }, + { "Brixelizer", []() { Brixelizer::GetSingleton()->DrawSettings(); } }, { "Upscaling", []() { Upscaling::GetSingleton()->DrawSettings(); } }, { "Frame Generation", []() { Streamline::GetSingleton()->DrawSettings(); } } }; diff --git a/src/Raytracing.cpp b/src/Raytracing.cpp deleted file mode 100644 index 5a053a022..000000000 --- a/src/Raytracing.cpp +++ /dev/null @@ -1,1275 +0,0 @@ -#include "Raytracing.h" - -#include -#include - -#include "Deferred.h" -#include "Util.h" - -void Raytracing::CacheFramebuffer() -{ - auto frameBuffer = (FrameBuffer*)mappedFrameBuffer->pData; - frameBufferCached = *frameBuffer; - mappedFrameBuffer = nullptr; -} - -void Raytracing::DrawSettings() -{ - ImGui::Text("Debug capture requires that PIX is attached."); - if (ImGui::Button("Take Debug Capture") && !debugCapture) { - debugCapture = true; - } - ImGui::SliderInt("Debug Mode", (int*)&m_DebugMode, 0, FFX_BRIXELIZER_TRACE_DEBUG_MODE_CASCADE_ID, "%d", ImGuiSliderFlags_AlwaysClamp); - if (auto _tt = Util::HoverTooltipWrapper()) - ImGui::Text("%s", magic_enum::enum_name(m_DebugMode).data()); - - ImGui::SliderInt("Start Cascade", &m_StartCascadeIdx, 0, NUM_BRIXELIZER_CASCADES - 1); - ImGui::SliderInt("End Cascade", &m_EndCascadeIdx, 0, NUM_BRIXELIZER_CASCADES - 1); - - ImGui::SliderFloat("SDF Solve Epsilon", &m_SdfSolveEps, 1e-6f, 1.0f); - - ImGui::Checkbox("Show Static Instance AABBs", &m_ShowStaticInstanceAABBs); - ImGui::Checkbox("Show Dynamic Instance AABBs", &m_ShowDynamicInstanceAABBs); - ImGui::Checkbox("Show Cascade AABBs", &m_ShowCascadeAABBs); - ImGui::SliderInt("Show AABB Tree Index", &m_ShowAABBTreeIndex, -1, NUM_BRIXELIZER_CASCADES - 1); - - static FfxBrixelizerStats statsFirstCascade{}; - - if (stats.cascadeIndex == 0) { - statsFirstCascade = stats; - } - - ImGui::NewLine(); - ImGui::Text("Stats:"); - ImGui::Text(std::format(" cascadeIndex : {}", statsFirstCascade.cascadeIndex).c_str()); - ImGui::Text(" staticCascadeStats:"); - ImGui::Text(std::format(" bricksAllocated : {}", statsFirstCascade.staticCascadeStats.bricksAllocated).c_str()); - ImGui::Text(std::format(" referencesAllocated : {}", statsFirstCascade.staticCascadeStats.referencesAllocated).c_str()); - ImGui::Text(std::format(" trianglesAllocated : {}", statsFirstCascade.staticCascadeStats.trianglesAllocated).c_str()); - - ImGui::Text(" dynamicCascadeStats:"); - ImGui::Text(std::format(" bricksAllocated : {}", statsFirstCascade.dynamicCascadeStats.bricksAllocated).c_str()); - ImGui::Text(std::format(" referencesAllocated : {}", statsFirstCascade.dynamicCascadeStats.referencesAllocated).c_str()); - ImGui::Text(std::format(" trianglesAllocated : {}", statsFirstCascade.dynamicCascadeStats.trianglesAllocated).c_str()); - - ImGui::Text(" contextStats:"); - ImGui::Text(std::format(" brickAllocationsAttempted : {}", statsFirstCascade.contextStats.brickAllocationsAttempted).c_str()); - ImGui::Text(std::format(" brickAllocationsSucceeded : {}", statsFirstCascade.contextStats.brickAllocationsSucceeded).c_str()); - ImGui::Text(std::format(" bricksCleared : {}", statsFirstCascade.contextStats.bricksCleared).c_str()); - ImGui::Text(std::format(" bricksMerged : {}", statsFirstCascade.contextStats.bricksMerged).c_str()); - ImGui::Text(std::format(" freeBricks : {}", statsFirstCascade.contextStats.freeBricks).c_str()); -} - -void Raytracing::InitD3D12(IDXGIAdapter* a_adapter) -{ - DX::ThrowIfFailed(D3D12CreateDevice(a_adapter, D3D_FEATURE_LEVEL_12_2, IID_PPV_ARGS(&d3d12Device))); - - D3D12_COMMAND_QUEUE_DESC queueDesc = {}; - queueDesc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT; - queueDesc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE; - - DX::ThrowIfFailed(d3d12Device->CreateCommandQueue(&queueDesc, IID_PPV_ARGS(&commandQueue))); - - DX::ThrowIfFailed(d3d12Device->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(&commandAllocator))); - - DX::ThrowIfFailed(d3d12Device->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, commandAllocator.get(), nullptr, IID_PPV_ARGS(&commandList))); - DX::ThrowIfFailed(commandList->Close()); - - InitFenceAndEvent(); - - debugAvailable = DXGIGetDebugInterface1(0, IID_PPV_ARGS(&ga)) == S_OK; -} - -// Helper function to create a committed resource -winrt::com_ptr Raytracing::CreateBuffer(UINT64 size, D3D12_RESOURCE_STATES resourceState = D3D12_RESOURCE_STATE_COMMON, D3D12_RESOURCE_FLAGS flags = D3D12_RESOURCE_FLAG_NONE) -{ - winrt::com_ptr buffer; - CD3DX12_HEAP_PROPERTIES heapProperties(D3D12_HEAP_TYPE_DEFAULT); - CD3DX12_RESOURCE_DESC bufferDesc = CD3DX12_RESOURCE_DESC::Buffer(size, flags); - - DX::ThrowIfFailed(d3d12Device->CreateCommittedResource( - &heapProperties, - D3D12_HEAP_FLAG_NONE, - &bufferDesc, - resourceState, - nullptr, - IID_PPV_ARGS(&buffer))); - - return buffer; -} - -void Raytracing::InitBrixelizer() -{ - auto ffxDevice = ffxGetDeviceDX12(d3d12Device.get()); - - size_t scratchBufferSize = ffxGetScratchMemorySizeDX12(2); - void* scratchBuffer = calloc(scratchBufferSize, 1); - memset(scratchBuffer, 0, scratchBufferSize); - - if (ffxGetInterfaceDX12(&initializationParameters.backendInterface, ffxDevice, scratchBuffer, scratchBufferSize, FFX_FSR3UPSCALER_CONTEXT_COUNT) != FFX_OK) - logger::critical("[Raytracing] Failed to initialize Brixelizer backend interface!"); - - initializationParameters.sdfCenter[0] = 0.0f; - initializationParameters.sdfCenter[1] = 0.0f; - initializationParameters.sdfCenter[2] = 0.0f; - initializationParameters.flags = FFX_BRIXELIZER_CONTEXT_FLAG_ALL_DEBUG; - initializationParameters.numCascades = NUM_BRIXELIZER_CASCADES; - - float voxelSize = 10.f; - for (uint32_t i = 0; i < NUM_BRIXELIZER_CASCADES; ++i) { - FfxBrixelizerCascadeDescription* cascadeDesc = &initializationParameters.cascadeDescs[i]; - cascadeDesc->flags = FfxBrixelizerCascadeFlag(FFX_BRIXELIZER_CASCADE_DYNAMIC | FFX_BRIXELIZER_CASCADE_STATIC); - cascadeDesc->voxelSize = voxelSize; - voxelSize *= 2.0f; - } - - FfxErrorCode error = ffxBrixelizerContextCreate(&initializationParameters, &brixelizerContext); - if (error != FFX_OK) { - logger::critical("[Raytracing] Failed to initialize Brixelizer context!"); - } - - D3D12_RESOURCE_DESC sdfAtlasDesc = {}; - sdfAtlasDesc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE3D; - sdfAtlasDesc.Width = FFX_BRIXELIZER_STATIC_CONFIG_SDF_ATLAS_SIZE; - sdfAtlasDesc.Height = FFX_BRIXELIZER_STATIC_CONFIG_SDF_ATLAS_SIZE; - sdfAtlasDesc.DepthOrArraySize = FFX_BRIXELIZER_STATIC_CONFIG_SDF_ATLAS_SIZE; - sdfAtlasDesc.MipLevels = 1; - sdfAtlasDesc.Format = DXGI_FORMAT_R8_UNORM; - sdfAtlasDesc.SampleDesc.Count = 1; - sdfAtlasDesc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN; - sdfAtlasDesc.Flags = D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS; - - { - CD3DX12_HEAP_PROPERTIES heapProperties(D3D12_HEAP_TYPE_DEFAULT); - DX::ThrowIfFailed(d3d12Device->CreateCommittedResource( - &heapProperties, - D3D12_HEAP_FLAG_NONE, - &sdfAtlasDesc, - D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE, - nullptr, - IID_PPV_ARGS(&sdfAtlas))); - } - - brickAABBs = CreateBuffer(FFX_BRIXELIZER_BRICK_AABBS_SIZE, D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE, D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS); - - gpuScratchBuffer = CreateBuffer(GPU_SCRATCH_BUFFER_SIZE, D3D12_RESOURCE_STATE_UNORDERED_ACCESS, D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS); - - for (int i = 0; i < FFX_BRIXELIZER_MAX_CASCADES; i++) { - cascadeAABBTrees[i] = CreateBuffer(FFX_BRIXELIZER_CASCADE_AABB_TREE_SIZE, D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE, D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS); - cascadeBrickMaps[i] = CreateBuffer(FFX_BRIXELIZER_CASCADE_BRICK_MAP_SIZE, D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE, D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS); - } - - { - D3D11_TEXTURE2D_DESC texDesc; - texDesc.Width = 1920; - texDesc.Height = 1080; - texDesc.MipLevels = 1; - texDesc.ArraySize = 1; - texDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM; - texDesc.SampleDesc.Count = 1; - texDesc.SampleDesc.Quality = 0; - texDesc.Usage = D3D11_USAGE_DEFAULT; - texDesc.BindFlags = D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_UNORDERED_ACCESS; - texDesc.CPUAccessFlags = 0; - texDesc.MiscFlags = D3D11_RESOURCE_MISC_SHARED_NTHANDLE | D3D11_RESOURCE_MISC_SHARED; - - CreatedWrappedResource(texDesc, debugRenderTarget); - } -} - -void Raytracing::CreatedWrappedResource(D3D11_TEXTURE2D_DESC a_texDesc, Raytracing::WrappedResource& a_resource) -{ - auto manager = RE::BSGraphics::Renderer::GetSingleton(); - auto d3d11Device = reinterpret_cast(manager->GetRuntimeData().forwarder); - - DX::ThrowIfFailed(d3d11Device->CreateTexture2D(&a_texDesc, nullptr, &a_resource.resource11)); - - IDXGIResource1* dxgiResource = nullptr; - DX::ThrowIfFailed(a_resource.resource11->QueryInterface(IID_PPV_ARGS(&dxgiResource))); - - HANDLE sharedHandle = nullptr; - DX::ThrowIfFailed(dxgiResource->CreateSharedHandle( - nullptr, - DXGI_SHARED_RESOURCE_READ | DXGI_SHARED_RESOURCE_WRITE, - nullptr, - &sharedHandle)); - - DX::ThrowIfFailed(d3d12Device->OpenSharedHandle( - sharedHandle, - IID_PPV_ARGS(&a_resource.resource))); - - CloseHandle(sharedHandle); - - if (a_texDesc.BindFlags & D3D11_BIND_SHADER_RESOURCE) { - D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc = {}; - srvDesc.Format = a_texDesc.Format; - srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D; - srvDesc.Texture2D.MostDetailedMip = 0; - srvDesc.Texture2D.MipLevels = 1; - - DX::ThrowIfFailed(d3d11Device->CreateShaderResourceView(a_resource.resource11, &srvDesc, &a_resource.srv)); - } - - if (a_texDesc.BindFlags & D3D11_BIND_UNORDERED_ACCESS) { - D3D11_UNORDERED_ACCESS_VIEW_DESC uavDesc = {}; - uavDesc.Format = a_texDesc.Format; - uavDesc.ViewDimension = D3D11_UAV_DIMENSION_TEXTURE2D; - uavDesc.Texture2D.MipSlice = 0; - - DX::ThrowIfFailed(d3d11Device->CreateUnorderedAccessView(a_resource.resource11, &uavDesc, &a_resource.uav)); - } -} - -void Raytracing::CreateMiscTextures() -{ - const auto displaySize = State::GetSingleton()->screenSize; - - D3D11_TEXTURE2D_DESC texDesc; - texDesc.Width = (UINT)displaySize.x; - texDesc.Height = (UINT)displaySize.y; - texDesc.MipLevels = 1; - texDesc.ArraySize = 1; - texDesc.Format = DXGI_FORMAT_R32_FLOAT; - texDesc.SampleDesc.Count = 1; - texDesc.SampleDesc.Quality = 0; - texDesc.Usage = D3D11_USAGE_DEFAULT; - texDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_UNORDERED_ACCESS; - texDesc.CPUAccessFlags = 0; - texDesc.MiscFlags = D3D11_RESOURCE_MISC_SHARED_NTHANDLE | D3D11_RESOURCE_MISC_SHARED; - - CD3DX12_HEAP_PROPERTIES heapProperties(D3D12_HEAP_TYPE_DEFAULT); - - CreatedWrappedResource(texDesc, depth); - CreatedWrappedResource(texDesc, historyDepth); - - texDesc.Format = DXGI_FORMAT_R16G16B16A16_FLOAT; - - CreatedWrappedResource(texDesc, normal); - CreatedWrappedResource(texDesc, historyNormal); - - CreatedWrappedResource(texDesc, prevLitOutput); - CreatedWrappedResource(texDesc, diffuseGi); - CreatedWrappedResource(texDesc, specularGi); -} - -void Raytracing::CreateNoiseTextures() -{ - auto& device = State::GetSingleton()->device; - auto& context = State::GetSingleton()->context; - - for (int i = 0; i < 16; i++) { - winrt::com_ptr noiseTexture11; - - wchar_t filePath[128]; - swprintf(filePath, 128, L"Data\\Shaders\\Brixelizer\\Noise\\LDR_RG01_%d.dds", i); - - DirectX::CreateDDSTextureFromFileEx( - device, - context, - filePath, - SIZE_T_MAX, - D3D11_USAGE_DEFAULT, - D3D11_BIND_SHADER_RESOURCE, - 0u, - D3D11_RESOURCE_MISC_SHARED_NTHANDLE | D3D11_RESOURCE_MISC_SHARED, - DirectX::DDS_LOADER_FLAGS::DDS_LOADER_DEFAULT, - noiseTexture11.put(), - nullptr); - - // Query the DXGIResource1 interface to access shared NT handle - winrt::com_ptr dxgiResource1; - DX::ThrowIfFailed(noiseTexture11->QueryInterface(IID_PPV_ARGS(&dxgiResource1))); - - // Create the shared NT handle - HANDLE sharedNtHandle = nullptr; - DX::ThrowIfFailed(dxgiResource1->CreateSharedHandle(nullptr, DXGI_SHARED_RESOURCE_READ, nullptr, &sharedNtHandle)); - - // Open the shared handle in D3D12 - winrt::com_ptr d3d12Resource; - DX::ThrowIfFailed(d3d12Device->OpenSharedHandle(sharedNtHandle, IID_PPV_ARGS(&d3d12Resource))); - CloseHandle(sharedNtHandle); // Close the handle after opening it in D3D12 - - winrt::com_ptr texture11; - DX::ThrowIfFailed(noiseTexture11->QueryInterface(IID_PPV_ARGS(&texture11))); - - D3D11_TEXTURE2D_DESC texDesc11{}; - texture11->GetDesc(&texDesc11); - - D3D12_RESOURCE_DESC texDesc = {}; - texDesc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D; - texDesc.Width = texDesc11.Width; - texDesc.Height = texDesc11.Height; - texDesc.DepthOrArraySize = 1; - texDesc.MipLevels = 1; - texDesc.Format = texDesc11.Format; - texDesc.SampleDesc.Count = 1; - texDesc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN; - texDesc.Flags = D3D12_RESOURCE_FLAG_NONE; - - CD3DX12_HEAP_PROPERTIES heapProperties(D3D12_HEAP_TYPE_DEFAULT); - DX::ThrowIfFailed(d3d12Device->CreateCommittedResource( - &heapProperties, - D3D12_HEAP_FLAG_NONE, - &texDesc, - D3D12_RESOURCE_STATE_COPY_DEST, - nullptr, - IID_PPV_ARGS(&noiseTextures[i]))); - - { - std::vector barriers{ - CD3DX12_RESOURCE_BARRIER::Transition(d3d12Resource.get(), - D3D12_RESOURCE_STATE_COMMON, - D3D12_RESOURCE_STATE_COPY_SOURCE) - }; - commandList->ResourceBarrier(static_cast(barriers.size()), barriers.data()); - } - - commandList->CopyResource(noiseTextures[i].get(), d3d12Resource.get()); - - { - std::vector barriers{ - CD3DX12_RESOURCE_BARRIER::Transition(d3d12Resource.get(), - D3D12_RESOURCE_STATE_COPY_SOURCE, - D3D12_RESOURCE_STATE_COMMON), - CD3DX12_RESOURCE_BARRIER::Transition(noiseTextures[i].get(), - D3D12_RESOURCE_STATE_COPY_DEST, - D3D12_RESOURCE_STATE_COMMON), - }; - commandList->ResourceBarrier(static_cast(barriers.size()), barriers.data()); - } - } -} - -void Raytracing::InitBrixelizerGI() -{ - const auto displaySize = State::GetSingleton()->screenSize; - - // Context Creation - FfxBrixelizerGIContextDescription desc = { - .flags = FFX_BRIXELIZER_GI_FLAG_DEPTH_INVERTED, - .internalResolution = FFX_BRIXELIZER_GI_INTERNAL_RESOLUTION_50_PERCENT, - .displaySize = { static_cast(displaySize.x), static_cast(displaySize.y) }, - .backendInterface = initializationParameters.backendInterface, - }; - if (ffxBrixelizerGIContextCreate(&brixelizerGIContext, &desc) != FFX_OK) - logger::critical("Failed to create Brixelizer GI context."); - if (ffxBrixelizerGIGetEffectVersion() == FFX_SDK_MAKE_VERSION(1, 0, 0)) - logger::critical("FidelityFX Brixelizer GI sample requires linking with a 1.0 version Brixelizer GI library."); - - // Resource Creation - D3D12_RESOURCE_DESC texDesc = { - .Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D, - .Width = static_cast(displaySize.x), - .Height = static_cast(displaySize.y), - .DepthOrArraySize = 1, - .MipLevels = 1, - .Format = DXGI_FORMAT_R16G16B16A16_FLOAT, - .SampleDesc = { .Count = 1 }, - .Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN, - .Flags = D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS | D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET, - }; - - CD3DX12_HEAP_PROPERTIES heapProperties(D3D12_HEAP_TYPE_DEFAULT); - - CreateMiscTextures(); - CreateNoiseTextures(); -} - -// Function to check for shared NT handle support and convert to D3D12 resource -Raytracing::RenderTargetDataD3D12 Raytracing::ConvertD3D11TextureToD3D12(RE::BSGraphics::RenderTargetData* rtData) -{ - RenderTargetDataD3D12 renderTargetData{}; - - if (!rtData->texture) - return renderTargetData; - - D3D11_TEXTURE2D_DESC texDesc{}; - rtData->texture->GetDesc(&texDesc); - - if (!(texDesc.MiscFlags & D3D11_RESOURCE_MISC_SHARED_NTHANDLE)) - return renderTargetData; - - // Query the DXGIResource1 interface to access shared NT handle - winrt::com_ptr dxgiResource1; - DX::ThrowIfFailed(rtData->texture->QueryInterface(IID_PPV_ARGS(&dxgiResource1))); - - // Create the shared NT handle - HANDLE sharedNtHandle = nullptr; - DX::ThrowIfFailed(dxgiResource1->CreateSharedHandle(nullptr, DXGI_SHARED_RESOURCE_READ | DXGI_SHARED_RESOURCE_WRITE, nullptr, &sharedNtHandle)); - - // Open the shared handle in D3D12 - DX::ThrowIfFailed(d3d12Device->OpenSharedHandle(sharedNtHandle, IID_PPV_ARGS(&renderTargetData.d3d12Resource))); - CloseHandle(sharedNtHandle); // Close the handle after opening it in D3D12 - - return renderTargetData; -} - -void Raytracing::BSTriShape_UpdateWorldData(RE::BSTriShape* This, RE::NiUpdateData* a_data) -{ - std::lock_guard lck{ mutex }; - - RE::NiPoint3 pointA = This->world * RE::NiPoint3{ 1.0f, 1.0f, 1.0f }; - - Hooks::BSTriShape_UpdateWorldData::func(This, a_data); - - RE::NiPoint3 pointB = This->world * RE::NiPoint3{ 1.0f, 1.0f, 1.0f }; - - if (pointA.GetDistance(pointB) > 0.1f) { - auto it = instances.find(This); - if (it != instances.end()) { - auto& instanceData = (*it).second; - auto error = ffxBrixelizerDeleteInstances(&brixelizerContext, &instanceData.instanceID, 1); - if (error != FFX_OK) - logger::critical("error"); - instances.erase(it); - } - } -} - -void Raytracing::OpenSharedHandles() -{ - auto renderer = RE::BSGraphics::Renderer::GetSingleton(); - - for (int i = 0; i < RE::RENDER_TARGET::kTOTAL; i++) { - renderTargetsD3D12[i] = ConvertD3D11TextureToD3D12(&renderer->GetRuntimeData().renderTargets[i]); - } -} - -uint Raytracing::GetBufferIndex(BufferData& a_bufferData) -{ - if (a_bufferData.registered) - return a_bufferData.index; - - FfxResource ffxResource = ffxGetResourceDX12(a_bufferData.buffer.get(), ffxGetResourceDescriptionDX12(a_bufferData.buffer.get(), FFX_RESOURCE_USAGE_READ_ONLY), nullptr, FFX_RESOURCE_STATE_PIXEL_COMPUTE_READ); - - FfxBrixelizerBufferDescription brixelizerBufferDesc = {}; - brixelizerBufferDesc.buffer = ffxResource; - brixelizerBufferDesc.outIndex = &a_bufferData.index; - auto error = ffxBrixelizerRegisterBuffers(&brixelizerContext, &brixelizerBufferDesc, 1); - if (error != FFX_OK) - logger::critical("error"); - - a_bufferData.registered = true; - - return a_bufferData.index; -} - -DirectX::XMMATRIX GetXMFromNiTransform(const RE::NiTransform& Transform) -{ - DirectX::XMMATRIX temp; - - const RE::NiMatrix3& m = Transform.rotate; - const float scale = Transform.scale; - - temp.r[0] = DirectX::XMVectorScale(DirectX::XMVectorSet( - m.entry[0][0], - m.entry[1][0], - m.entry[2][0], - 0.0f), - scale); - - temp.r[1] = DirectX::XMVectorScale(DirectX::XMVectorSet( - m.entry[0][1], - m.entry[1][1], - m.entry[2][1], - 0.0f), - scale); - - temp.r[2] = DirectX::XMVectorScale(DirectX::XMVectorSet( - m.entry[0][2], - m.entry[1][2], - m.entry[2][2], - 0.0f), - scale); - - temp.r[3] = DirectX::XMVectorSet( - Transform.translate.x, - Transform.translate.y, - Transform.translate.z, - 1.0f); - - return temp; -} - -struct int4 -{ - int x; - int y; - int z; - int w; -}; - -float4x4 GetBoneTransformMatrix(float4 bonePositions[240], float4 boneIndices, float4 pivot, float4 boneWeights) -{ - int4 boneIndicesInt; - - boneIndices *= 765.01f; - - boneIndicesInt = { (int)boneIndices.x, (int)boneIndices.y, (int)boneIndices.z, (int)boneIndices.w }; - - float4 zeroes = { 0, 0, 0, 0 }; - float4x4 pivotMatrix = float4x4(zeroes, zeroes, zeroes, pivot).Transpose(); - - float4x4 boneMatrix1 = - float4x4(bonePositions[boneIndicesInt.x], bonePositions[boneIndicesInt.x + 1], bonePositions[boneIndicesInt.x + 2], zeroes); - float4x4 boneMatrix2 = - float4x4(bonePositions[boneIndicesInt.y], bonePositions[boneIndicesInt.y + 1], bonePositions[boneIndicesInt.y + 2], zeroes); - float4x4 boneMatrix3 = - float4x4(bonePositions[boneIndicesInt.z], bonePositions[boneIndicesInt.z + 1], bonePositions[boneIndicesInt.z + 2], zeroes); - float4x4 boneMatrix4 = - float4x4(bonePositions[boneIndicesInt.w], bonePositions[boneIndicesInt.w + 1], bonePositions[boneIndicesInt.w + 2], zeroes); - - float4 ones = { 1.0, 1.0, 1.0, 1.0 }; - float4x4 unitMatrix = float4x4(ones, ones, ones, ones); - float4x4 weightMatrix1 = unitMatrix * boneWeights.x; - float4x4 weightMatrix2 = unitMatrix * boneWeights.y; - float4x4 weightMatrix3 = unitMatrix * boneWeights.z; - float4x4 weightMatrix4 = unitMatrix * boneWeights.w; - - return (boneMatrix1 - pivotMatrix) * weightMatrix1 + - (boneMatrix2 - pivotMatrix) * weightMatrix2 + - (boneMatrix3 - pivotMatrix) * weightMatrix3 + - (boneMatrix4 - pivotMatrix) * weightMatrix4; -} - -void Raytracing::AddInstance(RE::BSTriShape* a_geometry) -{ - const auto& transform = a_geometry->world; - const auto& modelData = a_geometry->GetModelData().modelBound; - if (a_geometry->worldBound.radius == 0) - return; - - auto effect = a_geometry->GetGeometryRuntimeData().properties[RE::BSGeometry::States::kEffect]; - auto lightingShader = netimmerse_cast(effect.get()); - - if (!lightingShader) - return; - - if (!lightingShader->flags.all(RE::BSShaderProperty::EShaderPropertyFlag::kZBufferWrite, RE::BSShaderProperty::EShaderPropertyFlag::kZBufferTest)) - return; - - if (lightingShader->flags.any(RE::BSShaderProperty::EShaderPropertyFlag::kLODObjects, RE::BSShaderProperty::EShaderPropertyFlag::kLODLandscape, RE::BSShaderProperty::EShaderPropertyFlag::kHDLODObjects)) - return; - - if (lightingShader->flags.any(RE::BSShaderProperty::EShaderPropertyFlag::kSkinned)) - return; - - // TODO: FIX THIS - if (lightingShader->flags.any(RE::BSShaderProperty::EShaderPropertyFlag::kMultiTextureLandscape, RE::BSShaderProperty::EShaderPropertyFlag::kMultipleTextures, RE::BSShaderProperty::EShaderPropertyFlag::kMultiIndexSnow)) - return; - - const RE::NiPoint3 c = { modelData.center.x, modelData.center.y, modelData.center.z }; - const RE::NiPoint3 r = { modelData.radius, modelData.radius, modelData.radius }; - const RE::NiPoint3 aabbMinVec = c - r; - const RE::NiPoint3 aabbMaxVec = c + r; - const RE::NiPoint3 extents = aabbMaxVec - aabbMinVec; - - const RE::NiPoint3 aabbCorners[8] = { - aabbMinVec + RE::NiPoint3(0.0f, 0.0f, 0.0f), - aabbMinVec + RE::NiPoint3(extents.x, 0.0f, 0.0f), - aabbMinVec + RE::NiPoint3(0.0f, 0.0f, extents.z), - aabbMinVec + RE::NiPoint3(extents.x, 0.0f, extents.z), - aabbMinVec + RE::NiPoint3(0.0f, extents.y, 0.0f), - aabbMinVec + RE::NiPoint3(extents.x, extents.y, 0.0f), - aabbMinVec + RE::NiPoint3(0.0f, extents.y, extents.z), - aabbMinVec + RE::NiPoint3(extents.x, extents.y, extents.z), - }; - - float4 minExtents = float4(FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX); - float4 maxExtents = float4(-FLT_MAX, -FLT_MAX, -FLT_MAX, -FLT_MAX); - - for (uint i = 0; i < 8; i++) { - auto transformed = transform * aabbCorners[i]; - float4 transformedF = { transformed.x, transformed.y, transformed.z, 0 }; - - minExtents = (float4)_mm_min_ps(minExtents, transformedF); - maxExtents = (float4)_mm_max_ps(maxExtents, transformedF); - } - - auto rendererData = a_geometry->GetGeometryRuntimeData().rendererData; - - if (!rendererData || !rendererData->vertexBuffer || !rendererData->indexBuffer) - return; - - BufferData* vertexBuffer; - BufferData* indexBuffer; - - { - auto it2 = vertexBuffers.find((ID3D11Buffer*)rendererData->vertexBuffer); - if (it2 == vertexBuffers.end()) - return; - vertexBuffer = &it2->second; - } - - { - auto it2 = indexBuffers.find((ID3D11Buffer*)rendererData->indexBuffer); - if (it2 == indexBuffers.end()) - return; - indexBuffer = &it2->second; - } - - auto vertexDesc = *(uint64_t*)&rendererData->vertexDesc; - - InputLayoutData* inputLayoutData; - - { - auto it2 = vertexDescToInputLayout.find(vertexDesc); - if (it2 == vertexDescToInputLayout.end()) - return; - auto inputLayout = it2->second; - auto it3 = inputLayouts.find(inputLayout); - if (it3 == inputLayouts.end()) - return; - inputLayoutData = &it3->second; - } - - FfxBrixelizerInstanceDescription instanceDesc = {}; - - { - instanceDesc.aabb.min[0] = minExtents.x; - instanceDesc.aabb.max[0] = maxExtents.x; - - instanceDesc.aabb.min[1] = minExtents.y; - instanceDesc.aabb.max[1] = maxExtents.y; - - instanceDesc.aabb.min[2] = minExtents.z; - instanceDesc.aabb.max[2] = maxExtents.z; - } - - float4x4 xmmTransform = GetXMFromNiTransform(transform); - - for (uint row = 0; row < 3; ++row) { - for (uint col = 0; col < 4; ++col) { - instanceDesc.transform[row * 4 + col] = xmmTransform.m[col][row]; - } - } - - instanceDesc.indexFormat = FFX_INDEX_TYPE_UINT16; - instanceDesc.indexBuffer = GetBufferIndex(*indexBuffer); - instanceDesc.indexBufferOffset = 0; - instanceDesc.triangleCount = a_geometry->GetTrishapeRuntimeData().triangleCount; - - instanceDesc.vertexBuffer = GetBufferIndex(*vertexBuffer); - instanceDesc.vertexStride = ((*(uint64_t*)&rendererData->vertexDesc) << 2) & 0x3C; - instanceDesc.vertexBufferOffset = rendererData->vertexDesc.GetAttributeOffset(RE::BSGraphics::Vertex::Attribute::VA_POSITION); - instanceDesc.vertexCount = a_geometry->GetTrishapeRuntimeData().vertexCount; - instanceDesc.vertexFormat = FFX_SURFACE_FORMAT_R32G32B32_FLOAT; - - instanceDesc.vertexStride = inputLayoutData->vertexStride; - instanceDesc.vertexBufferOffset = inputLayoutData->vertexBufferOffset; - instanceDesc.vertexCount = a_geometry->GetTrishapeRuntimeData().vertexCount; - instanceDesc.vertexFormat = inputLayoutData->vertexFormat; - - InstanceData instanceData{}; - instanceDesc.outInstanceID = &instanceData.instanceID; - instanceDesc.flags = FFX_BRIXELIZER_INSTANCE_FLAG_NONE; - - FfxErrorCode error = ffxBrixelizerCreateInstances(&brixelizerContext, &instanceDesc, 1); - if (error != FFX_OK) - logger::critical("error"); - - instances.insert({ a_geometry, instanceData }); -} - -RE::BSFadeNode* FindBSFadeNode(RE::NiNode* a_niNode) -{ - if (auto fadeNode = a_niNode->AsFadeNode()) { - return fadeNode; - } - return a_niNode->parent ? FindBSFadeNode(a_niNode->parent) : nullptr; -} - -void Raytracing::SeenInstance(RE::BSTriShape* a_geometry) -{ - auto& flags = a_geometry->GetFlags(); - if (flags.none(RE::NiAVObject::Flag::kHidden) && flags.all(RE::NiAVObject::Flag::kRenderUse)) { - if (auto fadeNode = FindBSFadeNode((RE::NiNode*)a_geometry)) { - if (auto extraData = fadeNode->GetExtraData("BSX")) { - auto bsxFlags = (RE::BSXFlags*)extraData; - auto value = static_cast(bsxFlags->value); - if (value & (int32_t)RE::BSXFlags::Flag::kEditorMarker) - return; - } - } - - auto it = instances.find(a_geometry); - if (it != instances.end()) { - auto& instanceData = (*it).second; - instanceData.state = visibleState; - } else { - queuedInstances.insert(a_geometry); - } - } -} - -void Raytracing::RemoveInstance(RE::BSTriShape* This) -{ - std::lock_guard lck{ mutex }; - - auto it = instances.find(This); - if (it != instances.end()) { - auto& instanceData = (*it).second; - auto error = ffxBrixelizerDeleteInstances(&brixelizerContext, &instanceData.instanceID, 1); - if (error != FFX_OK) - logger::critical("error"); - instances.erase(it); - } -} - -Raytracing::BufferData Raytracing::AllocateBuffer(const D3D11_BUFFER_DESC* pDesc, const D3D11_SUBRESOURCE_DATA* pInitialData) -{ - BufferData data; - - // Allocate the memory on the CPU and GPU - { - D3D12_HEAP_PROPERTIES heapProperties = {}; - heapProperties.Type = D3D12_HEAP_TYPE_UPLOAD; - - D3D12_RESOURCE_DESC bufferDesc = {}; - bufferDesc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER; - bufferDesc.Width = pDesc->ByteWidth; - bufferDesc.Height = 1; - bufferDesc.DepthOrArraySize = 1; - bufferDesc.MipLevels = 1; - bufferDesc.Format = DXGI_FORMAT_UNKNOWN; - bufferDesc.SampleDesc.Count = 1; - bufferDesc.SampleDesc.Quality = 0; - bufferDesc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR; - bufferDesc.Flags = D3D12_RESOURCE_FLAG_NONE; - - DX::ThrowIfFailed(d3d12Device->CreateCommittedResource( - &heapProperties, - D3D12_HEAP_FLAG_NONE, - &bufferDesc, - D3D12_RESOURCE_STATE_GENERIC_READ, - nullptr, - IID_PPV_ARGS(&data.buffer))); - - data.width = pDesc->ByteWidth; - } - - // Map the buffer to CPU memory and copy the vertex data - { - void* pVertexData = nullptr; - data.buffer->Map(0, nullptr, &pVertexData); - memcpy(pVertexData, pInitialData->pSysMem, pDesc->ByteWidth); - data.buffer->Unmap(0, nullptr); - } - - return data; -} - -struct ID3D11Buffer_Release -{ - static void thunk(ID3D11Buffer* This) - { - Raytracing::GetSingleton()->UnregisterVertexBuffer(This); - Raytracing::GetSingleton()->UnregisterIndexBuffer(This); - func(This); - } - static inline REL::Relocation func; -}; - -bool hooked = false; - -void Raytracing::RegisterVertexBuffer(const D3D11_BUFFER_DESC* pDesc, const D3D11_SUBRESOURCE_DATA* pInitialData, ID3D11Buffer** ppBuffer) -{ - BufferData data = AllocateBuffer(pDesc, pInitialData); - vertexBuffers.insert({ *ppBuffer, data }); - if (!hooked) { - stl::detour_vfunc<2, ID3D11Buffer_Release>(*ppBuffer); - hooked = true; - } -} - -void Raytracing::RegisterIndexBuffer(const D3D11_BUFFER_DESC* pDesc, const D3D11_SUBRESOURCE_DATA* pInitialData, ID3D11Buffer** ppBuffer) -{ - BufferData data = AllocateBuffer(pDesc, pInitialData); - indexBuffers.insert({ *ppBuffer, data }); - if (!hooked) { - stl::detour_vfunc<2, ID3D11Buffer_Release>(*ppBuffer); - hooked = true; - } -} - -void Raytracing::RegisterInputLayout(ID3D11InputLayout* ppInputLayout, D3D11_INPUT_ELEMENT_DESC* pInputElementDescs, UINT NumElements) -{ - InputLayoutData data = {}; - for (UINT i = 0; i < NumElements; i++) { - if (strcmp(pInputElementDescs[i].SemanticName, "POSITION") == 0) { - data.vertexStride = 0; - - for (UINT k = 0; k < NumElements; k++) { - data.vertexStride += (UINT)DirectX::BytesPerElement(pInputElementDescs[k].Format); - } - - data.vertexBufferOffset = 0; - - for (UINT k = 0; k < i; k++) { - data.vertexBufferOffset += (UINT)DirectX::BytesPerElement(pInputElementDescs[k].Format); - } - - auto format = pInputElementDescs[i].Format; - if (format == DXGI_FORMAT_R32G32B32A32_FLOAT || format == DXGI_FORMAT_R32G32B32_FLOAT) { - data.vertexFormat = FFX_SURFACE_FORMAT_R32G32B32_FLOAT; - } else if (format == DXGI_FORMAT_R16G16B16A16_FLOAT) { - data.vertexFormat = FFX_SURFACE_FORMAT_R16G16B16A16_FLOAT; - } else { - return; - } - - inputLayouts.insert({ ppInputLayout, data }); - } - } -} - -void Raytracing::UnregisterVertexBuffer(ID3D11Buffer* ppBuffer) -{ - vertexBuffers.erase(ppBuffer); -} - -void Raytracing::UnregisterIndexBuffer(ID3D11Buffer* ppBuffer) -{ - indexBuffers.erase(ppBuffer); -} - -void Raytracing::TransitionResources(D3D12_RESOURCE_STATES stateBefore, D3D12_RESOURCE_STATES stateAfter) -{ - std::vector barriers; - - // Transition the SDF Atlas - barriers.push_back(CD3DX12_RESOURCE_BARRIER::Transition( - sdfAtlas.get(), - stateBefore, - stateAfter)); - - // Transition the Brick AABBs - barriers.push_back(CD3DX12_RESOURCE_BARRIER::Transition( - brickAABBs.get(), - stateBefore, - stateAfter)); - - // Transition each Cascade AABB Tree - for (const auto aabbTree : cascadeAABBTrees) { - barriers.push_back(CD3DX12_RESOURCE_BARRIER::Transition( - aabbTree.get(), - stateBefore, - stateAfter)); - } - - // Transition each Cascade Brick Map - for (const auto brickMap : cascadeBrickMaps) { - barriers.push_back(CD3DX12_RESOURCE_BARRIER::Transition( - brickMap.get(), - stateBefore, - stateAfter)); - } - - // Execute the resource barriers on the command list - commandList->ResourceBarrier(static_cast(barriers.size()), barriers.data()); -} - -ID3D11ComputeShader* Raytracing::GetCopyToSharedBufferCS() -{ - if (!copyToSharedBufferCS) - copyToSharedBufferCS = (ID3D11ComputeShader*)Util::CompileShader(L"Data\\Shaders\\Brixelizer\\CopyToSharedBufferCS.hlsl", {}, "cs_5_0"); - return copyToSharedBufferCS; -} - -void Raytracing::ClearShaderCache() -{ - if (copyToSharedBufferCS) - copyToSharedBufferCS->Release(); - copyToSharedBufferCS = nullptr; -} - -void Raytracing::CopyResourcesToSharedBuffers() -{ - auto& context = State::GetSingleton()->context; - auto renderer = RE::BSGraphics::Renderer::GetSingleton(); - - auto& depth11 = renderer->GetDepthStencilData().depthStencils[RE::RENDER_TARGETS_DEPTHSTENCIL::kPOST_ZPREPASS_COPY]; - auto& normalRoughness = renderer->GetRuntimeData().renderTargets[NORMALROUGHNESS]; - - { - auto dispatchCount = Util::GetScreenDispatchCount(true); - - ID3D11ShaderResourceView* views[2] = { depth11.depthSRV, normalRoughness.SRV }; - context->CSSetShaderResources(0, ARRAYSIZE(views), views); - - ID3D11UnorderedAccessView* uavs[2] = { depth.uav, normal.uav }; - context->CSSetUnorderedAccessViews(0, ARRAYSIZE(uavs), uavs, nullptr); - - context->CSSetShader(GetCopyToSharedBufferCS(), nullptr, 0); - - context->Dispatch(dispatchCount.x, dispatchCount.y, 1); - } - - ID3D11ShaderResourceView* views[2] = { nullptr, nullptr }; - context->CSSetShaderResources(0, ARRAYSIZE(views), views); - - ID3D11UnorderedAccessView* uavs[2] = { nullptr, nullptr }; - context->CSSetUnorderedAccessViews(0, ARRAYSIZE(uavs), uavs, nullptr); - - ID3D11ComputeShader* shader = nullptr; - context->CSSetShader(shader, nullptr, 0); -} - -// Initialize Fence and Event -void Raytracing::InitFenceAndEvent() -{ - HRESULT hr = d3d12Device->CreateFence(0, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(&fence)); - if (FAILED(hr)) { - throw std::runtime_error("Failed to create fence."); - } - - fenceEvent = CreateEvent(nullptr, FALSE, FALSE, nullptr); - if (!fenceEvent) { - throw std::runtime_error("Failed to create fence event."); - } -} - -void Raytracing::WaitForD3D11() -{ - auto state = State::GetSingleton(); - - D3D11_QUERY_DESC queryDesc = { .Query = D3D11_QUERY_EVENT, .MiscFlags = 0 }; - winrt::com_ptr query; - DX::ThrowIfFailed(state->device->CreateQuery(&queryDesc, query.put())); - - // https://github.com/niessner/VoxelHashing/blob/master/DepthSensingCUDA/Source/GlobalAppState.cpp - state->context->Flush(); - state->context->End(query.get()); - state->context->Flush(); - - while (state->context->GetData(query.get(), nullptr, 0, 0) != S_OK) {} -} - -// WaitForD3D12 Function -void Raytracing::WaitForD3D12() -{ - // Increment the fence value - const UINT64 currentFenceValue = fenceValue; - DX::ThrowIfFailed(commandQueue->Signal(fence.get(), currentFenceValue)); - fenceValue++; - - // Check if the fence has been reached - if (fence->GetCompletedValue() < currentFenceValue) { - DX::ThrowIfFailed(fence->SetEventOnCompletion(currentFenceValue, fenceEvent)); - WaitForSingleObject(fenceEvent, INFINITE); - } -} - -FfxBrixelizerDebugVisualizationDescription Raytracing::GetDebugVisualization() -{ - FfxBrixelizerDebugVisualizationDescription debugVisDesc{}; - - auto cameraViewInverseAdjusted = frameBufferCached.CameraViewInverse.Transpose(); - cameraViewInverseAdjusted._41 += frameBufferCached.CameraPosAdjust.x; - cameraViewInverseAdjusted._42 += frameBufferCached.CameraPosAdjust.y; - cameraViewInverseAdjusted._43 += frameBufferCached.CameraPosAdjust.z; - auto cameraProjInverse = frameBufferCached.CameraProjInverse.Transpose(); - - memcpy(&debugVisDesc.inverseViewMatrix, &cameraViewInverseAdjusted, sizeof(debugVisDesc.inverseViewMatrix)); - memcpy(&debugVisDesc.inverseProjectionMatrix, &cameraProjInverse, sizeof(debugVisDesc.inverseProjectionMatrix)); - - debugVisDesc.debugState = m_DebugMode; - - uint32_t cascadeIndexOffset = 0; - - debugVisDesc.startCascadeIndex = cascadeIndexOffset + m_StartCascadeIdx; - debugVisDesc.endCascadeIndex = cascadeIndexOffset + m_EndCascadeIdx; - - debugVisDesc.tMin = m_TMin; - debugVisDesc.tMax = m_TMax; - debugVisDesc.sdfSolveEps = m_SdfSolveEps; - debugVisDesc.renderWidth = 1920; - debugVisDesc.renderHeight = 1080; - debugVisDesc.output = ffxGetResourceDX12(debugRenderTarget.resource.get(), ffxGetResourceDescriptionDX12(debugRenderTarget.resource.get(), FFX_RESOURCE_USAGE_UAV), nullptr, FFX_RESOURCE_STATE_UNORDERED_ACCESS); - - return debugVisDesc; -} - -void Raytracing::UpdateBrixelizerContext() -{ - // Transition all resources to resource state expected by Brixelizer - TransitionResources(D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE, D3D12_RESOURCE_STATE_UNORDERED_ACCESS); - - FfxBrixelizerDebugVisualizationDescription debugVisDesc = GetDebugVisualization(); - - // update desc - size_t scratchBufferSize = 0; - - FfxBrixelizerPopulateDebugAABBsFlags populateDebugAABBFlags = FFX_BRIXELIZER_POPULATE_AABBS_NONE; - if (m_ShowStaticInstanceAABBs) - populateDebugAABBFlags = (FfxBrixelizerPopulateDebugAABBsFlags)(populateDebugAABBFlags | FFX_BRIXELIZER_POPULATE_AABBS_STATIC_INSTANCES); - if (m_ShowDynamicInstanceAABBs) - populateDebugAABBFlags = (FfxBrixelizerPopulateDebugAABBsFlags)(populateDebugAABBFlags | FFX_BRIXELIZER_POPULATE_AABBS_DYNAMIC_INSTANCES); - if (m_ShowCascadeAABBs) - populateDebugAABBFlags = (FfxBrixelizerPopulateDebugAABBsFlags)(populateDebugAABBFlags | FFX_BRIXELIZER_POPULATE_AABBS_CASCADE_AABBS); - - FfxBrixelizerUpdateDescription updateDesc = { - .frameIndex = RE::BSGraphics::State::GetSingleton()->frameCount, - .sdfCenter = { frameBufferCached.CameraPosAdjust.x, frameBufferCached.CameraPosAdjust.y, frameBufferCached.CameraPosAdjust.z }, - .populateDebugAABBsFlags = populateDebugAABBFlags, - .debugVisualizationDesc = &debugVisDesc, - .maxReferences = 32 * (1 << 20), - .triangleSwapSize = 300 * (1 << 20), - .maxBricksPerBake = 1 << 14, - .outScratchBufferSize = &scratchBufferSize, - .outStats = &stats, - }; - - // Fill out the Brixelizer update description resources. - // Pass in the externally created output resources as FfxResource objects. - updateDesc.resources.sdfAtlas = ffxGetResourceDX12(sdfAtlas.get(), ffxGetResourceDescriptionDX12(sdfAtlas.get(), FFX_RESOURCE_USAGE_UAV), nullptr, FFX_RESOURCE_STATE_UNORDERED_ACCESS); - updateDesc.resources.brickAABBs = ffxGetResourceDX12(brickAABBs.get(), ffxGetResourceDescriptionDX12(brickAABBs.get(), FFX_RESOURCE_USAGE_UAV), nullptr, FFX_RESOURCE_STATE_UNORDERED_ACCESS); - - for (uint32_t i = 0; i < FFX_BRIXELIZER_MAX_CASCADES; ++i) { - updateDesc.resources.cascadeResources[i].aabbTree = ffxGetResourceDX12(cascadeAABBTrees[i].get(), ffxGetResourceDescriptionDX12(cascadeAABBTrees[i].get(), FFX_RESOURCE_USAGE_UAV), nullptr, FFX_RESOURCE_STATE_UNORDERED_ACCESS); - updateDesc.resources.cascadeResources[i].brickMap = ffxGetResourceDX12(cascadeBrickMaps[i].get(), ffxGetResourceDescriptionDX12(cascadeBrickMaps[i].get(), FFX_RESOURCE_USAGE_UAV), nullptr, FFX_RESOURCE_STATE_UNORDERED_ACCESS); - } - - FfxErrorCode error = ffxBrixelizerBakeUpdate(&brixelizerContext, &updateDesc, &bakedUpdateDesc); - if (error != FFX_OK) - logger::critical("error"); - - if (scratchBufferSize >= GPU_SCRATCH_BUFFER_SIZE) - logger::critical("Required Brixelizer scratch memory size larger than available GPU buffer."); - - FfxResource ffxGpuScratchBuffer = ffxGetResourceDX12(gpuScratchBuffer.get(), ffxGetResourceDescriptionDX12(gpuScratchBuffer.get(), FFX_RESOURCE_USAGE_UAV), nullptr, FFX_RESOURCE_STATE_UNORDERED_ACCESS); - ffxGpuScratchBuffer.description.stride = sizeof(uint32_t); - - // Call frame update - error = ffxBrixelizerUpdate(&brixelizerContext, &bakedUpdateDesc, ffxGpuScratchBuffer, ffxGetCommandListDX12(commandList.get())); - if (error != FFX_OK) - logger::critical("error"); - - // Transition all resources to the Non-Pixel Shader Resource state after the Brixelizer - TransitionResources(D3D12_RESOURCE_STATE_UNORDERED_ACCESS, D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE); -} - -void Raytracing::UpdateBrixelizerGIContext() -{ - //// auto& environmentMap = renderTargetsCubemapD3D12[RE::RENDER_TARGET_CUBEMAP::kREFLECTIONS].d3d12Resource; - auto& normalsRoughness = renderTargetsD3D12[NORMALROUGHNESS]; - auto& motionVectors = renderTargetsD3D12[RE::RENDER_TARGET::kMOTION_VECTOR]; - - auto& main = renderTargetsD3D12[Deferred::GetSingleton()->forwardRenderTargets[0]]; - - auto view = frameBufferCached.CameraView.Transpose(); - view._41 -= frameBufferCached.CameraPosAdjust.x; - view._42 -= frameBufferCached.CameraPosAdjust.y; - view._43 -= frameBufferCached.CameraPosAdjust.z; - - auto projection = frameBufferCached.CameraProj.Transpose(); - - static auto prevView = view; - static auto prevProjection = projection; - - uint noiseIndex = RE::BSGraphics::State::GetSingleton()->frameCount % 16u; - - { - std::vector barriers{ - CD3DX12_RESOURCE_BARRIER::Transition(depth.resource.get(), - D3D12_RESOURCE_STATE_COMMON, - D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE), - CD3DX12_RESOURCE_BARRIER::Transition(normal.resource.get(), - D3D12_RESOURCE_STATE_COMMON, - D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE), - CD3DX12_RESOURCE_BARRIER::Transition(normalsRoughness.d3d12Resource.get(), - D3D12_RESOURCE_STATE_COMMON, - D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE), - CD3DX12_RESOURCE_BARRIER::Transition(motionVectors.d3d12Resource.get(), - D3D12_RESOURCE_STATE_COMMON, - D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE), - CD3DX12_RESOURCE_BARRIER::Transition(historyDepth.resource.get(), - D3D12_RESOURCE_STATE_COMMON, - D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE), - CD3DX12_RESOURCE_BARRIER::Transition(historyNormal.resource.get(), - D3D12_RESOURCE_STATE_COMMON, - D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE), - CD3DX12_RESOURCE_BARRIER::Transition(main.d3d12Resource.get(), - D3D12_RESOURCE_STATE_COMMON, - D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE), - CD3DX12_RESOURCE_BARRIER::Transition(noiseTextures[noiseIndex].get(), - D3D12_RESOURCE_STATE_COMMON, - D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE), - CD3DX12_RESOURCE_BARRIER::Transition(diffuseGi.resource.get(), - D3D12_RESOURCE_STATE_COMMON, - D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE), - CD3DX12_RESOURCE_BARRIER::Transition(specularGi.resource.get(), - D3D12_RESOURCE_STATE_COMMON, - D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE) - }; - commandList->ResourceBarrier(static_cast(barriers.size()), barriers.data()); - } - - { - memcpy(&giDispatchDesc.view, &view, sizeof(giDispatchDesc.view)); - memcpy(&giDispatchDesc.projection, &projection, sizeof(giDispatchDesc.projection)); - memcpy(&giDispatchDesc.prevView, &prevView, sizeof(giDispatchDesc.prevView)); - memcpy(&giDispatchDesc.prevProjection, &prevProjection, sizeof(giDispatchDesc.prevProjection)); - - prevView = view; - prevProjection = projection; - - memcpy(&giDispatchDesc.cameraPosition, &frameBufferCached.CameraPosAdjust, sizeof(giDispatchDesc.cameraPosition)); - - giDispatchDesc.startCascade = m_StartCascadeIdx + (2 * NUM_BRIXELIZER_CASCADES); - giDispatchDesc.endCascade = m_EndCascadeIdx + (2 * NUM_BRIXELIZER_CASCADES); - giDispatchDesc.rayPushoff = m_RayPushoff; - giDispatchDesc.sdfSolveEps = m_SdfSolveEps; - giDispatchDesc.specularRayPushoff = m_RayPushoff; - giDispatchDesc.specularSDFSolveEps = m_SdfSolveEps; - giDispatchDesc.tMin = m_TMin; - giDispatchDesc.tMax = m_TMax; - - giDispatchDesc.normalsUnpackMul = 2.0f; - giDispatchDesc.normalsUnpackAdd = -1.0f; - giDispatchDesc.isRoughnessPerceptual = false; - giDispatchDesc.roughnessChannel = 1; - giDispatchDesc.roughnessThreshold = 0.9f; - giDispatchDesc.environmentMapIntensity = 0.0f; - giDispatchDesc.motionVectorScale = { 1.0f, 1.0f }; - - giDispatchDesc.depth = ffxGetResourceDX12(depth.resource.get(), ffxGetResourceDescriptionDX12(depth.resource.get(), FFX_RESOURCE_USAGE_READ_ONLY), L"Depth", FFX_RESOURCE_STATE_COMPUTE_READ); - - giDispatchDesc.normal = ffxGetResourceDX12(normal.resource.get(), ffxGetResourceDescriptionDX12(normal.resource.get(), FFX_RESOURCE_USAGE_READ_ONLY), L"Normal", FFX_RESOURCE_STATE_COMPUTE_READ); - giDispatchDesc.roughness = ffxGetResourceDX12(normalsRoughness.d3d12Resource.get(), ffxGetResourceDescriptionDX12(normalsRoughness.d3d12Resource.get(), FFX_RESOURCE_USAGE_READ_ONLY), L"Roughness", FFX_RESOURCE_STATE_COMPUTE_READ); - giDispatchDesc.motionVectors = ffxGetResourceDX12(motionVectors.d3d12Resource.get(), ffxGetResourceDescriptionDX12(motionVectors.d3d12Resource.get(), FFX_RESOURCE_USAGE_READ_ONLY), L"MotionVectors", FFX_RESOURCE_STATE_COMPUTE_READ); - - giDispatchDesc.historyDepth = ffxGetResourceDX12(historyDepth.resource.get(), ffxGetResourceDescriptionDX12(historyDepth.resource.get(), FFX_RESOURCE_USAGE_READ_ONLY), L"HistoryDepth", FFX_RESOURCE_STATE_COMPUTE_READ); - giDispatchDesc.historyNormal = ffxGetResourceDX12(historyNormal.resource.get(), ffxGetResourceDescriptionDX12(historyNormal.resource.get(), FFX_RESOURCE_USAGE_READ_ONLY), L"HistoryNormal", FFX_RESOURCE_STATE_COMPUTE_READ); - giDispatchDesc.prevLitOutput = ffxGetResourceDX12(main.d3d12Resource.get(), ffxGetResourceDescriptionDX12(main.d3d12Resource.get(), FFX_RESOURCE_USAGE_READ_ONLY), L"PrevLitOutput", FFX_RESOURCE_STATE_COMPUTE_READ); - - giDispatchDesc.noiseTexture = ffxGetResourceDX12(noiseTextures[noiseIndex].get(), ffxGetResourceDescriptionDX12(noiseTextures[noiseIndex].get(), FFX_RESOURCE_USAGE_READ_ONLY), L"Noise", FFX_RESOURCE_STATE_COMPUTE_READ); - giDispatchDesc.environmentMap = ffxGetResourceDX12(nullptr, ffxGetResourceDescriptionDX12(nullptr, FFX_RESOURCE_USAGE_READ_ONLY), L"EnvironmentMap", FFX_RESOURCE_STATE_COMPUTE_READ); - - giDispatchDesc.sdfAtlas = ffxGetResourceDX12(sdfAtlas.get(), ffxGetResourceDescriptionDX12(sdfAtlas.get(), FFX_RESOURCE_USAGE_READ_ONLY), nullptr, FFX_RESOURCE_STATE_COMPUTE_READ); - giDispatchDesc.bricksAABBs = ffxGetResourceDX12(brickAABBs.get(), ffxGetResourceDescriptionDX12(brickAABBs.get(), FFX_RESOURCE_USAGE_READ_ONLY), nullptr, FFX_RESOURCE_STATE_COMPUTE_READ); - - for (uint32_t i = 0; i < FFX_BRIXELIZER_MAX_CASCADES; ++i) { - giDispatchDesc.cascadeAABBTrees[i] = ffxGetResourceDX12(cascadeAABBTrees[i].get(), ffxGetResourceDescriptionDX12(cascadeAABBTrees[i].get(), FFX_RESOURCE_USAGE_READ_ONLY), nullptr, FFX_RESOURCE_STATE_COMPUTE_READ); - giDispatchDesc.cascadeBrickMaps[i] = ffxGetResourceDX12(cascadeBrickMaps[i].get(), ffxGetResourceDescriptionDX12(cascadeBrickMaps[i].get(), FFX_RESOURCE_USAGE_READ_ONLY), nullptr, FFX_RESOURCE_STATE_COMPUTE_READ); - } - - giDispatchDesc.outputDiffuseGI = ffxGetResourceDX12(diffuseGi.resource.get(), ffxGetResourceDescriptionDX12(diffuseGi.resource.get(), FFX_RESOURCE_USAGE_UAV), L"OutputDiffuseGI", FFX_RESOURCE_STATE_UNORDERED_ACCESS); - giDispatchDesc.outputSpecularGI = ffxGetResourceDX12(specularGi.resource.get(), ffxGetResourceDescriptionDX12(specularGi.resource.get(), FFX_RESOURCE_USAGE_UAV), L"OutputSpecularGI", FFX_RESOURCE_STATE_UNORDERED_ACCESS); - - if (ffxBrixelizerGetRawContext(&brixelizerContext, &giDispatchDesc.brixelizerContext) != FFX_OK) - logger::error("Failed to get Brixelizer context pointer."); - - if (ffxBrixelizerGIContextDispatch(&brixelizerGIContext, &giDispatchDesc, ffxGetCommandListDX12(commandList.get())) != FFX_OK) - logger::error("Failed to dispatch Brixelizer GI."); - } - - { - std::vector barriers{ - CD3DX12_RESOURCE_BARRIER::Transition(depth.resource.get(), - D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE, - D3D12_RESOURCE_STATE_COMMON), - CD3DX12_RESOURCE_BARRIER::Transition(normal.resource.get(), - D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE, - D3D12_RESOURCE_STATE_COMMON), - CD3DX12_RESOURCE_BARRIER::Transition(normalsRoughness.d3d12Resource.get(), - D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE, - D3D12_RESOURCE_STATE_COMMON), - CD3DX12_RESOURCE_BARRIER::Transition(motionVectors.d3d12Resource.get(), - D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE, - D3D12_RESOURCE_STATE_COMMON), - CD3DX12_RESOURCE_BARRIER::Transition(historyDepth.resource.get(), - D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE, - D3D12_RESOURCE_STATE_COMMON), - CD3DX12_RESOURCE_BARRIER::Transition(historyNormal.resource.get(), - D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE, - D3D12_RESOURCE_STATE_COMMON), - CD3DX12_RESOURCE_BARRIER::Transition(main.d3d12Resource.get(), - D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE, - D3D12_RESOURCE_STATE_COMMON), - CD3DX12_RESOURCE_BARRIER::Transition(noiseTextures[noiseIndex].get(), - D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE, - D3D12_RESOURCE_STATE_COMMON), - CD3DX12_RESOURCE_BARRIER::Transition(diffuseGi.resource.get(), - D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE, - D3D12_RESOURCE_STATE_COMMON), - CD3DX12_RESOURCE_BARRIER::Transition(specularGi.resource.get(), - D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE, - D3D12_RESOURCE_STATE_COMMON) - }; - commandList->ResourceBarrier(static_cast(barriers.size()), barriers.data()); - } -} - -void Raytracing::FrameUpdate() -{ - std::lock_guard lck{ mutex }; - - CopyResourcesToSharedBuffers(); - - WaitForD3D11(); - - if (debugAvailable && debugCapture) - ga->BeginCapture(); - - static auto shadowSceneNode = RE::BSShaderManager::State::GetSingleton().shadowSceneNode[0]; - - RE::BSVisit::TraverseScenegraphGeometries(shadowSceneNode, [&](RE::BSGeometry* a_geometry) -> RE::BSVisit::BSVisitControl { - if (auto triShape = a_geometry->AsTriShape()) { - SeenInstance(triShape); - } - return RE::BSVisit::BSVisitControl::kContinue; - }); - - for (auto it = instances.begin(); it != instances.end();) { - if (it->second.state != visibleState) { - auto error = ffxBrixelizerDeleteInstances(&brixelizerContext, &it->second.instanceID, 1); - if (error != FFX_OK) - logger::critical("error"); - - it = instances.erase(it); - - } else { - ++it; - } - } - - for (auto& queuedInstance : queuedInstances) { - AddInstance(queuedInstance); - } - - queuedInstances.clear(); - - DX::ThrowIfFailed(commandAllocator->Reset()); - DX::ThrowIfFailed(commandList->Reset(commandAllocator.get(), nullptr)); - - UpdateBrixelizerContext(); - - UpdateBrixelizerGIContext(); - - DX::ThrowIfFailed(commandList->Close()); - - ID3D12CommandList* ppCommandLists[] = { commandList.get() }; - commandQueue->ExecuteCommandLists(1, ppCommandLists); - - if (debugAvailable && debugCapture) - ga->EndCapture(); - - WaitForD3D12(); - - debugCapture = false; - - visibleState = !visibleState; -} - -void Raytracing::PostFrameUpdate() -{ - auto& context = State::GetSingleton()->context; - auto renderer = RE::BSGraphics::Renderer::GetSingleton(); - - auto main = renderer->GetRuntimeData().renderTargets[Deferred::GetSingleton()->forwardRenderTargets[0]]; - - context->CopyResource(historyDepth.resource11, depth.resource11); - context->CopyResource(historyNormal.resource11, normal.resource11); - context->CopyResource(prevLitOutput.resource11, main.texture); -} diff --git a/src/ShaderCache.cpp b/src/ShaderCache.cpp index be4aa23af..4b58c3dca 100644 --- a/src/ShaderCache.cpp +++ b/src/ShaderCache.cpp @@ -9,7 +9,7 @@ #include "Deferred.h" #include "Feature.h" -#include "Raytracing.h" +#include "Brixelizer.h" #include "State.h" #include "Features/DynamicCubemaps.h" @@ -1852,7 +1852,7 @@ namespace SIE } compilationSet.Clear(); Deferred::GetSingleton()->ClearShaderCache(); - Raytracing::GetSingleton()->ClearShaderCache(); + Brixelizer::GetSingleton()->ClearShaderCache(); for (auto* feature : Feature::GetFeatureList()) { if (feature->loaded) { feature->ClearShaderCache(); diff --git a/src/State.cpp b/src/State.cpp index 4211bf3ca..fa5a49fc2 100644 --- a/src/State.cpp +++ b/src/State.cpp @@ -15,7 +15,6 @@ #include "Features/TerrainBlending.h" #include "TruePBR.h" -#include "Raytracing.h" #include "Streamline.h" #include "Upscaling.h" @@ -112,7 +111,6 @@ void State::Setup() feature->SetupResources(); Deferred::GetSingleton()->SetupResources(); Streamline::GetSingleton()->SetupResources(); - Raytracing::GetSingleton()->OpenSharedHandles(); if (!upscalerLoaded) Upscaling::GetSingleton()->CreateUpscalingResources(); if (initialized) diff --git a/src/XSEPlugin.cpp b/src/XSEPlugin.cpp index 7fd47077e..82f85f66d 100644 --- a/src/XSEPlugin.cpp +++ b/src/XSEPlugin.cpp @@ -4,11 +4,12 @@ #include "Feature.h" #include "FrameAnnotations.h" #include "Menu.h" -#include "Raytracing.h" #include "ShaderCache.h" #include "State.h" #include "TruePBR.h" #include "Upscaling.h" +#include "Brixelizer.h" +#include "Brixelizer/BrixelizerContext.h" #include "ENB/ENBSeriesAPI.h" @@ -89,7 +90,8 @@ void MessageHandler(SKSE::MessagingInterface::Message* message) } Hooks::Install(); FrameAnnotations::OnPostPostLoad(); - Raytracing::Hooks::Install(); + Brixelizer::Hooks::Install(); + BrixelizerContext::Hooks::Install(); auto& shaderCache = SIE::ShaderCache::Instance();