/
redgpu
/
ezEngine
Обзор
Документация
Войти
/
redgpu
/
ezEngine
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
Аналитика
Безопасность
release-23.4
Code/Samples/ComputeShaderHistogram/ComputeShaderHistogram.cpp
297 строк
11 KB
Theophilus Eriata
Fix #902: Compute Shader Histogram Duplicate Windows. (#907)
27 мар 2023, 09:35
Не верифицирован
27 мар 2023, 09:35
42bf580
Код
Авторство
О чём код?
#include <ComputeShaderHistogram/ComputeShaderHistogram.h> #include <Core/ActorSystem/Actor.h> #include <Core/ActorSystem/ActorManager.h> #include <Core/ActorSystem/ActorPluginWindow.h> #include <Core/Graphics/Geometry.h> #include <Core/Input/InputManager.h> #include <Core/System/Window.h> #include <Foundation/Time/Clock.h> #include <Foundation/Utilities/Stats.h> #include <GameEngine/GameApplication/WindowOutputTarget.h> #include <RendererCore/RenderContext/RenderContext.h> #include <RendererCore/ShaderCompiler/ShaderManager.h> #include <RendererFoundation/Device/SwapChain.h> #include <RendererFoundation/Resources/Texture.h> static ezUInt32 g_uiComputeThreadGroupSize = 32; ezComputeShaderHistogramApp::ezComputeShaderHistogramApp() : ezGameApplication("ComputeShaderHistogram", "Data/Samples/ComputeShaderHistogram") , m_pWindow(nullptr) , m_bStuffChanged(false) { } ezComputeShaderHistogramApp::~ezComputeShaderHistogramApp() = default; ezApplication::Execution ezComputeShaderHistogramApp::Run() { ezActorManager::GetSingleton()->Update(); ezClock::GetGlobalClock()->Update(); Run_InputUpdate(); m_bStuffChanged = false; m_pDirectoryWatcher->EnumerateChanges(ezMakeDelegate(&ezComputeShaderHistogramApp::OnFileChanged, this)); if (m_bStuffChanged) { ezResourceManager::ReloadAllResources(false); } ezUInt32 uiWindowWidth = m_pWindow->GetClientAreaSize().width; ezUInt32 uiWindowHeight = m_pWindow->GetClientAreaSize().height; // do the rendering { auto device = ezGALDevice::GetDefaultDevice(); const ezGALSwapChain* pPrimarySwapChain = device->GetSwapChain(m_hSwapChain); ezGALRenderTargetViewHandle hBackbufferRTV = device->GetDefaultRenderTargetView(pPrimarySwapChain->GetRenderTargets().m_hRTs[0]); // Before starting to render in a frame call this function device->BeginFrame(); device->BeginPipeline("ComputeShaderHistogramSample", m_hSwapChain); ezGALPass* pGALPass = device->BeginPass("ezComputeShaderHistogram"); ezRenderContext& renderContext = *ezRenderContext::GetDefaultInstance(); // Constant buffer update { auto& globalConstants = renderContext.WriteGlobalConstants(); ezMemoryUtils::ZeroFill(&globalConstants, 1); globalConstants.ViewportSize = ezVec4((float)uiWindowWidth, (float)uiWindowHeight, 1.0f / (float)uiWindowWidth, 1.0f / (float)uiWindowHeight); // Wrap around to prevent floating point issues. Wrap around is dividable by all whole numbers up to 11. globalConstants.GlobalTime = (float)ezMath::Mod(ezClock::GetGlobalClock()->GetAccumulatedTime().GetSeconds(), 20790.0); globalConstants.WorldTime = globalConstants.GlobalTime; } ezRectFloat viewport(0.0f, 0.0f, (float)uiWindowWidth, (float)uiWindowHeight); // Draw background. { ezGALRenderingSetup renderingSetup; renderingSetup.m_RenderTargetSetup.SetRenderTarget(0, m_hScreenRTV); renderContext.BeginRendering(pGALPass, renderingSetup, viewport, "Background"); renderContext.BindShader(m_hScreenShader); renderContext.BindMeshBuffer(ezGALBufferHandle(), ezGALBufferHandle(), nullptr, ezGALPrimitiveTopology::Triangles, 1); // Vertices are generated by shader. renderContext.DrawMeshBuffer().IgnoreResult(); // Copy screentexture contents to backbuffer. // (Is drawing better? Don't care, this is a one liner and needs no shader!) renderContext.GetCommandEncoder()->CopyTexture(device->GetBackBufferTextureFromSwapChain(m_hSwapChain), m_hScreenTexture); renderContext.EndRendering(); } // Switch to backbuffer (so that the screen texture is no longer bound) { ezGALRenderingSetup renderingSetup; renderingSetup.m_RenderTargetSetup.SetRenderTarget(0, hBackbufferRTV); renderContext.BeginRendering(pGALPass, renderingSetup, viewport, "Dummy"); renderContext.EndRendering(); } // Compute histogram. { renderContext.BeginCompute(pGALPass, "ComputeHistogram"); // Reset first. renderContext.GetCommandEncoder()->ClearUnorderedAccessView(m_hHistogramUAV, ezVec4U32(0, 0, 0, 0)); renderContext.BindShader(m_hHistogramComputeShader); renderContext.BindTexture2D("ScreenTexture", m_hScreenSRV); renderContext.BindUAV("HistogramOutput", m_hHistogramUAV); renderContext.Dispatch(uiWindowWidth / g_uiComputeThreadGroupSize + (uiWindowWidth % g_uiComputeThreadGroupSize != 0 ? 1 : 0), uiWindowHeight / g_uiComputeThreadGroupSize + (uiWindowHeight % g_uiComputeThreadGroupSize != 0 ? 1 : 0)).IgnoreResult(); renderContext.EndCompute(); } // Draw histogram. { ezGALRenderingSetup renderingSetup; renderingSetup.m_RenderTargetSetup.SetRenderTarget(0, hBackbufferRTV); renderContext.BeginRendering(pGALPass, renderingSetup, viewport, "DrawHistogram"); renderContext.BindShader(m_hHistogramDisplayShader); renderContext.BindMeshBuffer(m_hHistogramQuadMeshBuffer); renderContext.BindTexture2D("HistogramTexture", m_hHistogramSRV); renderContext.DrawMeshBuffer().IgnoreResult(); renderContext.EndRendering(); } device->EndPass(pGALPass); device->EndPipeline(m_hSwapChain); device->EndFrame(); ezRenderContext::GetDefaultInstance()->ResetContextState(); } // needs to be called once per frame ezResourceManager::PerFrameUpdate(); // tell the task system to finish its work for this frame // this has to be done at the very end, so that the task system will only use up the time that is left in this frame for // uploading GPU data etc. ezTaskSystem::FinishFrameTasks(); return WasQuitRequested() ? ezApplication::Execution::Quit : ezApplication::Execution::Continue; } void ezComputeShaderHistogramApp::AfterCoreSystemsStartup() { SUPER::AfterCoreSystemsStartup(); m_pDirectoryWatcher = EZ_DEFAULT_NEW(ezDirectoryWatcher); EZ_VERIFY(m_pDirectoryWatcher->OpenDirectory(FindProjectDirectory(), ezDirectoryWatcher::Watch::Writes | ezDirectoryWatcher::Watch::Subdirectories).Succeeded(), "Failed to watch project directory"); auto device = ezGALDevice::GetDefaultDevice(); // Retrieve window and swapchain handle for rendering { ezHybridArray<ezActor*, 8> allActors; ezActorManager::GetSingleton()->GetAllActors(allActors); for (ezActor* pActor : allActors) { ezActorPluginWindow* pWindowPlugin = pActor->GetPlugin<ezActorPluginWindow>(); if (pWindowPlugin == nullptr) continue; m_pWindow = pWindowPlugin->GetWindow(); // Retrieve only the first output target if (auto pOutput = pWindowPlugin->GetOutputTarget()) { m_hSwapChain = static_cast<ezWindowOutputTargetGAL*>(pOutput)->m_hSwapChain; break; } } EZ_ASSERT_DEV(m_pWindow != nullptr, "Failed to retrieve active window. No window plugins have been registered."); EZ_ASSERT_DEV(!m_hSwapChain.IsInvalidated(), "Failed to retrieve active window output target."); } // Create textures and texture view for screen content (can't use back-buffer as shader resource view) { ezGALTextureCreationDescription texDesc; texDesc.m_uiWidth = m_pWindow->GetClientAreaSize().width; texDesc.m_uiHeight = m_pWindow->GetClientAreaSize().height; texDesc.m_Format = ezGALResourceFormat::RGBAUByteNormalized; // ezGALResourceFormat::RGBAUByteNormalizedsRGB; texDesc.m_bCreateRenderTarget = true; texDesc.m_bAllowShaderResourceView = true; m_hScreenTexture = device->CreateTexture(texDesc); m_hScreenRTV = device->GetDefaultRenderTargetView(m_hScreenTexture); m_hScreenSRV = device->GetDefaultResourceView(m_hScreenTexture); } // Create texture for histogram data. { ezGALTextureCreationDescription texDesc; texDesc.m_uiWidth = 256; texDesc.m_uiHeight = 3; // R, G, B texDesc.m_uiMipLevelCount = 1; texDesc.m_Format = ezGALResourceFormat::RUInt; texDesc.m_bCreateRenderTarget = false; texDesc.m_bAllowShaderResourceView = true; texDesc.m_bAllowUAV = true; texDesc.m_ResourceAccess.m_bImmutable = false; m_hHistogramTexture = device->CreateTexture(texDesc); m_hHistogramSRV = device->GetDefaultResourceView(m_hHistogramTexture); ezGALUnorderedAccessViewCreationDescription uavDesc; uavDesc.m_hTexture = m_hHistogramTexture; m_hHistogramUAV = device->CreateUnorderedAccessView(uavDesc); } // Setup Shaders and Materials { m_hScreenShader = ezResourceManager::LoadResource<ezShaderResource>("Shaders/screen.ezShader"); m_hHistogramComputeShader = ezResourceManager::LoadResource<ezShaderResource>("Shaders/histogramcompute.ezShader"); m_hHistogramDisplayShader = ezResourceManager::LoadResource<ezShaderResource>("Shaders/histogramdisplay.ezShader"); } // Geometry. CreateHistogramQuad(); } void ezComputeShaderHistogramApp::BeforeHighLevelSystemsShutdown() { auto device = ezGALDevice::GetDefaultDevice(); m_hScreenShader.Invalidate(); m_hHistogramDisplayShader.Invalidate(); m_hHistogramComputeShader.Invalidate(); m_hHistogramQuadMeshBuffer.Invalidate(); m_hScreenRTV.Invalidate(); m_hScreenSRV.Invalidate(); device->DestroyTexture(m_hScreenTexture); m_hScreenTexture.Invalidate(); device->DestroySwapChain(m_hSwapChain); device->DestroyUnorderedAccessView(m_hHistogramUAV); m_hHistogramUAV.Invalidate(); m_hHistogramSRV.Invalidate(); device->DestroyTexture(m_hHistogramTexture); m_hHistogramTexture.Invalidate(); SUPER::BeforeHighLevelSystemsShutdown(); } void ezComputeShaderHistogramApp::CreateHistogramQuad() { m_hHistogramQuadMeshBuffer = ezResourceManager::GetExistingResource<ezMeshBufferResource>("{4BEFA142-FEDB-42D0-84DC-58223ADD8C62}"); if (!m_hHistogramQuadMeshBuffer.IsValid()) { ezVec2 pixToScreen(1.0f / m_pWindow->GetClientAreaSize().width * 0.5f, 1.0f / m_pWindow->GetClientAreaSize().height * 0.5f); const float borderOffsetPix = 80.0f; const float sizeScreen = 0.8f; ezGeometry geom; ezGeometry::GeoOptions opt; opt.m_Color = ezColor::Black; opt.m_Transform = ezMat4(ezMat3::IdentityMatrix(), ezVec3(1.0f - pixToScreen.x * borderOffsetPix - sizeScreen / 2, -1.0f + pixToScreen.y * borderOffsetPix + sizeScreen / 2, 0.0f)); geom.AddRectXY(ezVec2(sizeScreen, sizeScreen), 1, 1, opt); ezMeshBufferResourceDescriptor desc; desc.AddStream(ezGALVertexAttributeSemantic::Position, ezGALResourceFormat::XYZFloat); desc.AddStream(ezGALVertexAttributeSemantic::TexCoord0, ezGALResourceFormat::XYFloat); desc.AllocateStreamsFromGeometry(geom); ezUInt32 t = 0; for (ezUInt32 p = 0; p < geom.GetPolygons().GetCount(); ++p) { for (ezUInt32 v = 0; v < geom.GetPolygons()[p].m_Vertices.GetCount() - 2; ++v) { desc.SetTriangleIndices(t, geom.GetPolygons()[p].m_Vertices[0], geom.GetPolygons()[p].m_Vertices[v + 1], geom.GetPolygons()[p].m_Vertices[v + 2]); ++t; } } m_hHistogramQuadMeshBuffer = ezResourceManager::GetOrCreateResource<ezMeshBufferResource>("{4BEFA142-FEDB-42D0-84DC-58223ADD8C62}", std::move(desc)); } } void ezComputeShaderHistogramApp::OnFileChanged(const char* filename, ezDirectoryWatcherAction action, ezDirectoryWatcherType type) { if (action == ezDirectoryWatcherAction::Modified && type == ezDirectoryWatcherType::File) { ezLog::Info("The file {0} was modified", filename); m_bStuffChanged = true; } } EZ_APPLICATION_ENTRY_POINT(ezComputeShaderHistogramApp);