#include #include "Viewport/ViewportHostSurfaceUtils.h" namespace { using XCEngine::Editor::BuildViewportRenderSurface; using XCEngine::Editor::BuildViewportTextureDesc; using XCEngine::Editor::BuildViewportTextureViewDesc; using XCEngine::Editor::CanReuseViewportResources; using XCEngine::Editor::ClampViewportPixelCoordinate; using XCEngine::Editor::EditorViewportKind; using XCEngine::Editor::ViewportHostResourceReuseQuery; using XCEngine::Editor::ViewportRequiresObjectIdResources; using XCEngine::RHI::Format; using XCEngine::RHI::RHIResourceView; using XCEngine::RHI::ResourceStates; using XCEngine::RHI::ResourceViewDimension; using XCEngine::RHI::ResourceViewType; class DummyResourceView final : public RHIResourceView { public: void Shutdown() override { } void* GetNativeHandle() override { return nullptr; } bool IsValid() const override { return true; } ResourceViewType GetViewType() const override { return ResourceViewType::RenderTarget; } ResourceViewDimension GetDimension() const override { return ResourceViewDimension::Texture2D; } Format GetFormat() const override { return Format::R8G8B8A8_UNorm; } }; TEST(ViewportHostSurfaceUtilsTest, ClampViewportPixelCoordinateClampsAndFloors) { EXPECT_EQ(ClampViewportPixelCoordinate(-3.0f, 1280), 0u); EXPECT_EQ(ClampViewportPixelCoordinate(0.99f, 1280), 0u); EXPECT_EQ(ClampViewportPixelCoordinate(10.8f, 1280), 10u); EXPECT_EQ(ClampViewportPixelCoordinate(5000.0f, 1280), 1279u); EXPECT_EQ(ClampViewportPixelCoordinate(12.0f, 0), 0u); } TEST(ViewportHostSurfaceUtilsTest, ViewportReuseRequiresObjectIdOnlyForSceneViewport) { ViewportHostResourceReuseQuery gameQuery = {}; gameQuery.kind = EditorViewportKind::Game; gameQuery.width = 1280; gameQuery.height = 720; gameQuery.requestedWidth = 1280; gameQuery.requestedHeight = 720; gameQuery.resources.hasColorTexture = true; gameQuery.resources.hasColorView = true; gameQuery.resources.hasDepthTexture = true; gameQuery.resources.hasDepthView = true; gameQuery.resources.hasTextureDescriptor = true; EXPECT_FALSE(ViewportRequiresObjectIdResources(EditorViewportKind::Game)); EXPECT_TRUE(CanReuseViewportResources(gameQuery)); ViewportHostResourceReuseQuery sceneQuery = gameQuery; sceneQuery.kind = EditorViewportKind::Scene; EXPECT_TRUE(ViewportRequiresObjectIdResources(EditorViewportKind::Scene)); EXPECT_FALSE(CanReuseViewportResources(sceneQuery)); sceneQuery.resources.hasDepthShaderView = true; sceneQuery.resources.hasObjectIdTexture = true; sceneQuery.resources.hasObjectIdDepthTexture = true; sceneQuery.resources.hasObjectIdDepthView = true; sceneQuery.resources.hasObjectIdView = true; sceneQuery.resources.hasObjectIdShaderView = true; sceneQuery.resources.hasSelectionMaskTexture = true; sceneQuery.resources.hasSelectionMaskView = true; sceneQuery.resources.hasSelectionMaskShaderView = true; EXPECT_TRUE(CanReuseViewportResources(sceneQuery)); } TEST(ViewportHostSurfaceUtilsTest, ViewportReuseRejectsMismatchedOrMissingResources) { ViewportHostResourceReuseQuery query = {}; query.kind = EditorViewportKind::Scene; query.width = 1280; query.height = 720; query.requestedWidth = 1280; query.requestedHeight = 720; query.resources.hasColorTexture = true; query.resources.hasColorView = true; query.resources.hasDepthTexture = true; query.resources.hasDepthView = true; query.resources.hasDepthShaderView = true; query.resources.hasObjectIdTexture = true; query.resources.hasObjectIdDepthTexture = true; query.resources.hasObjectIdDepthView = true; query.resources.hasObjectIdView = true; query.resources.hasObjectIdShaderView = true; query.resources.hasSelectionMaskTexture = true; query.resources.hasSelectionMaskView = true; query.resources.hasSelectionMaskShaderView = true; query.resources.hasTextureDescriptor = true; EXPECT_TRUE(CanReuseViewportResources(query)); query.requestedWidth = 0; EXPECT_FALSE(CanReuseViewportResources(query)); query.requestedWidth = 1280; query.width = 1024; EXPECT_FALSE(CanReuseViewportResources(query)); query.width = 1280; query.resources.hasTextureDescriptor = false; EXPECT_FALSE(CanReuseViewportResources(query)); } TEST(ViewportHostSurfaceUtilsTest, BuildViewportTextureDescriptorsUseExpectedDefaults) { const auto textureDesc = BuildViewportTextureDesc(640, 360, Format::D24_UNorm_S8_UInt); EXPECT_EQ(textureDesc.width, 640u); EXPECT_EQ(textureDesc.height, 360u); EXPECT_EQ(textureDesc.depth, 1u); EXPECT_EQ(textureDesc.mipLevels, 1u); EXPECT_EQ(textureDesc.arraySize, 1u); EXPECT_EQ(textureDesc.format, static_cast(Format::D24_UNorm_S8_UInt)); EXPECT_EQ(textureDesc.textureType, static_cast(XCEngine::RHI::TextureType::Texture2D)); EXPECT_EQ(textureDesc.sampleCount, 1u); EXPECT_EQ(textureDesc.sampleQuality, 0u); EXPECT_EQ(textureDesc.flags, 0u); const auto viewDesc = BuildViewportTextureViewDesc(Format::R8G8B8A8_UNorm); EXPECT_EQ(viewDesc.format, static_cast(Format::R8G8B8A8_UNorm)); EXPECT_EQ(viewDesc.dimension, ResourceViewDimension::Texture2D); } TEST(ViewportHostSurfaceUtilsTest, BuildViewportRenderSurfaceCarriesAttachmentsAndStates) { DummyResourceView colorView; DummyResourceView depthView; const auto surface = BuildViewportRenderSurface( 800, 600, &colorView, &depthView, ResourceStates::Common, ResourceStates::PixelShaderResource); ASSERT_EQ(surface.GetWidth(), 800u); ASSERT_EQ(surface.GetHeight(), 600u); ASSERT_EQ(surface.GetColorAttachments().size(), 1u); EXPECT_EQ(surface.GetColorAttachments()[0], &colorView); EXPECT_EQ(surface.GetDepthAttachment(), &depthView); EXPECT_EQ(surface.GetColorStateBefore(), ResourceStates::Common); EXPECT_EQ(surface.GetColorStateAfter(), ResourceStates::PixelShaderResource); } } // namespace