#include #include #include #include #include #include #include #include #include #include #include #include #include "stbi/stb_image.h" #include "XCEngine/RHI/Enums.h" #include "XCEngine/RHI/D3D12/D3D12Enum.h" using namespace XCEngine::RHI; #pragma comment(lib,"d3d12.lib") #pragma comment(lib,"dxgi.lib") #pragma comment(lib,"d3dcompiler.lib") #pragma comment(lib,"winmm.lib") //================================================================================= // D3D12 核心全局对象 (最小渲染所需) //================================================================================= ID3D12Device* gD3D12Device = nullptr; ID3D12CommandQueue* gCommandQueue = nullptr; IDXGISwapChain3* gSwapChain = nullptr; // 渲染目标 (SwapChain的后台Buffer) ID3D12Resource* gDSRT = nullptr; // 深度模板缓冲 ID3D12Resource* gColorRTs[2]; // 颜色缓冲 (双缓冲) int gCurrentRTIndex = 0; // 描述符堆 ID3D12DescriptorHeap* gSwapChainRTVHeap = nullptr; // RTV堆 ID3D12DescriptorHeap* gSwapChainDSVHeap = nullptr; // DSV堆 UINT gRTVDescriptorSize = 0; UINT gDSVDescriptorSize = 0; // 命令相关 ID3D12CommandAllocator* gCommandAllocator = nullptr; ID3D12GraphicsCommandList* gCommandList = nullptr; // 同步对象 ID3D12Fence* gFence = nullptr; HANDLE gFenceEvent = nullptr; UINT64 gFenceValue = 0; //================================================================================= // 工具函数前向声明 //================================================================================= D3D12_RESOURCE_BARRIER InitResourceBarrier( ID3D12Resource* inResource, D3D12_RESOURCE_STATES inPrevState, D3D12_RESOURCE_STATES inNextState); ID3D12Resource* CreateBufferObject(ID3D12GraphicsCommandList* inCommandList, void* inData, int inDataLen, D3D12_RESOURCE_STATES inFinalResourceState); //================================================================================= // 工具函数 //================================================================================= 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 { ID3D12Resource* mIBO; D3D12_INDEX_BUFFER_VIEW mIBView; int mIndexCount; }; //================================================================================= // 网格组件类 (StaticMeshComponent) // 封装顶点缓冲(VBO)、索引缓冲(IBO)和渲染逻辑 //================================================================================= class StaticMeshComponent { public: ID3D12Resource* mVBO; D3D12_VERTEX_BUFFER_VIEW mVBOView; StaticMeshComponentVertexData* mVertexData; int mVertexCount; 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; mVertexData = new StaticMeshComponentVertexData[mVertexCount]; fread(mVertexData, 1, sizeof(StaticMeshComponentVertexData) * mVertexCount, pFile); mVBO = CreateBufferObject(inCommandList, mVertexData, sizeof(StaticMeshComponentVertexData) * mVertexCount, D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER); mVBOView.BufferLocation = mVBO->GetGPUVirtualAddress(); mVBOView.SizeInBytes = sizeof(StaticMeshComponentVertexData) * mVertexCount; mVBOView.StrideInBytes = sizeof(StaticMeshComponentVertexData); 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 = CreateBufferObject(inCommandList, indexes, sizeof(unsigned int) * temp, D3D12_RESOURCE_STATE_INDEX_BUFFER); submesh->mIBView.BufferLocation = submesh->mIBO->GetGPUVirtualAddress(); submesh->mIBView.SizeInBytes = sizeof(unsigned int) * temp; submesh->mIBView.Format = DXGI_FORMAT_R32_UINT; mSubMeshes.insert(std::pair(name, submesh)); delete[] indexes; } fclose(pFile); } } void Render(ID3D12GraphicsCommandList* inCommandList) { D3D12_VERTEX_BUFFER_VIEW vbos[] = { mVBOView }; inCommandList->IASetVertexBuffers(0, 1, vbos); if (mSubMeshes.empty()) { inCommandList->DrawInstanced(mVertexCount, 1, 0, 0); } else { for (auto iter = mSubMeshes.begin(); iter != mSubMeshes.end(); iter++) { inCommandList->IASetIndexBuffer(&iter->second->mIBView); inCommandList->DrawIndexedInstanced(iter->second->mIndexCount, 1, 0, 0, 0); } } } }; //================================================================================= // ResourceBarrier 工具函数 // 用于资源状态转换 (例如: PRESENT → RENDER_TARGET) //================================================================================= D3D12_RESOURCE_BARRIER InitResourceBarrier( ID3D12Resource* inResource, D3D12_RESOURCE_STATES inPrevState, D3D12_RESOURCE_STATES inNextState) { D3D12_RESOURCE_BARRIER d3d12ResourceBarrier; memset(&d3d12ResourceBarrier, 0, sizeof(d3d12ResourceBarrier)); d3d12ResourceBarrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION; d3d12ResourceBarrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE; d3d12ResourceBarrier.Transition.pResource = inResource; d3d12ResourceBarrier.Transition.StateBefore = inPrevState; d3d12ResourceBarrier.Transition.StateAfter = inNextState; d3d12ResourceBarrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES; return d3d12ResourceBarrier; } //================================================================================= // 根签名初始化 (RootSignature) // 定义GPU资源绑定规则: CBV(常量缓冲) / SRV(着色器资源) / DescriptorTable //================================================================================= ID3D12RootSignature* InitRootSignature() { D3D12_ROOT_PARAMETER rootParameters[4]; rootParameters[1].ParameterType = D3D12_ROOT_PARAMETER_TYPE_32BIT_CONSTANTS; rootParameters[1].ShaderVisibility = ToD3D12(ShaderVisibility::Vertex); rootParameters[1].Constants.RegisterSpace = 0; rootParameters[1].Constants.ShaderRegister = 0; rootParameters[1].Constants.Num32BitValues = 4; rootParameters[0].ParameterType = D3D12_ROOT_PARAMETER_TYPE_CBV; rootParameters[0].ShaderVisibility = ToD3D12(ShaderVisibility::All); rootParameters[0].Descriptor.RegisterSpace = 0; rootParameters[0].Descriptor.ShaderRegister = 1; 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].ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE; rootParameters[2].ShaderVisibility = ToD3D12(ShaderVisibility::Pixel); rootParameters[2].DescriptorTable.pDescriptorRanges = descriptorRange; rootParameters[2].DescriptorTable.NumDescriptorRanges = _countof(descriptorRange); rootParameters[3].ParameterType = D3D12_ROOT_PARAMETER_TYPE_SRV; rootParameters[3].ShaderVisibility = ToD3D12(ShaderVisibility::All); rootParameters[3].Descriptor.RegisterSpace = 1; rootParameters[3].Descriptor.ShaderRegister = 0; D3D12_STATIC_SAMPLER_DESC samplerDesc[1]; memset(samplerDesc, 0, sizeof(D3D12_STATIC_SAMPLER_DESC) * _countof(samplerDesc)); samplerDesc[0].Filter = ToD3D12(FilterMode::Linear); samplerDesc[0].AddressU = ToD3D12(TextureAddressMode::Clamp); samplerDesc[0].AddressV = ToD3D12(TextureAddressMode::Clamp); samplerDesc[0].AddressW = ToD3D12(TextureAddressMode::Clamp); samplerDesc[0].BorderColor = ToD3D12(BorderColor::OpaqueBlack); samplerDesc[0].MaxLOD = D3D12_FLOAT32_MAX; samplerDesc[0].RegisterSpace = 0; samplerDesc[0].ShaderRegister = 0; samplerDesc[0].ShaderVisibility = ToD3D12(ShaderVisibility::Pixel); D3D12_ROOT_SIGNATURE_DESC rootSignatureDesc = {}; rootSignatureDesc.NumParameters = _countof(rootParameters); rootSignatureDesc.pParameters = rootParameters; rootSignatureDesc.NumStaticSamplers = _countof(samplerDesc); rootSignatureDesc.pStaticSamplers = samplerDesc; rootSignatureDesc.Flags = D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT; ID3DBlob* signature; HRESULT hResult = D3D12SerializeRootSignature(&rootSignatureDesc, D3D_ROOT_SIGNATURE_VERSION_1, &signature, nullptr); ID3D12RootSignature* d3d12RootSignature; gD3D12Device->CreateRootSignature( 0, signature->GetBufferPointer(), signature->GetBufferSize(), IID_PPV_ARGS(&d3d12RootSignature)); return d3d12RootSignature; } //================================================================================= // 着色器加载函数 // 从.hlsl文件编译着色器 (VS/GS/PS) //================================================================================= void CreateShaderFromFile( LPCTSTR inShaderFilePath, const char* inMainFunctionName, const char* inTarget, D3D12_SHADER_BYTECODE* inShader) { ID3DBlob* shaderBuffer = nullptr; ID3DBlob* errorBuffer = nullptr; HRESULT hResult = D3DCompileFromFile(inShaderFilePath, nullptr, nullptr, inMainFunctionName, inTarget, D3DCOMPILE_DEBUG | D3DCOMPILE_SKIP_OPTIMIZATION, 0, &shaderBuffer, &errorBuffer); if (FAILED(hResult)) { char szLog[1024] = { 0 }; strcpy_s(szLog, (char*)errorBuffer->GetBufferPointer()); printf("CreateShaderFromFile error : [%s][%s]:[%s]\n", inMainFunctionName, inTarget, szLog); errorBuffer->Release(); return; } inShader->pShaderBytecode = shaderBuffer->GetBufferPointer(); inShader->BytecodeLength = shaderBuffer->GetBufferSize(); } //================================================================================= // 常量缓冲 (Constant Buffer) 创建与更新 // UPLOAD堆: CPU可写, GPU可读 //================================================================================= ID3D12Resource* CreateConstantBufferObject(int inDataLen) { D3D12_HEAP_PROPERTIES d3dHeapProperties = {}; d3dHeapProperties.Type = D3D12_HEAP_TYPE_UPLOAD; D3D12_RESOURCE_DESC d3d12ResourceDesc = {}; d3d12ResourceDesc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER; d3d12ResourceDesc.Alignment = 0; d3d12ResourceDesc.Width = inDataLen; d3d12ResourceDesc.Height = 1; d3d12ResourceDesc.DepthOrArraySize = 1; d3d12ResourceDesc.MipLevels = 1; d3d12ResourceDesc.Format = DXGI_FORMAT_UNKNOWN; d3d12ResourceDesc.SampleDesc.Count = 1; d3d12ResourceDesc.SampleDesc.Quality = 0; d3d12ResourceDesc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR; d3d12ResourceDesc.Flags = D3D12_RESOURCE_FLAG_NONE; ID3D12Resource* bufferObject = nullptr; gD3D12Device->CreateCommittedResource( &d3dHeapProperties, D3D12_HEAP_FLAG_NONE, &d3d12ResourceDesc, D3D12_RESOURCE_STATE_GENERIC_READ, nullptr, IID_PPV_ARGS(&bufferObject) ); return bufferObject; } //================================================================================= // 更新常量缓冲数据 //================================================================================= void UpdateConstantBuffer(ID3D12Resource* inCB, void* inData, int inDataLen) { D3D12_RANGE d3d12Range = { 0 }; unsigned char* pBuffer = nullptr; inCB->Map(0, &d3d12Range, (void**)&pBuffer); memcpy(pBuffer, inData, inDataLen); inCB->Unmap(0, nullptr); } //================================================================================= // GPU Buffer创建 (顶点/索引缓冲) // DEFAULT堆 → 通过Upload堆中转数据 → 状态转换 //================================================================================= ID3D12Resource* CreateBufferObject(ID3D12GraphicsCommandList* inCommandList, void* inData, int inDataLen, D3D12_RESOURCE_STATES inFinalResourceState) { D3D12_HEAP_PROPERTIES d3dHeapProperties = {}; d3dHeapProperties.Type = D3D12_HEAP_TYPE_DEFAULT; D3D12_RESOURCE_DESC d3d12ResourceDesc = {}; d3d12ResourceDesc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER; d3d12ResourceDesc.Alignment = 0; d3d12ResourceDesc.Width = inDataLen; d3d12ResourceDesc.Height = 1; d3d12ResourceDesc.DepthOrArraySize = 1; d3d12ResourceDesc.MipLevels = 1; d3d12ResourceDesc.Format = DXGI_FORMAT_UNKNOWN; d3d12ResourceDesc.SampleDesc.Count = 1; d3d12ResourceDesc.SampleDesc.Quality = 0; d3d12ResourceDesc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR; d3d12ResourceDesc.Flags = D3D12_RESOURCE_FLAG_NONE; ID3D12Resource* bufferObject = nullptr; gD3D12Device->CreateCommittedResource( &d3dHeapProperties, D3D12_HEAP_FLAG_NONE, &d3d12ResourceDesc, D3D12_RESOURCE_STATE_COPY_DEST, nullptr, IID_PPV_ARGS(&bufferObject) ); d3d12ResourceDesc = bufferObject->GetDesc(); UINT64 memorySizeUsed = 0; UINT64 rowSizeInBytes = 0; UINT rowUsed = 0; D3D12_PLACED_SUBRESOURCE_FOOTPRINT subresourceFootprint; gD3D12Device->GetCopyableFootprints(&d3d12ResourceDesc, 0, 1, 0, &subresourceFootprint, &rowUsed, &rowSizeInBytes, &memorySizeUsed); ID3D12Resource* tempBufferObject = nullptr; d3dHeapProperties = {}; d3dHeapProperties.Type = D3D12_HEAP_TYPE_UPLOAD; gD3D12Device->CreateCommittedResource( &d3dHeapProperties, D3D12_HEAP_FLAG_NONE, &d3d12ResourceDesc, D3D12_RESOURCE_STATE_GENERIC_READ, nullptr, IID_PPV_ARGS(&tempBufferObject) ); BYTE* pData; tempBufferObject->Map(0, nullptr, reinterpret_cast(&pData)); BYTE* pDstTempBuffer = reinterpret_cast(pData + subresourceFootprint.Offset); const BYTE* pSrcData = reinterpret_cast(inData); for (UINT i = 0; i < rowUsed; i++) { memcpy(pDstTempBuffer + subresourceFootprint.Footprint.RowPitch * i, pSrcData + rowSizeInBytes * i, rowSizeInBytes); } tempBufferObject->Unmap(0, nullptr); inCommandList->CopyBufferRegion(bufferObject, 0, tempBufferObject, 0, subresourceFootprint.Footprint.Width); D3D12_RESOURCE_BARRIER barrier = InitResourceBarrier(bufferObject, D3D12_RESOURCE_STATE_COPY_DEST, inFinalResourceState); inCommandList->ResourceBarrier(1, &barrier); return bufferObject; } //================================================================================= // 2D纹理创建 // DEFAULT堆 → 通过Upload堆中转数据 → CopyTextureRegion → 状态转换 //================================================================================= ID3D12Resource* CreateTexture2D(ID3D12GraphicsCommandList* inCommandList, const void* inPixelData, int inDataSizeInBytes, int inWidth, int inHeight, DXGI_FORMAT inFormat) { D3D12_HEAP_PROPERTIES d3dHeapProperties = {}; d3dHeapProperties.Type = D3D12_HEAP_TYPE_DEFAULT; D3D12_RESOURCE_DESC d3d12ResourceDesc = {}; d3d12ResourceDesc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D; d3d12ResourceDesc.Alignment = 0; d3d12ResourceDesc.Width = inWidth; d3d12ResourceDesc.Height = inHeight; d3d12ResourceDesc.DepthOrArraySize = 1; d3d12ResourceDesc.MipLevels = 1; d3d12ResourceDesc.Format = inFormat; d3d12ResourceDesc.SampleDesc.Count = 1; d3d12ResourceDesc.SampleDesc.Quality = 0; d3d12ResourceDesc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN; d3d12ResourceDesc.Flags = D3D12_RESOURCE_FLAG_NONE; ID3D12Resource* texture = nullptr; gD3D12Device->CreateCommittedResource(&d3dHeapProperties, D3D12_HEAP_FLAG_NONE, &d3d12ResourceDesc, D3D12_RESOURCE_STATE_COPY_DEST, nullptr, IID_PPV_ARGS(&texture) ); d3d12ResourceDesc = texture->GetDesc(); UINT64 memorySizeUsed = 0; UINT64 rowSizeInBytes = 0; UINT rowUsed = 0; D3D12_PLACED_SUBRESOURCE_FOOTPRINT subresourceFootprint; gD3D12Device->GetCopyableFootprints(&d3d12ResourceDesc, 0, 1, 0, &subresourceFootprint, &rowUsed, &rowSizeInBytes, &memorySizeUsed); ID3D12Resource* tempBufferObject = nullptr; D3D12_HEAP_PROPERTIES d3dTempHeapProperties = {}; d3dTempHeapProperties.Type = D3D12_HEAP_TYPE_UPLOAD; D3D12_RESOURCE_DESC d3d12TempResourceDesc = {}; d3d12TempResourceDesc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER; d3d12TempResourceDesc.Alignment = 0; d3d12TempResourceDesc.Width = memorySizeUsed; d3d12TempResourceDesc.Height = 1; d3d12TempResourceDesc.DepthOrArraySize = 1; d3d12TempResourceDesc.MipLevels = 1; d3d12TempResourceDesc.Format = DXGI_FORMAT_UNKNOWN; d3d12TempResourceDesc.SampleDesc.Count = 1; d3d12TempResourceDesc.SampleDesc.Quality = 0; d3d12TempResourceDesc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR; d3d12TempResourceDesc.Flags = D3D12_RESOURCE_FLAG_NONE; gD3D12Device->CreateCommittedResource( &d3dTempHeapProperties, D3D12_HEAP_FLAG_NONE, &d3d12TempResourceDesc, D3D12_RESOURCE_STATE_GENERIC_READ, nullptr, IID_PPV_ARGS(&tempBufferObject) ); BYTE* pData; tempBufferObject->Map(0, nullptr, reinterpret_cast(&pData)); BYTE* pDstTempBuffer = reinterpret_cast(pData + subresourceFootprint.Offset); const BYTE* pSrcData = reinterpret_cast(inPixelData); for (UINT i = 0; i < rowUsed; i++) { memcpy(pDstTempBuffer + subresourceFootprint.Footprint.RowPitch * i, pSrcData + rowSizeInBytes * i, rowSizeInBytes); } tempBufferObject->Unmap(0, nullptr); D3D12_TEXTURE_COPY_LOCATION dst = {}; dst.pResource = texture; dst.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX; dst.SubresourceIndex = 0; D3D12_TEXTURE_COPY_LOCATION src = {}; src.pResource = tempBufferObject; src.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT; src.PlacedFootprint = subresourceFootprint; inCommandList->CopyTextureRegion(&dst, 0, 0, 0, &src, nullptr); D3D12_RESOURCE_BARRIER barrier = InitResourceBarrier(texture, D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE); inCommandList->ResourceBarrier(1, &barrier); return texture; } //================================================================================= // 渲染管线状态对象 (PSO) // 包含: InputLayout / VS/GS/PS / Rasterizer / DepthStencil / Blend //================================================================================= ID3D12PipelineState* CreatePSO(ID3D12RootSignature* inID3D12RootSignature, D3D12_SHADER_BYTECODE inVertexShader, D3D12_SHADER_BYTECODE inPixelShader, D3D12_SHADER_BYTECODE inGSShader) { D3D12_INPUT_ELEMENT_DESC vertexDataElementDesc[] = { {"POSITION",0,DXGI_FORMAT_R32G32B32A32_FLOAT,0,0,D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA,0}, {"TEXCOORD",0,DXGI_FORMAT_R32G32B32A32_FLOAT,0,sizeof(float) * 4,D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA,0}, {"NORMAL",0,DXGI_FORMAT_R32G32B32A32_FLOAT,0,sizeof(float) * 8,D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA,0}, {"TANGENT",0,DXGI_FORMAT_R32G32B32A32_FLOAT,0,sizeof(float) * 12,D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA,0} }; D3D12_INPUT_LAYOUT_DESC vertexDataLayoutDesc = {}; vertexDataLayoutDesc.NumElements = 4; vertexDataLayoutDesc.pInputElementDescs = vertexDataElementDesc; D3D12_GRAPHICS_PIPELINE_STATE_DESC psoDesc = {}; psoDesc.pRootSignature = inID3D12RootSignature; psoDesc.VS = inVertexShader; psoDesc.GS = inGSShader; psoDesc.PS = inPixelShader; psoDesc.RTVFormats[0] = DXGI_FORMAT_R8G8B8A8_UNORM; psoDesc.DSVFormat = DXGI_FORMAT_D24_UNORM_S8_UINT; psoDesc.SampleDesc.Count = 1; psoDesc.SampleDesc.Quality = 0; psoDesc.SampleMask = 0xffffffff; psoDesc.InputLayout = vertexDataLayoutDesc; psoDesc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE; psoDesc.RasterizerState.FillMode = ToD3D12(FillMode::Solid); psoDesc.RasterizerState.CullMode = ToD3D12(CullMode::Back); psoDesc.RasterizerState.DepthClipEnable = TRUE; psoDesc.DepthStencilState.DepthEnable = true; psoDesc.DepthStencilState.DepthWriteMask = D3D12_DEPTH_WRITE_MASK_ALL; psoDesc.DepthStencilState.DepthFunc = ToD3D12(ComparisonFunc::LessEqual); psoDesc.BlendState = { 0 }; D3D12_RENDER_TARGET_BLEND_DESC rtBlendDesc = { FALSE,FALSE, ToD3D12(BlendFactor::SrcAlpha),ToD3D12(BlendFactor::InvSrcAlpha),ToD3D12(BlendOp::Add), ToD3D12(BlendFactor::SrcAlpha),ToD3D12(BlendFactor::InvSrcAlpha),ToD3D12(BlendOp::Add), ToD3D12(LogicOp::Noop), static_cast(ColorWriteMask::All), }; for (int i = 0; i < D3D12_SIMULTANEOUS_RENDER_TARGET_COUNT; ++i) psoDesc.BlendState.RenderTarget[i] = rtBlendDesc; psoDesc.NumRenderTargets = 1; ID3D12PipelineState* d3d12PSO = nullptr; HRESULT hResult = gD3D12Device->CreateGraphicsPipelineState(&psoDesc, IID_PPV_ARGS(&d3d12PSO)); if (FAILED(hResult)) { return nullptr; } return d3d12PSO; } //================================================================================= // 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) { HRESULT hResult; UINT dxgiFactoryFlags = 0; #ifdef _DEBUG { ID3D12Debug* debugController = nullptr; if (SUCCEEDED(D3D12GetDebugInterface(IID_PPV_ARGS(&debugController)))) { debugController->EnableDebugLayer(); dxgiFactoryFlags |= DXGI_CREATE_FACTORY_DEBUG; } } #endif IDXGIFactory4* dxgiFactory; hResult = CreateDXGIFactory2(dxgiFactoryFlags, IID_PPV_ARGS(&dxgiFactory)); if (FAILED(hResult)) { return false; } IDXGIAdapter1* adapter; int adapterIndex = 0; bool adapterFound = false; while (dxgiFactory->EnumAdapters1(adapterIndex, &adapter) != DXGI_ERROR_NOT_FOUND) { DXGI_ADAPTER_DESC1 desc; adapter->GetDesc1(&desc); if (desc.Flags & DXGI_ADAPTER_FLAG_SOFTWARE) { continue; } hResult = D3D12CreateDevice(adapter, D3D_FEATURE_LEVEL_11_0, __uuidof(ID3D12Device), nullptr); if (SUCCEEDED(hResult)) { adapterFound = true; break; } adapterIndex++; } if (false == adapterFound) { return false; } hResult = D3D12CreateDevice(adapter, D3D_FEATURE_LEVEL_11_0, IID_PPV_ARGS(&gD3D12Device)); if (FAILED(hResult)) { return false; } D3D12_COMMAND_QUEUE_DESC d3d12CommandQueueDesc = {}; hResult = gD3D12Device->CreateCommandQueue(&d3d12CommandQueueDesc, IID_PPV_ARGS(&gCommandQueue)); if (FAILED(hResult)) { 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, &swapChainDesc, &swapChain); gSwapChain = static_cast(swapChain); D3D12_HEAP_PROPERTIES d3dHeapProperties = {}; d3dHeapProperties.Type = D3D12_HEAP_TYPE_DEFAULT; D3D12_RESOURCE_DESC d3d12ResourceDesc = {}; d3d12ResourceDesc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D; d3d12ResourceDesc.Alignment = 0; d3d12ResourceDesc.Width = inWidth; d3d12ResourceDesc.Height = inHeight; d3d12ResourceDesc.DepthOrArraySize = 1; d3d12ResourceDesc.MipLevels = 1; d3d12ResourceDesc.Format = DXGI_FORMAT_D24_UNORM_S8_UINT; d3d12ResourceDesc.SampleDesc.Count = 1; d3d12ResourceDesc.SampleDesc.Quality = 0; d3d12ResourceDesc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN; d3d12ResourceDesc.Flags = D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL; D3D12_CLEAR_VALUE dsClearValue = {}; dsClearValue.Format = DXGI_FORMAT_D24_UNORM_S8_UINT; dsClearValue.DepthStencil.Depth = 1.0f; dsClearValue.DepthStencil.Stencil = 0; gD3D12Device->CreateCommittedResource(&d3dHeapProperties, D3D12_HEAP_FLAG_NONE, &d3d12ResourceDesc, D3D12_RESOURCE_STATE_DEPTH_WRITE, &dsClearValue, IID_PPV_ARGS(&gDSRT) ); D3D12_DESCRIPTOR_HEAP_DESC d3dDescriptorHeapDescRTV = {}; d3dDescriptorHeapDescRTV.NumDescriptors = 2; d3dDescriptorHeapDescRTV.Type = D3D12_DESCRIPTOR_HEAP_TYPE_RTV; gD3D12Device->CreateDescriptorHeap(&d3dDescriptorHeapDescRTV, IID_PPV_ARGS(&gSwapChainRTVHeap)); gRTVDescriptorSize = gD3D12Device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_RTV); D3D12_DESCRIPTOR_HEAP_DESC d3dDescriptorHeapDescDSV = {}; d3dDescriptorHeapDescDSV.NumDescriptors = 1; d3dDescriptorHeapDescDSV.Type = D3D12_DESCRIPTOR_HEAP_TYPE_DSV; gD3D12Device->CreateDescriptorHeap(&d3dDescriptorHeapDescDSV, IID_PPV_ARGS(&gSwapChainDSVHeap)); gDSVDescriptorSize = gD3D12Device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_DSV); D3D12_CPU_DESCRIPTOR_HANDLE rtvHeapStart = gSwapChainRTVHeap->GetCPUDescriptorHandleForHeapStart(); for (int i = 0; i < 2; i++) { gSwapChain->GetBuffer(i, IID_PPV_ARGS(&gColorRTs[i])); D3D12_CPU_DESCRIPTOR_HANDLE rtvPointer; rtvPointer.ptr = rtvHeapStart.ptr + i * gRTVDescriptorSize; gD3D12Device->CreateRenderTargetView(gColorRTs[i], nullptr, rtvPointer); } D3D12_DEPTH_STENCIL_VIEW_DESC d3dDSViewDesc = {}; d3dDSViewDesc.Format = DXGI_FORMAT_D24_UNORM_S8_UINT; d3dDSViewDesc.ViewDimension = D3D12_DSV_DIMENSION_TEXTURE2D; gD3D12Device->CreateDepthStencilView(gDSRT, &d3dDSViewDesc, gSwapChainDSVHeap->GetCPUDescriptorHandleForHeapStart()); gD3D12Device->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(&gCommandAllocator)); gD3D12Device->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, gCommandAllocator, nullptr, IID_PPV_ARGS(&gCommandList)); gD3D12Device->CreateFence(0, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(&gFence)); gFenceEvent = CreateEvent(nullptr, FALSE, FALSE, nullptr); return true; } //================================================================================= // 命令相关辅助函数 //================================================================================= ID3D12CommandAllocator* GetCommandAllocator() { return gCommandAllocator; } ID3D12GraphicsCommandList* GetCommandList() { return gCommandList; } void WaitForCompletionOfCommandList() { if (gFence->GetCompletedValue() < gFenceValue) { gFence->SetEventOnCompletion(gFenceValue, gFenceEvent); WaitForSingleObject(gFenceEvent, INFINITE); } } //================================================================================= // 命令列表结束提交 // 关闭CommandList → ExecuteCommandLists → Signal Fence //================================================================================= void EndCommandList() { gCommandList->Close(); ID3D12CommandList* ppCommandLists[] = { gCommandList }; gCommandQueue->ExecuteCommandLists(1, ppCommandLists); gFenceValue += 1; gCommandQueue->Signal(gFence, gFenceValue); } //================================================================================= // 开始渲染到SwapChain // 1. 获取当前BackBuffer索引 // 2. 状态转换: PRESENT → RENDER_TARGET // 3. 设置RenderTargets (Color + Depth) // 4. 设置Viewport/Scissor // 5. Clear Color/Depth //================================================================================= void BeginRenderToSwapChain(ID3D12GraphicsCommandList* inCommandList) { gCurrentRTIndex = gSwapChain->GetCurrentBackBufferIndex(); D3D12_RESOURCE_BARRIER barrier = InitResourceBarrier(gColorRTs[gCurrentRTIndex], D3D12_RESOURCE_STATE_PRESENT, D3D12_RESOURCE_STATE_RENDER_TARGET); inCommandList->ResourceBarrier(1, &barrier); D3D12_CPU_DESCRIPTOR_HANDLE colorRT, dsv; dsv.ptr = gSwapChainDSVHeap->GetCPUDescriptorHandleForHeapStart().ptr; colorRT.ptr = gSwapChainRTVHeap->GetCPUDescriptorHandleForHeapStart().ptr + gCurrentRTIndex * gRTVDescriptorSize; inCommandList->OMSetRenderTargets(1, &colorRT, FALSE, &dsv); D3D12_VIEWPORT viewport = { 0.0f,0.0f,1280.0f,720.0f }; D3D12_RECT scissorRect = { 0,0,1280,720 }; inCommandList->RSSetViewports(1, &viewport); inCommandList->RSSetScissorRects(1, &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(ID3D12GraphicsCommandList* inCommandList) { D3D12_RESOURCE_BARRIER barrier = InitResourceBarrier(gColorRTs[gCurrentRTIndex], D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_PRESENT); inCommandList->ResourceBarrier(1, &barrier); } //================================================================================= // 交换缓冲区 (显示渲染结果) //================================================================================= void SwapD3D12Buffers() { gSwapChain->Present(0, 0); } //================================================================================= // 获取D3D12设备 //================================================================================= ID3D12Device* GetD3DDevice() { return gD3D12Device; } //================================================================================= // 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) { 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); ID3D12GraphicsCommandList* commandList = GetCommandList(); ID3D12CommandAllocator* commandAllocator = GetCommandAllocator(); StaticMeshComponent staticMeshComponent; staticMeshComponent.InitFromFile(commandList, "Res/Model/Sphere.lhsm"); ID3D12RootSignature* rootSignature = InitRootSignature(); D3D12_SHADER_BYTECODE vs, gs, ps; CreateShaderFromFile(L"Res/Shader/gs.hlsl", "MainVS", "vs_5_1", &vs); CreateShaderFromFile(L"Res/Shader/gs.hlsl", "MainGS", "gs_5_1", &gs); CreateShaderFromFile(L"Res/Shader/gs.hlsl", "MainPS", "ps_5_1", &ps); ID3D12PipelineState* pso = CreatePSO(rootSignature, vs, ps, gs); ID3D12Resource* cb = CreateConstantBufferObject(65536); 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); } UpdateConstantBuffer(cb, matrices, sizeof(float) * 64); ID3D12Resource* sb = CreateConstantBufferObject(65536); struct MaterialData { float r; }; MaterialData* materialDatas = new MaterialData[3000]; for (int i = 0; i < 3000; i++) { materialDatas[i].r = srandom() * 0.1f + 0.1f; } UpdateConstantBuffer(sb, materialDatas, sizeof(MaterialData) * 3000); int imageWidth, imageHeight, imageChannel; stbi_uc* pixels = stbi_load("Res/Image/earth_d.jpg", &imageWidth, &imageHeight, &imageChannel, 4); ID3D12Resource* texture = CreateTexture2D(commandList, pixels, imageWidth * imageHeight * imageChannel, imageWidth, imageHeight, DXGI_FORMAT_R8G8B8A8_UNORM); delete[] pixels; ID3D12Device* d3dDevice = GetD3DDevice(); ID3D12DescriptorHeap* srvHeap = nullptr; D3D12_DESCRIPTOR_HEAP_DESC d3dDescriptorHeapDescSRV = {}; d3dDescriptorHeapDescSRV.NumDescriptors = 3; d3dDescriptorHeapDescSRV.Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV; d3dDescriptorHeapDescSRV.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE; d3dDevice->CreateDescriptorHeap(&d3dDescriptorHeapDescSRV, IID_PPV_ARGS(&srvHeap)); ID3D12DescriptorHeap* descriptorHeaps[] = { srvHeap }; 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(); d3dDevice->CreateShaderResourceView(texture, &srvDesc, srvHeapPtr); srvHeapPtr.ptr += d3dDevice->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_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; 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 { 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(); commandList->Reset(commandAllocator, nullptr); BeginRenderToSwapChain(commandList); commandList->SetPipelineState(pso); commandList->SetGraphicsRootSignature(rootSignature); commandList->SetDescriptorHeaps(_countof(descriptorHeaps), descriptorHeaps); commandList->SetGraphicsRootConstantBufferView(0, cb->GetGPUVirtualAddress()); commandList->SetGraphicsRoot32BitConstants(1, 4, color, 0); commandList->SetGraphicsRootDescriptorTable(2, srvHeap->GetGPUDescriptorHandleForHeapStart()); commandList->SetGraphicsRootShaderResourceView(3, sb->GetGPUVirtualAddress()); commandList->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST); staticMeshComponent.Render(commandList); EndRenderToSwapChain(commandList); EndCommandList(); SwapD3D12Buffers(); } } return 0; }