#include #include "Viewport/ViewportHostRenderTargets.h" #include namespace { using XCEngine::Editor::BuildViewportColorSurface; using XCEngine::Editor::BuildViewportObjectIdSurface; using XCEngine::Editor::BuildViewportSelectionMaskSurface; using XCEngine::Editor::BuildViewportRenderTargetsReuseQuery; using XCEngine::Editor::DestroyViewportRenderTargets; using XCEngine::Editor::EditorViewportKind; using XCEngine::Editor::ViewportRenderTargets; using XCEngine::RHI::Format; using XCEngine::RHI::RHIResourceView; using XCEngine::RHI::RHITexture; using XCEngine::RHI::ResourceStates; using XCEngine::RHI::ResourceViewDimension; using XCEngine::RHI::ResourceViewType; using XCEngine::RHI::TextureType; class DummyTexture final : public RHITexture { public: explicit DummyTexture(Format format = Format::R8G8B8A8_UNorm) : m_format(format) { } uint32_t GetWidth() const override { return 1; } uint32_t GetHeight() const override { return 1; } uint32_t GetDepth() const override { return 1; } uint32_t GetMipLevels() const override { return 1; } Format GetFormat() const override { return m_format; } TextureType GetTextureType() const override { return TextureType::Texture2D; } ResourceStates GetState() const override { return m_state; } void SetState(ResourceStates state) override { m_state = state; } void* GetNativeHandle() override { return nullptr; } const std::string& GetName() const override { return m_name; } void SetName(const std::string& name) override { m_name = name; } void Shutdown() override { shutdownCalled = true; } bool shutdownCalled = false; private: Format m_format = Format::R8G8B8A8_UNorm; ResourceStates m_state = ResourceStates::Common; std::string m_name; }; class DummyResourceView final : public RHIResourceView { public: explicit DummyResourceView( ResourceViewType viewType = ResourceViewType::RenderTarget, Format format = Format::R8G8B8A8_UNorm) : m_viewType(viewType) , m_format(format) { } void Shutdown() override { shutdownCalled = true; } void* GetNativeHandle() override { return nullptr; } bool IsValid() const override { return true; } ResourceViewType GetViewType() const override { return m_viewType; } ResourceViewDimension GetDimension() const override { return ResourceViewDimension::Texture2D; } Format GetFormat() const override { return m_format; } bool shutdownCalled = false; private: ResourceViewType m_viewType = ResourceViewType::RenderTarget; Format m_format = Format::R8G8B8A8_UNorm; }; TEST(ViewportRenderTargetsTest, BuildReuseQueryReflectsCurrentResourcePresence) { ViewportRenderTargets targets = {}; targets.width = 1280; targets.height = 720; targets.colorTexture = reinterpret_cast(static_cast(0x1)); targets.colorView = reinterpret_cast(static_cast(0x2)); targets.depthTexture = reinterpret_cast(static_cast(0x3)); targets.depthView = reinterpret_cast(static_cast(0x4)); targets.depthShaderView = reinterpret_cast(static_cast(0x5)); targets.objectIdTexture = reinterpret_cast(static_cast(0x6)); targets.objectIdDepthTexture = reinterpret_cast(static_cast(0x7)); targets.objectIdDepthView = reinterpret_cast(static_cast(0x8)); targets.objectIdView = reinterpret_cast(static_cast(0x9)); targets.objectIdShaderView = reinterpret_cast(static_cast(0xA)); targets.selectionMaskTexture = reinterpret_cast(static_cast(0xB)); targets.selectionMaskView = reinterpret_cast(static_cast(0xC)); targets.selectionMaskShaderView = reinterpret_cast(static_cast(0xD)); targets.textureHandle.nativeHandle = 0xE; targets.textureHandle.width = 1280; targets.textureHandle.height = 720; const auto query = BuildViewportRenderTargetsReuseQuery(EditorViewportKind::Scene, targets, 1280, 720); EXPECT_EQ(query.width, 1280u); EXPECT_EQ(query.height, 720u); EXPECT_TRUE(query.resources.hasColorTexture); EXPECT_TRUE(query.resources.hasColorView); EXPECT_TRUE(query.resources.hasDepthTexture); EXPECT_TRUE(query.resources.hasDepthView); EXPECT_TRUE(query.resources.hasDepthShaderView); EXPECT_TRUE(query.resources.hasObjectIdTexture); EXPECT_TRUE(query.resources.hasObjectIdDepthTexture); EXPECT_TRUE(query.resources.hasObjectIdDepthView); EXPECT_TRUE(query.resources.hasObjectIdView); EXPECT_TRUE(query.resources.hasObjectIdShaderView); EXPECT_TRUE(query.resources.hasSelectionMaskTexture); EXPECT_TRUE(query.resources.hasSelectionMaskView); EXPECT_TRUE(query.resources.hasSelectionMaskShaderView); EXPECT_TRUE(query.resources.hasTextureDescriptor); } TEST(ViewportRenderTargetsTest, BuildSurfaceUsesTargetAttachmentsAndStates) { DummyResourceView colorView(ResourceViewType::RenderTarget); DummyResourceView depthView(ResourceViewType::DepthStencil, Format::D24_UNorm_S8_UInt); DummyResourceView objectIdDepthView(ResourceViewType::DepthStencil, Format::D24_UNorm_S8_UInt); DummyResourceView objectIdView(ResourceViewType::RenderTarget); DummyResourceView selectionMaskView(ResourceViewType::RenderTarget); ViewportRenderTargets targets = {}; targets.width = 800; targets.height = 600; targets.colorView = &colorView; targets.depthView = &depthView; targets.objectIdDepthView = &objectIdDepthView; targets.objectIdView = &objectIdView; targets.selectionMaskView = &selectionMaskView; targets.colorState = ResourceStates::Common; targets.objectIdState = ResourceStates::PixelShaderResource; targets.selectionMaskState = ResourceStates::PixelShaderResource; const auto colorSurface = BuildViewportColorSurface(targets); ASSERT_EQ(colorSurface.GetColorAttachments().size(), 1u); EXPECT_EQ(colorSurface.GetColorAttachments()[0], &colorView); EXPECT_EQ(colorSurface.GetDepthAttachment(), &depthView); EXPECT_EQ(colorSurface.GetColorStateBefore(), ResourceStates::Common); const auto objectIdSurface = BuildViewportObjectIdSurface(targets); ASSERT_EQ(objectIdSurface.GetColorAttachments().size(), 1u); EXPECT_EQ(objectIdSurface.GetColorAttachments()[0], &objectIdView); EXPECT_EQ(objectIdSurface.GetDepthAttachment(), &objectIdDepthView); EXPECT_EQ(objectIdSurface.GetColorStateBefore(), ResourceStates::PixelShaderResource); const auto selectionMaskSurface = BuildViewportSelectionMaskSurface(targets); ASSERT_EQ(selectionMaskSurface.GetColorAttachments().size(), 1u); EXPECT_EQ(selectionMaskSurface.GetColorAttachments()[0], &selectionMaskView); EXPECT_EQ(selectionMaskSurface.GetDepthAttachment(), &depthView); EXPECT_EQ(selectionMaskSurface.GetColorStateBefore(), ResourceStates::PixelShaderResource); } TEST(ViewportRenderTargetsTest, DestroyViewportRenderTargetsShutsDownAndClearsState) { auto* colorTexture = new DummyTexture(); auto* colorView = new DummyResourceView(ResourceViewType::RenderTarget); auto* depthTexture = new DummyTexture(Format::D24_UNorm_S8_UInt); auto* depthView = new DummyResourceView(ResourceViewType::DepthStencil, Format::D24_UNorm_S8_UInt); auto* depthShaderView = new DummyResourceView(ResourceViewType::ShaderResource, Format::D24_UNorm_S8_UInt); auto* objectIdTexture = new DummyTexture(); auto* objectIdDepthTexture = new DummyTexture(Format::D24_UNorm_S8_UInt); auto* objectIdDepthView = new DummyResourceView(ResourceViewType::DepthStencil, Format::D24_UNorm_S8_UInt); auto* objectIdView = new DummyResourceView(ResourceViewType::RenderTarget); auto* objectIdShaderView = new DummyResourceView(ResourceViewType::ShaderResource); auto* selectionMaskTexture = new DummyTexture(); auto* selectionMaskView = new DummyResourceView(ResourceViewType::RenderTarget); auto* selectionMaskShaderView = new DummyResourceView(ResourceViewType::ShaderResource); ViewportRenderTargets targets = {}; targets.width = 640; targets.height = 360; targets.colorTexture = colorTexture; targets.colorView = colorView; targets.depthTexture = depthTexture; targets.depthView = depthView; targets.depthShaderView = depthShaderView; targets.objectIdTexture = objectIdTexture; targets.objectIdDepthTexture = objectIdDepthTexture; targets.objectIdDepthView = objectIdDepthView; targets.objectIdView = objectIdView; targets.objectIdShaderView = objectIdShaderView; targets.selectionMaskTexture = selectionMaskTexture; targets.selectionMaskView = selectionMaskView; targets.selectionMaskShaderView = selectionMaskShaderView; targets.imguiCpuHandle.ptr = 123; targets.imguiGpuHandle.ptr = 456; targets.textureHandle.nativeHandle = 789; targets.textureHandle.width = 640; targets.textureHandle.height = 360; targets.colorState = ResourceStates::RenderTarget; targets.objectIdState = ResourceStates::PixelShaderResource; targets.selectionMaskState = ResourceStates::PixelShaderResource; targets.hasValidObjectIdFrame = true; DestroyViewportRenderTargets(nullptr, targets); EXPECT_TRUE(colorTexture->shutdownCalled); EXPECT_TRUE(colorView->shutdownCalled); EXPECT_TRUE(depthTexture->shutdownCalled); EXPECT_TRUE(depthView->shutdownCalled); EXPECT_TRUE(depthShaderView->shutdownCalled); EXPECT_TRUE(objectIdTexture->shutdownCalled); EXPECT_TRUE(objectIdDepthTexture->shutdownCalled); EXPECT_TRUE(objectIdDepthView->shutdownCalled); EXPECT_TRUE(objectIdView->shutdownCalled); EXPECT_TRUE(objectIdShaderView->shutdownCalled); EXPECT_TRUE(selectionMaskTexture->shutdownCalled); EXPECT_TRUE(selectionMaskView->shutdownCalled); EXPECT_TRUE(selectionMaskShaderView->shutdownCalled); EXPECT_EQ(targets.width, 0u); EXPECT_EQ(targets.height, 0u); EXPECT_EQ(targets.colorTexture, nullptr); EXPECT_EQ(targets.colorView, nullptr); EXPECT_EQ(targets.depthTexture, nullptr); EXPECT_EQ(targets.depthView, nullptr); EXPECT_EQ(targets.depthShaderView, nullptr); EXPECT_EQ(targets.objectIdTexture, nullptr); EXPECT_EQ(targets.objectIdDepthTexture, nullptr); EXPECT_EQ(targets.objectIdDepthView, nullptr); EXPECT_EQ(targets.objectIdView, nullptr); EXPECT_EQ(targets.objectIdShaderView, nullptr); EXPECT_EQ(targets.selectionMaskTexture, nullptr); EXPECT_EQ(targets.selectionMaskView, nullptr); EXPECT_EQ(targets.selectionMaskShaderView, nullptr); EXPECT_EQ(targets.imguiCpuHandle.ptr, 0u); EXPECT_EQ(targets.imguiGpuHandle.ptr, 0u); EXPECT_EQ(targets.textureHandle.nativeHandle, 0u); EXPECT_EQ(targets.textureHandle.width, 0u); EXPECT_EQ(targets.textureHandle.height, 0u); EXPECT_EQ(targets.colorState, ResourceStates::Common); EXPECT_EQ(targets.objectIdState, ResourceStates::Common); EXPECT_EQ(targets.selectionMaskState, ResourceStates::Common); EXPECT_FALSE(targets.hasValidObjectIdFrame); } } // namespace