#include #include #include #include "XCEngine/RHI/D3D12/D3D12Shader.h" #include #include #include #include #include #include #include #include #include #include "stbi/stb_image.h" #include "XCEngine/RHI/Enums.h" #include "XCEngine/RHI/Types.h" #include "XCEngine/RHI/Enums.h" #include "XCEngine/RHI/D3D12/D3D12Enum.h" #include "XCEngine/RHI/D3D12/D3D12Device.h" #include "XCEngine/RHI/D3D12/D3D12CommandQueue.h" #include "XCEngine/RHI/D3D12/D3D12CommandAllocator.h" #include "XCEngine/RHI/D3D12/D3D12CommandList.h" #include "XCEngine/RHI/D3D12/D3D12DescriptorHeap.h" #include "XCEngine/RHI/D3D12/D3D12Fence.h" #include "XCEngine/RHI/D3D12/D3D12SwapChain.h" #include "XCEngine/RHI/D3D12/D3D12RootSignature.h" #include "XCEngine/RHI/D3D12/D3D12PipelineState.h" #include "XCEngine/RHI/D3D12/D3D12Buffer.h" #include "XCEngine/RHI/D3D12/D3D12Texture.h" #include "XCEngine/RHI/D3D12/D3D12RenderTargetView.h" #include "XCEngine/RHI/D3D12/D3D12DepthStencilView.h" #include "XCEngine/RHI/D3D12/D3D12ShaderResourceView.h" #include "XCEngine/RHI/D3D12/D3D12Screenshot.h" #include "XCEngine/Debug/Logger.h" #include "XCEngine/Debug/ConsoleLogSink.h" #include "XCEngine/Debug/FileLogSink.h" using namespace XCEngine::RHI; using namespace XCEngine::Debug; #pragma comment(lib,"d3d12.lib") #pragma comment(lib,"dxgi.lib") #pragma comment(lib,"d3dcompiler.lib") #pragma comment(lib,"winmm.lib") void Log(const char* format, ...) { char buffer[1024]; va_list args; va_start(args, format); vsnprintf(buffer, sizeof(buffer), format, args); va_end(args); Logger::Get().Debug(LogCategory::Rendering, buffer); } //================================================================================= // D3D12 核心全局对象 (最小渲染所需) //================================================================================= XCEngine::RHI::D3D12Device gD3D12Device; // 底层实现 XCEngine::RHI::D3D12CommandQueue gCommandQueue; XCEngine::RHI::D3D12SwapChain gSwapChain; // 渲染目标 (SwapChain的后台Buffer) XCEngine::RHI::D3D12Texture gColorRTs[2]; // 颜色缓冲 (双缓冲) int gCurrentRTIndex = 0; // 描述符堆 XCEngine::RHI::D3D12DescriptorHeap gSwapChainRTVHeap; // RTV堆 XCEngine::RHI::D3D12DescriptorHeap gSwapChainDSVHeap; // DSV堆 XCEngine::RHI::D3D12RenderTargetView gSwapChainRTVs[2]; XCEngine::RHI::D3D12DepthStencilView gSwapChainDSV; UINT gRTVDescriptorSize = 0; UINT gDSVDescriptorSize = 0; // 命令相关 XCEngine::RHI::D3D12CommandAllocator gCommandAllocator; XCEngine::RHI::D3D12CommandList gCommandList; XCEngine::RHI::D3D12RootSignature gRootSignature; XCEngine::RHI::D3D12PipelineState gPipelineState; XCEngine::RHI::D3D12Shader gVertexShader; XCEngine::RHI::D3D12Shader gGeometryShader; XCEngine::RHI::D3D12Shader gPixelShader; // Buffer objects XCEngine::RHI::D3D12Buffer gConstantBuffer; // matrices XCEngine::RHI::D3D12Buffer gMaterialBuffer; // material data XCEngine::RHI::D3D12Texture gTexture; // earth texture XCEngine::RHI::D3D12Texture gDepthStencil; // depth stencil buffer XCEngine::RHI::D3D12ShaderResourceView gTextureSRV; // texture SRV // 同步对象 XCEngine::RHI::D3D12Fence gFence; UINT64 gFenceValue = 0; //================================================================================= // 工具函数 //================================================================================= float srandom() { float number = float(rand()) / float(RAND_MAX); number *= 2.0f; number -= 1.0f; return number; } //================================================================================= // 数据结构定义 //================================================================================= struct StaticMeshComponentVertexData { float mPosition[4]; float mTexcoord[4]; float mNormal[4]; float mTangent[4]; }; struct SubMesh { XCEngine::RHI::D3D12Buffer mIBO; int mIndexCount; }; //================================================================================= // 网格组件类 (StaticMeshComponent) // 封装顶点缓冲(VBO)、索引缓冲(IBO)和渲染逻辑 //================================================================================= class StaticMeshComponent { public: XCEngine::RHI::D3D12Buffer mVBO; StaticMeshComponentVertexData* mVertexData; int mVertexCount; uint32_t mStride; std::unordered_map mSubMeshes; void SetVertexCount(int inVertexCount) { mVertexCount = inVertexCount; mVertexData = new StaticMeshComponentVertexData[inVertexCount]; memset(mVertexData, 0, sizeof(StaticMeshComponentVertexData) * inVertexCount); } void SetVertexPosition(int inIndex, float inX, float inY, float inZ, float inW = 1.0f) { mVertexData[inIndex].mPosition[0] = inX; mVertexData[inIndex].mPosition[1] = inY; mVertexData[inIndex].mPosition[2] = inZ; mVertexData[inIndex].mPosition[3] = inW; } void SetVertexTexcoord(int inIndex, float inX, float inY, float inZ, float inW = 1.0f) { mVertexData[inIndex].mTexcoord[0] = inX; mVertexData[inIndex].mTexcoord[1] = inY; mVertexData[inIndex].mTexcoord[2] = inZ; mVertexData[inIndex].mTexcoord[3] = inW; } void SetVertexNormal(int inIndex, float inX, float inY, float inZ, float inW = 1.0f) { mVertexData[inIndex].mNormal[0] = inX; mVertexData[inIndex].mNormal[1] = inY; mVertexData[inIndex].mNormal[2] = inZ; mVertexData[inIndex].mNormal[3] = inW; } void SetVertexTangent(int inIndex, float inX, float inY, float inZ, float inW = 1.0f) { mVertexData[inIndex].mTangent[0] = inX; mVertexData[inIndex].mTangent[1] = inY; mVertexData[inIndex].mTangent[2] = inZ; mVertexData[inIndex].mTangent[3] = inW; } void InitFromFile(ID3D12GraphicsCommandList* inCommandList, const char* inFilePath) { FILE* pFile = nullptr; errno_t err = fopen_s(&pFile, inFilePath, "rb"); if (err == 0) { int temp = 0; fread(&temp, 4, 1, pFile); mVertexCount = temp; mStride = sizeof(StaticMeshComponentVertexData); mVertexData = new StaticMeshComponentVertexData[mVertexCount]; fread(mVertexData, 1, sizeof(StaticMeshComponentVertexData) * mVertexCount, pFile); mVBO.InitializeWithData(gD3D12Device.GetDevice(), inCommandList, mVertexData, sizeof(StaticMeshComponentVertexData) * mVertexCount, D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER); while (!feof(pFile)) { fread(&temp, 4, 1, pFile); if (feof(pFile)) { break; } char name[256] = { 0 }; fread(name, 1, temp, pFile); fread(&temp, 4, 1, pFile); SubMesh* submesh = new SubMesh; submesh->mIndexCount = temp; unsigned int* indexes = new unsigned int[temp]; fread(indexes, 1, sizeof(unsigned int) * temp, pFile); submesh->mIBO.InitializeWithData(gD3D12Device.GetDevice(), inCommandList, indexes, sizeof(unsigned int) * temp, D3D12_RESOURCE_STATE_INDEX_BUFFER); mSubMeshes.insert(std::pair(name, submesh)); delete[] indexes; } fclose(pFile); } } void Render(XCEngine::RHI::D3D12CommandList& inCommandList) { inCommandList.SetVertexBuffer(0, mVBO.GetResource(), 0, mStride); if (mSubMeshes.empty()) { inCommandList.Draw(mVertexCount, 1, 0, 0); } else { for (auto iter = mSubMeshes.begin(); iter != mSubMeshes.end(); iter++) { inCommandList.SetIndexBuffer(iter->second->mIBO.GetResource(), 0, XCEngine::RHI::Format::R32_UInt); inCommandList.DrawIndexed(iter->second->mIndexCount, 1, 0, 0, 0); } } } }; //================================================================================= // 根签名初始化 (RootSignature) // 定义GPU资源绑定规则: CBV(常量缓冲) / SRV(着色器资源) / DescriptorTable //================================================================================= ID3D12RootSignature* InitRootSignature() { using namespace XCEngine::RHI; D3D12_ROOT_PARAMETER rootParameters[4]; rootParameters[0] = D3D12RootSignature::CreateCBV(1, ShaderVisibility::All, 0); rootParameters[1] = D3D12RootSignature::Create32BitConstants(0, 4, ShaderVisibility::Vertex, 0); D3D12_DESCRIPTOR_RANGE descriptorRange[1]; descriptorRange[0].RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV; descriptorRange[0].RegisterSpace = 0; descriptorRange[0].BaseShaderRegister = 0; descriptorRange[0].NumDescriptors = 1; descriptorRange[0].OffsetInDescriptorsFromTableStart = D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND; rootParameters[2] = D3D12RootSignature::CreateDescriptorTable(1, descriptorRange, ShaderVisibility::Pixel); rootParameters[3] = D3D12RootSignature::CreateSRV(0, ShaderVisibility::All, 1); D3D12_SAMPLER_DESC samplerDesc = {}; samplerDesc.Filter = D3D12_FILTER_MIN_MAG_MIP_LINEAR; samplerDesc.AddressU = D3D12_TEXTURE_ADDRESS_MODE_CLAMP; samplerDesc.AddressV = D3D12_TEXTURE_ADDRESS_MODE_CLAMP; samplerDesc.AddressW = D3D12_TEXTURE_ADDRESS_MODE_CLAMP; samplerDesc.MaxLOD = D3D12_FLOAT32_MAX; D3D12_STATIC_SAMPLER_DESC staticSamplerDesc = D3D12RootSignature::CreateStaticSampler(0, samplerDesc, ShaderVisibility::Pixel); D3D12_ROOT_SIGNATURE_DESC rootSignatureDesc = D3D12RootSignature::CreateDesc( rootParameters, 4, &staticSamplerDesc, 1); gRootSignature.Initialize(gD3D12Device.GetDevice(), rootSignatureDesc); return gRootSignature.GetRootSignature(); } //================================================================================= //================================================================================= //================================================================================= // 渲染管线状态对象 (PSO) // 包含: InputLayout / VS/GS/PS / Rasterizer / DepthStencil / Blend //================================================================================= ID3D12PipelineState* CreatePSO(ID3D12RootSignature* inID3D12RootSignature, D3D12_SHADER_BYTECODE inVertexShader, D3D12_SHADER_BYTECODE inPixelShader, D3D12_SHADER_BYTECODE inGSShader) { using namespace XCEngine::RHI; D3D12_INPUT_ELEMENT_DESC vertexDataElementDesc[] = { D3D12PipelineState::CreateInputElement("POSITION", 0, Format::R32G32B32A32_Float, 0, 0), D3D12PipelineState::CreateInputElement("TEXCOORD", 0, Format::R32G32B32A32_Float, 0, sizeof(float) * 4), D3D12PipelineState::CreateInputElement("NORMAL", 0, Format::R32G32B32A32_Float, 0, sizeof(float) * 8), D3D12PipelineState::CreateInputElement("TANGENT", 0, Format::R32G32B32A32_Float, 0, sizeof(float) * 12) }; D3D12_GRAPHICS_PIPELINE_STATE_DESC psoDesc = D3D12PipelineState::CreateDesc( inID3D12RootSignature, inVertexShader, inPixelShader, inGSShader, 4, vertexDataElementDesc); ID3D12PipelineState* d3d12PSO = nullptr; gPipelineState.Initialize(gD3D12Device.GetDevice(), psoDesc); if (!gPipelineState.GetPipelineState()) { return nullptr; } return gPipelineState.GetPipelineState(); } //================================================================================= // D3D12 初始化核心函数 (InitD3D12) // 最小渲染系统初始化流程: // 1. 启用Debug层 (可选, _DEBUG) // 2. 创建IDXGIFactory4 // 3. 枚举Adapter, 创建ID3D12Device // 4. 创建CommandQueue (命令队列) // 5. 创建SwapChain (交换链) // 6. 创建DepthStencilBuffer (深度缓冲) // 7. 创建RTV/DSV描述符堆 // 8. 创建RenderTargetView / DepthStencilView // 9. 创建CommandAllocator / CommandList // 10. 创建Fence (同步) //================================================================================= bool InitD3D12(HWND inHWND, int inWidth, int inHeight) { if (!gD3D12Device.Initialize()) { return false; } ID3D12Device* device = gD3D12Device.GetDevice(); IDXGIFactory4* dxgiFactory = gD3D12Device.GetFactory(); if (!gCommandQueue.Initialize(device, XCEngine::RHI::CommandQueueType::Direct)) { return false; } DXGI_SWAP_CHAIN_DESC swapChainDesc = {}; swapChainDesc.BufferCount = 2; swapChainDesc.BufferDesc = {}; swapChainDesc.BufferDesc.Width = inWidth; swapChainDesc.BufferDesc.Height = inHeight; swapChainDesc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; swapChainDesc.OutputWindow = inHWND; swapChainDesc.SampleDesc.Count = 1; swapChainDesc.Windowed = true; swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD; IDXGISwapChain* swapChain = nullptr; dxgiFactory->CreateSwapChain(gCommandQueue.GetCommandQueue(), &swapChainDesc, &swapChain); gSwapChain.Initialize(swapChain, inWidth, inHeight); gDepthStencil.InitializeDepthStencil(device, inWidth, inHeight); D3D12_DESCRIPTOR_HEAP_DESC d3dDescriptorHeapDescRTV = {}; d3dDescriptorHeapDescRTV.NumDescriptors = 2; d3dDescriptorHeapDescRTV.Type = D3D12_DESCRIPTOR_HEAP_TYPE_RTV; gSwapChainRTVHeap.Initialize(device, XCEngine::RHI::DescriptorHeapType::RTV, 2); gRTVDescriptorSize = gD3D12Device.GetDescriptorHandleIncrementSize(XCEngine::RHI::DescriptorHeapType::RTV); D3D12_DESCRIPTOR_HEAP_DESC d3dDescriptorHeapDescDSV = {}; d3dDescriptorHeapDescDSV.NumDescriptors = 1; d3dDescriptorHeapDescDSV.Type = D3D12_DESCRIPTOR_HEAP_TYPE_DSV; gSwapChainDSVHeap.Initialize(device, XCEngine::RHI::DescriptorHeapType::DSV, 1); gDSVDescriptorSize = gD3D12Device.GetDescriptorHandleIncrementSize(XCEngine::RHI::DescriptorHeapType::DSV); D3D12_CPU_DESCRIPTOR_HANDLE rtvHeapStart = gSwapChainRTVHeap.GetCPUDescriptorHandleForHeapStart(); for (int i = 0; i < 2; i++) { ID3D12Resource* buffer = nullptr; gSwapChain.GetSwapChain()->GetBuffer(i, IID_PPV_ARGS(&buffer)); gColorRTs[i].InitializeFromExisting(buffer); D3D12_CPU_DESCRIPTOR_HANDLE rtvPointer; rtvPointer.ptr = rtvHeapStart.ptr + i * gRTVDescriptorSize; gSwapChainRTVs[i].InitializeAt(device, gColorRTs[i].GetResource(), rtvPointer, nullptr); } D3D12_DEPTH_STENCIL_VIEW_DESC d3dDSViewDesc = {}; d3dDSViewDesc.Format = DXGI_FORMAT_D24_UNORM_S8_UINT; d3dDSViewDesc.ViewDimension = D3D12_DSV_DIMENSION_TEXTURE2D; gSwapChainDSV.InitializeAt(device, gDepthStencil.GetResource(), gSwapChainDSVHeap.GetCPUDescriptorHandleForHeapStart(), &d3dDSViewDesc); gCommandAllocator.Initialize(device, XCEngine::RHI::CommandQueueType::Direct); gCommandList.Initialize(device, XCEngine::RHI::CommandQueueType::Direct, gCommandAllocator.GetCommandAllocator()); gFence.Initialize(device, 0); return true; } //================================================================================= // 命令相关辅助函数 //================================================================================= void WaitForCompletionOfCommandList() { UINT64 completed = gFence.GetCompletedValue(); UINT64 current = gFenceValue; Log("[DEBUG] WaitForCompletion: completed=%llu, waiting for=%llu\n", completed, current); if (completed < current) { Log("[DEBUG] WaitForCompletion: waiting...\n"); gFence.Wait(current); Log("[DEBUG] WaitForCompletion: done\n"); } } //================================================================================= // 命令列表结束提交 // 关闭CommandList → ExecuteCommandLists → Signal Fence //================================================================================= void EndCommandList() { gCommandList.Close(); ID3D12CommandList* ppCommandLists[] = { gCommandList.GetCommandList() }; gCommandQueue.ExecuteCommandLists(1, ppCommandLists); gFenceValue += 1; gCommandQueue.Signal(gFence.GetFence(), gFenceValue); } //================================================================================= // 开始渲染到SwapChain // 1. 获取当前BackBuffer索引 // 2. 状态转换: PRESENT → RENDER_TARGET // 3. 设置RenderTargets (Color + Depth) // 4. 设置Viewport/Scissor // 5. Clear Color/Depth //================================================================================= void BeginRenderToSwapChain(XCEngine::RHI::D3D12CommandList& inCommandList) { gCurrentRTIndex = gSwapChain.GetCurrentBackBufferIndex(); inCommandList.TransitionBarrier(gColorRTs[gCurrentRTIndex].GetResource(), XCEngine::RHI::ResourceStates::Present, XCEngine::RHI::ResourceStates::RenderTarget); D3D12_CPU_DESCRIPTOR_HANDLE colorRT, dsv; dsv.ptr = gSwapChainDSVHeap.GetCPUDescriptorHandleForHeapStart().ptr; colorRT.ptr = gSwapChainRTVHeap.GetCPUDescriptorHandleForHeapStart().ptr + gCurrentRTIndex * gRTVDescriptorSize; inCommandList.SetRenderTargets(1, &colorRT, &dsv); XCEngine::RHI::Viewport viewport = { 0.0f, 0.0f, 1280.0f, 720.0f, 0.0f, 1.0f }; XCEngine::RHI::Rect scissorRect = { 0, 0, 1280, 720 }; inCommandList.SetViewport(viewport); inCommandList.SetScissorRect(scissorRect); const float clearColor[] = { 0.0f,0.0f,0.0f,1.0f }; inCommandList.ClearRenderTargetView(colorRT, clearColor, 0, nullptr); inCommandList.ClearDepthStencilView(dsv, D3D12_CLEAR_FLAG_DEPTH | D3D12_CLEAR_FLAG_STENCIL, 1.0f, 0, 0, nullptr); } //================================================================================= // 结束渲染到SwapChain // 状态转换: RENDER_TARGET → PRESENT //================================================================================= void EndRenderToSwapChain(XCEngine::RHI::D3D12CommandList& inCommandList) { inCommandList.TransitionBarrier(gColorRTs[gCurrentRTIndex].GetResource(), XCEngine::RHI::ResourceStates::RenderTarget, XCEngine::RHI::ResourceStates::Present); } //================================================================================= // 截图保存 Debug 工具 // 使用 RHI 模块的 D3D12Screenshot 类 //================================================================================= bool SaveScreenshot(const char* filename, int width, int height) { Log("[DEBUG] SaveScreenshot: start\n"); ID3D12Device* device = gD3D12Device.GetDevice(); ID3D12CommandQueue* queue = gCommandQueue.GetCommandQueue(); ID3D12Resource* renderTarget = gColorRTs[gCurrentRTIndex].GetResource(); Log("[DEBUG] SaveScreenshot: calling D3D12Screenshot::Capture\n"); bool result = XCEngine::RHI::D3D12Screenshot::Capture( device, queue, renderTarget, filename, (uint32_t)width, (uint32_t)height); Log("[DEBUG] SaveScreenshot: done, result=%d\n", result); return result; } //================================================================================= // Win32 窗口相关 //================================================================================= LPCTSTR gWindowClassName = L"BattleFire"; //================================================================================= // 窗口消息回调函数 //================================================================================= LRESULT CALLBACK WindowProc(HWND inHWND, UINT inMSG, WPARAM inWParam, LPARAM inLParam) { switch (inMSG) { case WM_CLOSE: PostQuitMessage(0); break; } return DefWindowProc(inHWND, inMSG, inWParam, inLParam); } //================================================================================= // 主入口函数 WinMain // 程序入口点 //================================================================================= int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int inShowCmd) { Logger::Get().AddSink(std::make_unique("D3D12_engine_log.txt")); Logger::Get().SetMinimumLevel(LogLevel::Debug); AllocConsole(); freopen("CONOUT$", "w", stdout); Log("[DEBUG] D3D12 Test Application Started\n"); WNDCLASSEX wndClassEx; wndClassEx.cbSize = sizeof(WNDCLASSEX); wndClassEx.style = CS_HREDRAW | CS_VREDRAW; wndClassEx.cbClsExtra = NULL; wndClassEx.cbWndExtra = NULL; wndClassEx.hInstance = hInstance; wndClassEx.hIcon = LoadIcon(NULL, IDI_APPLICATION); wndClassEx.hIconSm = LoadIcon(NULL, IDI_APPLICATION); wndClassEx.hCursor = LoadCursor(NULL, IDC_ARROW); wndClassEx.hbrBackground = NULL; wndClassEx.lpszMenuName = NULL; wndClassEx.lpszClassName = gWindowClassName; wndClassEx.lpfnWndProc = WindowProc; if (!RegisterClassEx(&wndClassEx)) { MessageBox(NULL, L"Register Class Failed!", L"Error", MB_OK | MB_ICONERROR); return -1; } int viewportWidth = 1280; int viewportHeight = 720; RECT rect; rect.left = 0; rect.top = 0; rect.right = viewportWidth; rect.bottom = viewportHeight; AdjustWindowRect(&rect, WS_OVERLAPPEDWINDOW, FALSE); int windowWidth = rect.right - rect.left; int windowHeight = rect.bottom - rect.top; HWND hwnd = CreateWindowEx(NULL, gWindowClassName, L"My Render Window", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, windowWidth, windowHeight, NULL, NULL, hInstance, NULL); if (!hwnd) { MessageBox(NULL, L"Create Window Failed!", L"Error", MB_OK | MB_ICONERROR); return -1; } InitD3D12(hwnd, 1280, 720); ID3D12CommandAllocator* commandAllocator = gCommandAllocator.GetCommandAllocator(); StaticMeshComponent staticMeshComponent; staticMeshComponent.InitFromFile(gCommandList.GetCommandList(), "Res/Model/Sphere.lhsm"); ID3D12RootSignature* rootSignature = InitRootSignature(); gVertexShader.CompileFromFile(L"Res/Shader/gs.hlsl", "MainVS", "vs_5_1"); gGeometryShader.CompileFromFile(L"Res/Shader/gs.hlsl", "MainGS", "gs_5_1"); gPixelShader.CompileFromFile(L"Res/Shader/gs.hlsl", "MainPS", "ps_5_1"); ID3D12PipelineState* pso = CreatePSO(rootSignature, gVertexShader.GetD3D12Bytecode(), gPixelShader.GetD3D12Bytecode(), gGeometryShader.GetD3D12Bytecode()); gConstantBuffer.Initialize(gD3D12Device.GetDevice(), 65536, D3D12_RESOURCE_STATE_GENERIC_READ, D3D12_HEAP_TYPE_UPLOAD); DirectX::XMMATRIX projectionMatrix = DirectX::XMMatrixPerspectiveFovLH( (45.0f * 3.141592f) / 180.0f, 1280.0f / 720.0f, 0.1f, 1000.0f); DirectX::XMMATRIX viewMatrix = DirectX::XMMatrixIdentity(); DirectX::XMMATRIX modelMatrix = DirectX::XMMatrixTranslation(0.0f, 0.0f, 5.0f); DirectX::XMFLOAT4X4 tempMatrix; float matrices[64]; DirectX::XMStoreFloat4x4(&tempMatrix, projectionMatrix); memcpy(matrices, &tempMatrix, sizeof(float) * 16); DirectX::XMStoreFloat4x4(&tempMatrix, viewMatrix); memcpy(matrices + 16, &tempMatrix, sizeof(float) * 16); DirectX::XMStoreFloat4x4(&tempMatrix, modelMatrix); memcpy(matrices + 32, &tempMatrix, sizeof(float) * 16); DirectX::XMVECTOR determinant; DirectX::XMMATRIX inverseModelMatrix = DirectX::XMMatrixInverse(&determinant, modelMatrix); if (DirectX::XMVectorGetX(determinant) != 0.0f) { DirectX::XMMATRIX normalMatrix = DirectX::XMMatrixTranspose(inverseModelMatrix); DirectX::XMStoreFloat4x4(&tempMatrix, modelMatrix); memcpy(matrices + 48, &tempMatrix, sizeof(float) * 16); } { D3D12_RANGE d3d12Range = { 0 }; unsigned char* pBuffer = nullptr; gConstantBuffer.GetResource()->Map(0, &d3d12Range, (void**)&pBuffer); memcpy(pBuffer, matrices, sizeof(float) * 64); gConstantBuffer.GetResource()->Unmap(0, nullptr); } gMaterialBuffer.Initialize(gD3D12Device.GetDevice(), 65536, D3D12_RESOURCE_STATE_GENERIC_READ, D3D12_HEAP_TYPE_UPLOAD); struct MaterialData { float r; }; MaterialData* materialDatas = new MaterialData[3000]; for (int i = 0; i < 3000; i++) { materialDatas[i].r = srandom() * 0.1f + 0.1f; } { D3D12_RANGE d3d12Range = { 0 }; unsigned char* pBuffer = nullptr; gMaterialBuffer.GetResource()->Map(0, &d3d12Range, (void**)&pBuffer); memcpy(pBuffer, materialDatas, sizeof(MaterialData) * 3000); gMaterialBuffer.GetResource()->Unmap(0, nullptr); } int imageWidth, imageHeight, imageChannel; stbi_uc* pixels = stbi_load("Res/Image/earth_d.jpg", &imageWidth, &imageHeight, &imageChannel, 4); Log("[DEBUG] Texture loaded: width=%d, height=%d, channels=%d, pixels=%p\n", imageWidth, imageHeight, imageChannel, pixels); gTexture.InitializeFromData(gD3D12Device.GetDevice(), gCommandList.GetCommandList(), pixels, imageWidth, imageHeight, DXGI_FORMAT_R8G8B8A8_UNORM); ID3D12Resource* texture = gTexture.GetResource(); delete[] pixels; ID3D12Device* d3dDevice = gD3D12Device.GetDevice(); XCEngine::RHI::D3D12DescriptorHeap srvHeap; srvHeap.Initialize(d3dDevice, XCEngine::RHI::DescriptorHeapType::CBV_SRV_UAV, 3, true); ID3D12DescriptorHeap* descriptorHeaps[] = { srvHeap.GetDescriptorHeap() }; D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = {}; srvDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING; srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D; srvDesc.Texture2D.MipLevels = 1; D3D12_CPU_DESCRIPTOR_HANDLE srvHeapPtr = srvHeap.GetCPUDescriptorHandleForHeapStart(); gTextureSRV.InitializeAt(d3dDevice, texture, srvHeapPtr, &srvDesc); srvHeapPtr.ptr += gD3D12Device.GetDescriptorHandleIncrementSize(XCEngine::RHI::DescriptorHeapType::CBV_SRV_UAV); EndCommandList(); WaitForCompletionOfCommandList(); ShowWindow(hwnd, inShowCmd); UpdateWindow(hwnd); float color[] = { 0.5f,0.5f,0.5f,1.0f }; MSG msg; DWORD last_time = timeGetTime(); DWORD appStartTime = last_time; int frameCount = 0; while (true) { ZeroMemory(&msg, sizeof(MSG)); if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { if (msg.message == WM_QUIT) { break; } TranslateMessage(&msg); DispatchMessage(&msg); } else { frameCount++; WaitForCompletionOfCommandList(); DWORD current_time = timeGetTime(); DWORD frameTime = current_time - last_time; DWORD timeSinceAppStartInMS = current_time - appStartTime; last_time = current_time; float frameTimeInSecond = float(frameTime) / 1000.0f; float timeSinceAppStartInSecond = float(timeSinceAppStartInMS) / 1000.0f; color[0] = timeSinceAppStartInSecond; commandAllocator->Reset(); gCommandList.Reset(gCommandAllocator.GetCommandAllocator()); BeginRenderToSwapChain(gCommandList); gCommandList.SetPipelineState(pso); gCommandList.SetRootSignature(rootSignature); gCommandList.SetDescriptorHeaps(_countof(descriptorHeaps), descriptorHeaps); gCommandList.SetGraphicsRootConstantBufferView(0, gConstantBuffer.GetGPUVirtualAddress()); gCommandList.SetGraphicsRoot32BitConstants(1, 4, color, 0); gCommandList.SetGraphicsRootDescriptorTable(2, srvHeap.GetGPUDescriptorHandleForHeapStart()); gCommandList.SetGraphicsRootShaderResourceView(3, gMaterialBuffer.GetGPUVirtualAddress()); gCommandList.SetPrimitiveTopology(XCEngine::RHI::PrimitiveTopology::TriangleList); staticMeshComponent.Render(gCommandList); // On screenshot frame, don't transition to PRESENT - keep RENDER_TARGET for screenshot if (frameCount != 30) { EndRenderToSwapChain(gCommandList); } EndCommandList(); // On screenshot frame, don't Present - we'll screenshot before next frame if (frameCount != 30) { gSwapChain.Present(0, 0); } // Screenshot after rendering is done if (frameCount == 30) { Log("[DEBUG] Saving screenshot at frame %d...\n", frameCount); if (SaveScreenshot("screenshot.ppm", 1280, 720)) { Log("[DEBUG] Screenshot saved to screenshot.ppm\n"); } else { Log("[DEBUG] Failed to save screenshot!\n"); } PostQuitMessage(0); } } } Logger::Get().Shutdown(); return 0; }