#include #include "Viewport/ViewportHostRenderTargets.h" #include namespace { using XCEngine::Editor::BuildViewportColorSurface; using XCEngine::Editor::BuildViewportObjectIdSurface; 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.objectIdTexture = reinterpret_cast(static_cast(0x5)); targets.objectIdView = reinterpret_cast(static_cast(0x6)); targets.objectIdShaderView = reinterpret_cast(static_cast(0x7)); targets.textureId = static_cast(static_cast(0x8)); 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.hasObjectIdTexture); EXPECT_TRUE(query.resources.hasObjectIdView); EXPECT_TRUE(query.resources.hasObjectIdShaderView); EXPECT_TRUE(query.resources.hasTextureDescriptor); } TEST(ViewportRenderTargetsTest, BuildSurfaceUsesTargetAttachmentsAndStates) { DummyResourceView colorView(ResourceViewType::RenderTarget); DummyResourceView depthView(ResourceViewType::DepthStencil, Format::D24_UNorm_S8_UInt); DummyResourceView objectIdView(ResourceViewType::RenderTarget); ViewportRenderTargets targets = {}; targets.width = 800; targets.height = 600; targets.colorView = &colorView; targets.depthView = &depthView; targets.objectIdView = &objectIdView; targets.colorState = ResourceStates::Common; targets.objectIdState = 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(), &depthView); EXPECT_EQ(objectIdSurface.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* objectIdTexture = new DummyTexture(); auto* objectIdView = new DummyResourceView(ResourceViewType::RenderTarget); auto* objectIdShaderView = 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.objectIdTexture = objectIdTexture; targets.objectIdView = objectIdView; targets.objectIdShaderView = objectIdShaderView; targets.imguiCpuHandle.ptr = 123; targets.imguiGpuHandle.ptr = 456; targets.textureId = static_cast(static_cast(789)); targets.colorState = ResourceStates::RenderTarget; targets.objectIdState = 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(objectIdTexture->shutdownCalled); EXPECT_TRUE(objectIdView->shutdownCalled); EXPECT_TRUE(objectIdShaderView->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.objectIdTexture, nullptr); EXPECT_EQ(targets.objectIdView, nullptr); EXPECT_EQ(targets.objectIdShaderView, nullptr); EXPECT_EQ(targets.imguiCpuHandle.ptr, 0u); EXPECT_EQ(targets.imguiGpuHandle.ptr, 0u); EXPECT_EQ(targets.textureId, ImTextureID{}); EXPECT_EQ(targets.colorState, ResourceStates::Common); EXPECT_EQ(targets.objectIdState, ResourceStates::Common); EXPECT_FALSE(targets.hasValidObjectIdFrame); } } // namespace