#pragma once #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace XCTest { class TestRenderResourceView final : public XCEngine::RHI::RHIResourceView { public: TestRenderResourceView( XCEngine::RHI::ResourceViewType viewType, XCEngine::RHI::ResourceViewDimension dimension, XCEngine::RHI::Format format) : m_viewType(viewType) , m_dimension(dimension) , m_format(format) { } void Shutdown() override { } void* GetNativeHandle() override { return nullptr; } bool IsValid() const override { return true; } XCEngine::RHI::ResourceViewType GetViewType() const override { return m_viewType; } XCEngine::RHI::ResourceViewDimension GetDimension() const override { return m_dimension; } XCEngine::RHI::Format GetFormat() const override { return m_format; } private: XCEngine::RHI::ResourceViewType m_viewType = XCEngine::RHI::ResourceViewType::ShaderResource; XCEngine::RHI::ResourceViewDimension m_dimension = XCEngine::RHI::ResourceViewDimension::Texture2D; XCEngine::RHI::Format m_format = XCEngine::RHI::Format::Unknown; }; class TestRenderTexture final : public XCEngine::RHI::RHITexture { public: explicit TestRenderTexture(const XCEngine::RHI::TextureDesc& desc) : m_width(desc.width) , m_height(desc.height) , m_depth(desc.depth) , m_mipLevels(desc.mipLevels) , m_format(static_cast(desc.format)) , m_textureType( static_cast(desc.textureType)) { } uint32_t GetWidth() const override { return m_width; } uint32_t GetHeight() const override { return m_height; } uint32_t GetDepth() const override { return m_depth; } uint32_t GetMipLevels() const override { return m_mipLevels; } XCEngine::RHI::Format GetFormat() const override { return m_format; } XCEngine::RHI::TextureType GetTextureType() const override { return m_textureType; } XCEngine::RHI::ResourceStates GetState() const override { return m_state; } void SetState(XCEngine::RHI::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 { } private: uint32_t m_width = 0u; uint32_t m_height = 0u; uint32_t m_depth = 1u; uint32_t m_mipLevels = 1u; XCEngine::RHI::Format m_format = XCEngine::RHI::Format::Unknown; XCEngine::RHI::TextureType m_textureType = XCEngine::RHI::TextureType::Texture2D; XCEngine::RHI::ResourceStates m_state = XCEngine::RHI::ResourceStates::Common; std::string m_name; }; class TestRenderSampler final : public XCEngine::RHI::RHISampler { public: void Shutdown() override { } void Bind(unsigned int) override { } void Unbind(unsigned int) override { } void* GetNativeHandle() override { return nullptr; } unsigned int GetID() override { return 0u; } }; class TestRenderPipelineLayout final : public XCEngine::RHI::RHIPipelineLayout { public: explicit TestRenderPipelineLayout( const XCEngine::RHI::RHIPipelineLayoutDesc& desc) : m_desc(desc) { } bool Initialize(const XCEngine::RHI::RHIPipelineLayoutDesc& desc) override { m_desc = desc; return true; } void Shutdown() override { } void* GetNativeHandle() override { return nullptr; } private: XCEngine::RHI::RHIPipelineLayoutDesc m_desc = {}; }; class TestRenderPipelineState final : public XCEngine::RHI::RHIPipelineState { public: explicit TestRenderPipelineState( const XCEngine::RHI::GraphicsPipelineDesc& desc) : m_inputLayout(desc.inputLayout) , m_rasterizerState(desc.rasterizerState) , m_blendState(desc.blendState) , m_depthStencilState(desc.depthStencilState) , m_topologyType(desc.topologyType) { SetRenderTargetFormats( desc.renderTargetCount, desc.renderTargetFormats, desc.depthStencilFormat); SetSampleCount(desc.sampleCount); SetSampleQuality(desc.sampleQuality); } void SetInputLayout(const XCEngine::RHI::InputLayoutDesc& layout) override { m_inputLayout = layout; } void SetRasterizerState(const XCEngine::RHI::RasterizerDesc& state) override { m_rasterizerState = state; } void SetBlendState(const XCEngine::RHI::BlendDesc& state) override { m_blendState = state; } void SetDepthStencilState( const XCEngine::RHI::DepthStencilStateDesc& state) override { m_depthStencilState = state; } void SetTopology(uint32_t topologyType) override { m_topologyType = topologyType; } void SetRenderTargetFormats( uint32_t count, const uint32_t* formats, uint32_t depthFormat) override { m_renderTargetCount = count; m_depthStencilFormat = depthFormat; m_renderTargetFormats.fill(0u); for (uint32_t index = 0u; index < count && index < m_renderTargetFormats.size(); ++index) { m_renderTargetFormats[index] = formats[index]; } } void SetSampleCount(uint32_t count) override { m_sampleCount = count; } void SetSampleQuality(uint32_t quality) override { m_sampleQuality = quality; } void SetComputeShader(XCEngine::RHI::RHIShader* shader) override { m_computeShader = shader; } const XCEngine::RHI::RasterizerDesc& GetRasterizerState() const override { return m_rasterizerState; } const XCEngine::RHI::BlendDesc& GetBlendState() const override { return m_blendState; } const XCEngine::RHI::DepthStencilStateDesc& GetDepthStencilState() const override { return m_depthStencilState; } const XCEngine::RHI::InputLayoutDesc& GetInputLayout() const override { return m_inputLayout; } XCEngine::RHI::PipelineStateHash GetHash() const override { return {}; } XCEngine::RHI::RHIShader* GetComputeShader() const override { return m_computeShader; } bool HasComputeShader() const override { return m_computeShader != nullptr; } bool IsValid() const override { return true; } void EnsureValid() override { } void Shutdown() override { } void Bind() override { } void Unbind() override { } void* GetNativeHandle() override { return nullptr; } XCEngine::RHI::PipelineType GetType() const override { return XCEngine::RHI::PipelineType::Graphics; } private: XCEngine::RHI::InputLayoutDesc m_inputLayout = {}; XCEngine::RHI::RasterizerDesc m_rasterizerState = {}; XCEngine::RHI::BlendDesc m_blendState = {}; XCEngine::RHI::DepthStencilStateDesc m_depthStencilState = {}; uint32_t m_topologyType = 0u; uint32_t m_renderTargetCount = 0u; std::array m_renderTargetFormats = {}; uint32_t m_depthStencilFormat = 0u; uint32_t m_sampleCount = 1u; uint32_t m_sampleQuality = 0u; XCEngine::RHI::RHIShader* m_computeShader = nullptr; }; class TestRenderDescriptorSet final : public XCEngine::RHI::RHIDescriptorSet { public: explicit TestRenderDescriptorSet( const XCEngine::RHI::DescriptorSetLayoutDesc& layout) { if (layout.bindings == nullptr || layout.bindingCount == 0u) { return; } m_bindings.assign( layout.bindings, layout.bindings + layout.bindingCount); uint32_t maxBinding = 0u; for (const XCEngine::RHI::DescriptorSetLayoutBinding& binding : m_bindings) { maxBinding = std::max(maxBinding, binding.binding); } m_views.resize(static_cast(maxBinding) + 1u, nullptr); m_samplers.resize(static_cast(maxBinding) + 1u, nullptr); } void Shutdown() override { } void Bind() override { } void Unbind() override { } void Update(uint32_t offset, XCEngine::RHI::RHIResourceView* view) override { if (offset >= m_views.size()) { m_views.resize(static_cast(offset) + 1u, nullptr); } m_views[offset] = view; } void UpdateSampler(uint32_t offset, XCEngine::RHI::RHISampler* sampler) override { if (offset >= m_samplers.size()) { m_samplers.resize(static_cast(offset) + 1u, nullptr); } m_samplers[offset] = sampler; } void WriteConstant( uint32_t, const void* data, size_t size, size_t offset = 0u) override { if (data == nullptr || size == 0u) { return; } if (m_constantBuffer.size() < offset + size) { m_constantBuffer.resize(offset + size); } std::memcpy(m_constantBuffer.data() + offset, data, size); m_constantDirty = true; } uint32_t GetBindingCount() const override { return static_cast(m_bindings.size()); } const XCEngine::RHI::DescriptorSetLayoutBinding* GetBindings() const override { return m_bindings.empty() ? nullptr : m_bindings.data(); } void* GetConstantBufferData() override { return m_constantBuffer.empty() ? nullptr : m_constantBuffer.data(); } size_t GetConstantBufferSize() const override { return m_constantBuffer.size(); } bool IsConstantDirty() const override { return m_constantDirty; } void MarkConstantClean() override { m_constantDirty = false; } private: std::vector m_bindings; std::vector m_views; std::vector m_samplers; std::vector m_constantBuffer; bool m_constantDirty = false; }; class TestRenderDescriptorPool final : public XCEngine::RHI::RHIDescriptorPool { public: explicit TestRenderDescriptorPool( const XCEngine::RHI::DescriptorPoolDesc& desc) : m_desc(desc) { } bool Initialize(const XCEngine::RHI::DescriptorPoolDesc& desc) override { m_desc = desc; return true; } void Shutdown() override { } void* GetNativeHandle() override { return nullptr; } uint32_t GetDescriptorCount() const override { return m_desc.descriptorCount; } XCEngine::RHI::DescriptorHeapType GetType() const override { return m_desc.type; } XCEngine::RHI::RHIDescriptorSet* AllocateSet( const XCEngine::RHI::DescriptorSetLayoutDesc& layout) override { return new TestRenderDescriptorSet(layout); } void FreeSet(XCEngine::RHI::RHIDescriptorSet* set) override { delete set; } private: XCEngine::RHI::DescriptorPoolDesc m_desc = {}; }; class TestRenderCommandList final : public XCEngine::RHI::RHICommandList { public: void Shutdown() override { } void Reset() override { } void Close() override { } void TransitionBarrier( XCEngine::RHI::RHIResourceView*, XCEngine::RHI::ResourceStates, XCEngine::RHI::ResourceStates) override { } void BeginRenderPass( XCEngine::RHI::RHIRenderPass*, XCEngine::RHI::RHIFramebuffer*, const XCEngine::RHI::Rect&, uint32_t, const XCEngine::RHI::ClearValue*) override { } void EndRenderPass() override { ++endRenderPassCalls; } void SetShader(XCEngine::RHI::RHIShader*) override { } void SetPipelineState(XCEngine::RHI::RHIPipelineState*) override { ++setPipelineStateCalls; } void SetGraphicsDescriptorSets( uint32_t, uint32_t, XCEngine::RHI::RHIDescriptorSet**, XCEngine::RHI::RHIPipelineLayout*) override { } void SetComputeDescriptorSets( uint32_t, uint32_t, XCEngine::RHI::RHIDescriptorSet**, XCEngine::RHI::RHIPipelineLayout*) override { } void SetPrimitiveTopology(XCEngine::RHI::PrimitiveTopology) override { } void SetViewport(const XCEngine::RHI::Viewport&) override { } void SetViewports(uint32_t, const XCEngine::RHI::Viewport*) override { } void SetScissorRect(const XCEngine::RHI::Rect&) override { } void SetScissorRects(uint32_t, const XCEngine::RHI::Rect*) override { } void SetRenderTargets( uint32_t, XCEngine::RHI::RHIResourceView**, XCEngine::RHI::RHIResourceView*) override { } void SetStencilRef(uint8_t) override { } void SetBlendFactor(const float[4]) override { } void SetVertexBuffers( uint32_t, uint32_t, XCEngine::RHI::RHIResourceView**, const uint64_t*, const uint32_t*) override { } void SetIndexBuffer(XCEngine::RHI::RHIResourceView*, uint64_t) override { } void Draw(uint32_t, uint32_t, uint32_t, uint32_t) override { ++drawCalls; } void DrawIndexed( uint32_t, uint32_t, uint32_t, int32_t, uint32_t) override { ++drawIndexedCalls; } void Clear(float, float, float, float, uint32_t) override { } void ClearRenderTarget( XCEngine::RHI::RHIResourceView*, const float[4], uint32_t, const XCEngine::RHI::Rect*) override { } void ClearDepthStencil( XCEngine::RHI::RHIResourceView*, float, uint8_t, uint32_t, const XCEngine::RHI::Rect*) override { } void CopyResource( XCEngine::RHI::RHIResourceView*, XCEngine::RHI::RHIResourceView*) override { } void Dispatch(uint32_t, uint32_t, uint32_t) override { } size_t endRenderPassCalls = 0u; size_t setPipelineStateCalls = 0u; size_t drawCalls = 0u; size_t drawIndexedCalls = 0u; }; class TestRenderCommandQueue final : public XCEngine::RHI::RHICommandQueue { public: void Shutdown() override { } void ExecuteCommandLists(uint32_t, void**) override { } void Signal(XCEngine::RHI::RHIFence*, uint64_t) override { } void Wait(XCEngine::RHI::RHIFence*, uint64_t) override { } uint64_t GetCompletedValue() override { return 0u; } void WaitForIdle() override { } XCEngine::RHI::CommandQueueType GetType() const override { return XCEngine::RHI::CommandQueueType::Direct; } uint64_t GetTimestampFrequency() const override { return 0u; } void* GetNativeHandle() override { return nullptr; } void WaitForPreviousFrame() override { } uint64_t GetCurrentFrame() const override { return 0u; } }; class TestRenderDevice final : public XCEngine::RHI::RHIDevice { public: bool Initialize(const XCEngine::RHI::RHIDeviceDesc&) override { return true; } void Shutdown() override { } XCEngine::RHI::RHIBuffer* CreateBuffer( const XCEngine::RHI::BufferDesc&) override { return nullptr; } XCEngine::RHI::RHITexture* CreateTexture( const XCEngine::RHI::TextureDesc& desc) override { ++createTextureCalls; return new TestRenderTexture(desc); } XCEngine::RHI::RHITexture* CreateTexture( const XCEngine::RHI::TextureDesc& desc, const void*, size_t, uint32_t) override { return CreateTexture(desc); } XCEngine::RHI::RHISwapChain* CreateSwapChain( const XCEngine::RHI::SwapChainDesc&, XCEngine::RHI::RHICommandQueue*) override { return nullptr; } XCEngine::RHI::RHICommandList* CreateCommandList( const XCEngine::RHI::CommandListDesc&) override { return nullptr; } XCEngine::RHI::RHICommandQueue* CreateCommandQueue( const XCEngine::RHI::CommandQueueDesc&) override { return nullptr; } XCEngine::RHI::RHIShader* CreateShader( const XCEngine::RHI::ShaderCompileDesc&) override { return nullptr; } XCEngine::RHI::RHIPipelineState* CreatePipelineState( const XCEngine::RHI::GraphicsPipelineDesc& desc) override { ++createPipelineStateCalls; return new TestRenderPipelineState(desc); } XCEngine::RHI::RHIPipelineLayout* CreatePipelineLayout( const XCEngine::RHI::RHIPipelineLayoutDesc& desc) override { ++createPipelineLayoutCalls; return new TestRenderPipelineLayout(desc); } XCEngine::RHI::RHIFence* CreateFence( const XCEngine::RHI::FenceDesc&) override { return nullptr; } XCEngine::RHI::RHISampler* CreateSampler( const XCEngine::RHI::SamplerDesc&) override { ++createSamplerCalls; return new TestRenderSampler(); } XCEngine::RHI::RHIRenderPass* CreateRenderPass( uint32_t, const XCEngine::RHI::AttachmentDesc*, const XCEngine::RHI::AttachmentDesc*) override { return nullptr; } XCEngine::RHI::RHIFramebuffer* CreateFramebuffer( XCEngine::RHI::RHIRenderPass*, uint32_t, uint32_t, uint32_t, XCEngine::RHI::RHIResourceView**, XCEngine::RHI::RHIResourceView*) override { return nullptr; } XCEngine::RHI::RHIDescriptorPool* CreateDescriptorPool( const XCEngine::RHI::DescriptorPoolDesc& desc) override { ++createDescriptorPoolCalls; auto* pool = new TestRenderDescriptorPool(desc); pool->Initialize(desc); return pool; } XCEngine::RHI::RHIDescriptorSet* CreateDescriptorSet( XCEngine::RHI::RHIDescriptorPool*, const XCEngine::RHI::DescriptorSetLayoutDesc& layout) override { return new TestRenderDescriptorSet(layout); } XCEngine::RHI::RHIResourceView* CreateVertexBufferView( XCEngine::RHI::RHIBuffer*, const XCEngine::RHI::ResourceViewDesc&) override { return nullptr; } XCEngine::RHI::RHIResourceView* CreateIndexBufferView( XCEngine::RHI::RHIBuffer*, const XCEngine::RHI::ResourceViewDesc&) override { return nullptr; } XCEngine::RHI::RHIResourceView* CreateRenderTargetView( XCEngine::RHI::RHITexture*, const XCEngine::RHI::ResourceViewDesc& desc) override { ++createRenderTargetViewCalls; return new TestRenderResourceView( XCEngine::RHI::ResourceViewType::RenderTarget, desc.dimension, static_cast(desc.format)); } XCEngine::RHI::RHIResourceView* CreateDepthStencilView( XCEngine::RHI::RHITexture*, const XCEngine::RHI::ResourceViewDesc& desc) override { ++createDepthStencilViewCalls; return new TestRenderResourceView( XCEngine::RHI::ResourceViewType::DepthStencil, desc.dimension, static_cast(desc.format)); } XCEngine::RHI::RHIResourceView* CreateShaderResourceView( XCEngine::RHI::RHIBuffer*, const XCEngine::RHI::ResourceViewDesc&) override { return nullptr; } XCEngine::RHI::RHIResourceView* CreateShaderResourceView( XCEngine::RHI::RHITexture*, const XCEngine::RHI::ResourceViewDesc& desc) override { ++createShaderResourceViewCalls; return new TestRenderResourceView( XCEngine::RHI::ResourceViewType::ShaderResource, desc.dimension, static_cast(desc.format)); } XCEngine::RHI::RHIResourceView* CreateUnorderedAccessView( XCEngine::RHI::RHIBuffer*, const XCEngine::RHI::ResourceViewDesc&) override { return nullptr; } XCEngine::RHI::RHIResourceView* CreateUnorderedAccessView( XCEngine::RHI::RHITexture*, const XCEngine::RHI::ResourceViewDesc& desc) override { return new TestRenderResourceView( XCEngine::RHI::ResourceViewType::UnorderedAccess, desc.dimension, static_cast(desc.format)); } const XCEngine::RHI::RHICapabilities& GetCapabilities() const override { return m_capabilities; } const XCEngine::RHI::RHIDeviceInfo& GetDeviceInfo() const override { return m_deviceInfo; } void* GetNativeDevice() override { return nullptr; } size_t createTextureCalls = 0u; size_t createSamplerCalls = 0u; size_t createRenderTargetViewCalls = 0u; size_t createDepthStencilViewCalls = 0u; size_t createShaderResourceViewCalls = 0u; size_t createDescriptorPoolCalls = 0u; size_t createPipelineLayoutCalls = 0u; size_t createPipelineStateCalls = 0u; private: XCEngine::RHI::RHICapabilities m_capabilities = {}; XCEngine::RHI::RHIDeviceInfo m_deviceInfo = {}; }; inline XCEngine::Rendering::RenderContext CreateRenderContext( XCEngine::RHI::RHIDevice& device, XCEngine::RHI::RHICommandList& commandList, XCEngine::RHI::RHICommandQueue& commandQueue) { XCEngine::Rendering::RenderContext context = {}; context.device = &device; context.commandList = &commandList; context.commandQueue = &commandQueue; return context; } } // namespace XCTest