#include "D3D12Surface.h"
#include "D3D12Core.h"


namespace XEngine::graphics::d3d12 {
namespace {
constexpr DXGI_FORMAT
to_non_srgb(DXGI_FORMAT format)
{
	if (format == DXGI_FORMAT_R8G8B8A8_UNORM_SRGB) return DXGI_FORMAT_R8G8B8A8_UNORM;
	return format;
}
} // anonymous namespace

void
d3d12_surface::create_swap_chain(IDXGIFactory7* factory, ID3D12CommandQueue* cmd_queue, DXGI_FORMAT format)
{
	assert(factory && cmd_queue);

	// 应为可以多次调用，所以需要先释放旧的 swap chain
	release();

	if (SUCCEEDED(factory->CheckFeatureSupport(DXGI_FEATURE_PRESENT_ALLOW_TEARING, &_allow_tearing, sizeof(u32))) && _allow_tearing)
	{
		_present_flags = DXGI_PRESENT_ALLOW_TEARING;
	}

	DXGI_SWAP_CHAIN_DESC1 desc{};
	desc.AlphaMode = DXGI_ALPHA_MODE_UNSPECIFIED;                   // Alpha通道模式（窗口透明度相关）
	desc.BufferCount = frame_buffer_count;                          // 后台缓冲区数量（用于双缓冲/多缓冲）
	desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;             // 缓冲区用途（作为渲染目标输出）
	desc.Flags = _allow_tearing ? DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING : 0;   // 交换链标志位（无）
	desc.Format = to_non_srgb(format);                              // 像素格式（转换为非SRGB格式）
	desc.Height = _window.height();                                 // 交换链高度（与窗口高度一致）
	desc.Width = _window.width();                                   // 交换链宽度（与窗口宽度一致）
	desc.SampleDesc.Count = 1;                                      // 多重采样数量（1表示禁用MSAA）
	desc.SampleDesc.Quality = 0;                                    // 多重采样质量等级（0表示禁用）
	desc.Scaling = DXGI_SCALING_STRETCH;                            // 缓冲区缩放模式（窗口大小变化时的处理方式）
	desc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD;                // 交换链效果（翻转并丢弃旧缓冲区）
	desc.Stereo = false;                                            // 立体显示模式（3D显示）

	IDXGISwapChain1* swap_chain;
	HWND hwnd{ (HWND)_window.handle() };
	// 为窗口创建交换链，指定交换链描述结构体
	DXCall(factory->CreateSwapChainForHwnd(cmd_queue, hwnd, &desc, nullptr, nullptr, &swap_chain));
	// 控制 DXGI 如何响应特定的系统按键,阻止 DXGI 响应 Alt+Enter 按键序列，由应用程序手动处理全屏切换逻辑。
	DXCall(factory->MakeWindowAssociation(hwnd, DXGI_MWA_NO_ALT_ENTER));
	// 将局部变量 swap_chain 创建的交换链对象“转移”给类成员 _swap_chain 来长期持有。
	// 免了直接赋值（_swap_chain = swap_chain）可能导致的引用计数问题：直接赋值不增加
	// 计数，后续释放 swap_chain 会使对象计数归零而被销毁，_swap_chain 就会变成悬空指针。
	DXCall(swap_chain->QueryInterface(IID_PPV_ARGS(&_swap_chain)));
	core::release(swap_chain);

	_current_bb_index = _swap_chain->GetCurrentBackBufferIndex();

	for (u32 i = 0; i < frame_buffer_count; ++i)
	{
		_render_target_data[i].rtv = core::rtv_heap().allocate();
	}

	finalize();
}

void
d3d12_surface::present() const
{
	assert(_swap_chain);
	// 设置是否使用垂直同步
	// 0 表示不使用垂直同步，1 表示使用垂直同步
	// 第二个参数设置有无特殊行为，0 表示无特殊行为
	DXCall(_swap_chain->Present(0, _present_flags));
	_current_bb_index = _swap_chain->GetCurrentBackBufferIndex();
}

void
d3d12_surface::finalize()
{
	// 为每个缓冲区创建渲染目标视图
	for (u32 i = 0; i < frame_buffer_count; ++i)
	{
		render_target_data& data{ _render_target_data[i] };
		assert(!data.resource);
		DXCall(_swap_chain->GetBuffer(i, IID_PPV_ARGS(&data.resource)));
		D3D12_RENDER_TARGET_VIEW_DESC desc{};
		desc.Format = core::default_render_target_format();
		desc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2D;
		core::device()->CreateRenderTargetView(data.resource, &desc, data.rtv.cpu);
	}

	DXGI_SWAP_CHAIN_DESC desc{};
	DXCall(_swap_chain->GetDesc(&desc));
	const u32 width{ desc.BufferDesc.Width };
	const u32 height{ desc.BufferDesc.Height };
	assert(_window.width() == width && _window.height() == height);


	_viewport.TopLeftX = 0.0f;
	_viewport.TopLeftY = 0.0f;
	_viewport.Width = (float)width;
	_viewport.Height = (float)height;
	_viewport.MaxDepth = 1.0f;
	_viewport.MinDepth = 0.0f;

	_scissor_rect = { 0, 0, (s32)width, (s32)height };
}

void
d3d12_surface::release()
{
	for (u32 i = 0; i < frame_buffer_count; ++i)
	{
		render_target_data& data{ _render_target_data[i] };
		core::release(data.resource);
		core::rtv_heap().free(data.rtv);

	}
	core::release(_swap_chain);
}

void
d3d12_surface::resize()
{
}

u32
d3d12_surface::width()
{
	return _window.width();
}

u32
d3d12_surface::height()
{
	return _window.height();
}


} // namespace XEngine::graphics::d3d12