#include "Graphics.h" #include "dxerr.h" #include #include #include namespace dx = DirectX; namespace wrl = Microsoft::WRL; #pragma comment(lib,"d3d11.lib") #pragma comment(lib,"D3DCompiler.lib") // graphics exception checking/throwing macros (some with dxgi infos) #define GFX_EXCEPT_NOINFO(hr) Graphics::HrException( __LINE__,__FILE__,(hr) ) #define GFX_THROW_NOINFO(hrcall) if( FAILED( hr = (hrcall) ) ) throw Graphics::HrException( __LINE__,__FILE__,hr ) #ifndef NDEBUG #define GFX_EXCEPT(hr) Graphics::HrException( __LINE__,__FILE__,(hr),infoManager.GetMessages() ) #define GFX_THROW_INFO(hrcall) infoManager.Set(); if( FAILED( hr = (hrcall) ) ) throw GFX_EXCEPT(hr) #define GFX_DEVICE_REMOVED_EXCEPT(hr) Graphics::DeviceRemovedException( __LINE__,__FILE__,(hr),infoManager.GetMessages() ) #define GFX_THROW_INFO_ONLY(call) infoManager.Set(); (call); {auto v = infoManager.GetMessages(); if(!v.empty()) {throw Graphics::InfoException( __LINE__,__FILE__,v);}} #else #define GFX_EXCEPT(hr) Graphics::HrException( __LINE__,__FILE__,(hr) ) #define GFX_THROW_INFO(hrcall) GFX_THROW_NOINFO(hrcall) #define GFX_DEVICE_REMOVED_EXCEPT(hr) Graphics::DeviceRemovedException( __LINE__,__FILE__,(hr) ) #define GFX_THROW_INFO_ONLY(call) (call) #endif Graphics::Graphics( HWND hWnd ) { // 交换链的参数定义 DXGI_SWAP_CHAIN_DESC sd = {}; sd.BufferDesc.Width = 0; sd.BufferDesc.Height = 0; sd.BufferDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM; sd.BufferDesc.RefreshRate.Numerator = 0; sd.BufferDesc.RefreshRate.Denominator = 0; sd.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED; sd.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED; sd.SampleDesc.Count = 1; sd.SampleDesc.Quality = 0; sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; sd.BufferCount = 1; sd.OutputWindow = hWnd; sd.Windowed = TRUE; sd.SwapEffect = DXGI_SWAP_EFFECT_DISCARD; sd.Flags = 0; UINT swapCreateFlags = 0u; #ifndef NDEBUG swapCreateFlags |= D3D11_CREATE_DEVICE_DEBUG; #endif // for checking results of d3d functions HRESULT hr; // create device and front/back buffers, and swap chain and rendering context // 创建Device,SwapChain和Context GFX_THROW_INFO(D3D11CreateDeviceAndSwapChain( nullptr, D3D_DRIVER_TYPE_HARDWARE, nullptr, swapCreateFlags, nullptr, 0, D3D11_SDK_VERSION, &sd, &pSwap, &pDevice, nullptr, &pContext )); // gain access to texture subresource in swap chain (back buffer) wrl::ComPtr pBackBuffer; GFX_THROW_INFO(pSwap->GetBuffer(0, __uuidof(ID3D11Resource), &pBackBuffer)); GFX_THROW_INFO(pDevice->CreateRenderTargetView(pBackBuffer.Get(), nullptr, &pTarget)); // Create depth stencil state D3D11_DEPTH_STENCIL_DESC depthStencilDesc = {}; depthStencilDesc.DepthEnable = TRUE; depthStencilDesc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ALL; depthStencilDesc.DepthFunc = D3D11_COMPARISON_LESS; wrl::ComPtr pDepthStencilState; // Create depth stencil state GFX_THROW_INFO(pDevice->CreateDepthStencilState(&depthStencilDesc, &pDepthStencilState)); // bind depth state pContext->OMSetDepthStencilState(pDepthStencilState.Get(), 1u); // Create the depth stencil texture wrl::ComPtr depthStencilTexture; D3D11_TEXTURE2D_DESC depthStencilTextureDesc = {}; depthStencilTextureDesc.Width = 800; depthStencilTextureDesc.Height = 600; depthStencilTextureDesc.MipLevels = 1u; depthStencilTextureDesc.ArraySize = 1u; depthStencilTextureDesc.Format = DXGI_FORMAT_D32_FLOAT; depthStencilTextureDesc.SampleDesc.Count = 1u; depthStencilTextureDesc.SampleDesc.Quality = 0u; depthStencilTextureDesc.Usage = D3D11_USAGE_DEFAULT; depthStencilTextureDesc.BindFlags = D3D11_BIND_DEPTH_STENCIL; GFX_THROW_INFO(pDevice->CreateTexture2D(&depthStencilTextureDesc, nullptr, &depthStencilTexture)); // Create the depth stencil view D3D11_DEPTH_STENCIL_VIEW_DESC depthStencilViewDesc = {}; depthStencilViewDesc.Format = DXGI_FORMAT_D32_FLOAT; depthStencilViewDesc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2D; depthStencilViewDesc.Texture2D.MipSlice = 0u; GFX_THROW_INFO(pDevice->CreateDepthStencilView(depthStencilTexture.Get(), &depthStencilViewDesc, &pDSView)); // Bind depth stencil view to out put merger pContext->OMSetRenderTargets(1u, pTarget.GetAddressOf(), pDSView.Get()); } void Graphics::EndFrame() { // flipping,使用SwapChain将back buffer的内容展现到屏幕 HRESULT hr; #ifndef NDEBUG infoManager.Set(); #endif if (FAILED(hr = pSwap->Present(1u, 0u))) // 同步频率1,代表屏幕每刷新一次,就进行图形刷新。 { if (hr == DXGI_ERROR_DEVICE_REMOVED) { throw GFX_DEVICE_REMOVED_EXCEPT(pDevice->GetDeviceRemovedReason()); } else { throw GFX_EXCEPT(hr); } } } void Graphics::ClearBuffer(float red, float green, float blue) noexcept { const float color[] = { red,green,blue,1.0f }; pContext->ClearRenderTargetView(pTarget.Get(), color); pContext->ClearDepthStencilView(pDSView.Get(), D3D11_CLEAR_DEPTH, 1.0f, 0u); } void Graphics::DrawTestTriangle(float angle, float x, float y) { namespace wrl = Microsoft::WRL; HRESULT hr; struct Vertex { struct { float x; float y; float z; } pos; }; // create vertex buffer (8 vertices for one cube) const Vertex vertices[] = { // left bottom back { -1.0f, -1.0f, -1.0f }, // right bottom back { 1.0f, -1.0f, -1.0f }, // left top back { -1.0f, 1.0f, -1.0f }, // right top back { 1.0f, 1.0f, -1.0f }, // left bottom front { -1.0f, -1.0f, 1.0f }, // right bottom front { 1.0f, -1.0f, 1.0f }, // left top front { -1.0f, 1.0f, 1.0f }, // right top front { 1.0f, 1.0f, 1.0f }, }; wrl::ComPtr pVertexBuffer; D3D11_BUFFER_DESC bd = {}; bd.BindFlags = D3D11_BIND_VERTEX_BUFFER; bd.Usage = D3D11_USAGE_DEFAULT; bd.CPUAccessFlags = 0u; bd.MiscFlags = 0u; bd.ByteWidth = sizeof(vertices); bd.StructureByteStride = sizeof(Vertex); D3D11_SUBRESOURCE_DATA sd = {}; sd.pSysMem = vertices; GFX_THROW_INFO(pDevice->CreateBuffer(&bd, &sd, &pVertexBuffer)); // Bind vertex buffer to pipeline const UINT stride = sizeof(Vertex); const UINT offset = 0u; pContext->IASetVertexBuffers(0u, 1u, pVertexBuffer.GetAddressOf(), &stride, &offset); // Create index buffer const unsigned short indices[] = { // back surface 0, 2, 1, 2, 3, 1, // right surface 1, 3, 5, 3, 7, 5, // top surface 2, 6, 3, 3, 6, 7, // front surface 4, 5, 7, 4, 7, 6, // left surface 0, 4, 2, 2, 4, 6, // bottom surface 0, 1, 4, 1, 5, 4, }; wrl::ComPtr pIndexBuffer; D3D11_BUFFER_DESC ibd = {}; ibd.BindFlags = D3D11_BIND_INDEX_BUFFER; ibd.Usage = D3D11_USAGE_DEFAULT; ibd.CPUAccessFlags = 0u; ibd.MiscFlags = 0u; ibd.ByteWidth = sizeof(indices); ibd.StructureByteStride = sizeof(unsigned short); D3D11_SUBRESOURCE_DATA isd = {}; isd.pSysMem = indices; GFX_THROW_INFO(pDevice->CreateBuffer(&ibd, &isd, &pIndexBuffer)); // Bind index buffer to pipeline pContext->IASetIndexBuffer(pIndexBuffer.Get(), DXGI_FORMAT_R16_UINT, 0u); // Create constant buffer for transformation matrix struct ConstantBuffer { // Use extended mathematics matrix which is optmized for SIMD // SIMD (Single Instruction Multiple Data) is available in mordern processors dx::XMMATRIX transform; }; const float heightWidthRatio = 0.3f / 0.4f; const ConstantBuffer cb = { // transpose the matrix to change from row_major to column_major dx::XMMatrixTranspose( // rotate Z axis dx::XMMatrixRotationZ(-angle) // rotate X axis * dx::XMMatrixRotationX(-angle) // rotate Y axis * dx::XMMatrixRotationY(-angle) // attach the image to mouse * dx::XMMatrixTranslation( x, 0.0f, 4.0f + y ) // projection * dx::XMMatrixPerspectiveLH( 1.0f, heightWidthRatio, 0.5f, 10.0f) ) }; wrl::ComPtr pConstantBuffer; D3D11_BUFFER_DESC cbd = {}; cbd.BindFlags = D3D11_BIND_CONSTANT_BUFFER; cbd.Usage = D3D11_USAGE_DYNAMIC; cbd.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; cbd.MiscFlags = 0u; cbd.ByteWidth = sizeof(cb); cbd.StructureByteStride = 0u; D3D11_SUBRESOURCE_DATA csd = {}; csd.pSysMem = &cb; GFX_THROW_INFO(pDevice->CreateBuffer(&cbd, &csd, &pConstantBuffer)); // Bind constant buffer to vertex pContext->VSSetConstantBuffers(0u, 1u, pConstantBuffer.GetAddressOf()); // Create constant buffer for color struct ColorConstantBuffer { struct { float r; float g; float b; float a; } face_colors[6]; }; const ColorConstantBuffer ccb = { { { 1.0f, 0.0f, 1.0f }, { 1.0f, 0.0f, 0.0f }, { 0.0f, 1.0f, 0.0f }, { 0.0f, 0.0f, 1.0f }, { 1.0f, 1.0f, 0.0f }, { 0.0f, 1.0f, 1.0f }, } }; wrl::ComPtr pColorConstantBuffer; D3D11_BUFFER_DESC ccbd = {}; ccbd.BindFlags = D3D11_BIND_CONSTANT_BUFFER; ccbd.Usage = D3D11_USAGE_DEFAULT; ccbd.CPUAccessFlags = 0u; ccbd.MiscFlags = 0u; ccbd.ByteWidth = sizeof(ccb); ccbd.StructureByteStride = 0u; D3D11_SUBRESOURCE_DATA ccsd = {}; ccsd.pSysMem = &ccb; GFX_THROW_INFO(pDevice->CreateBuffer(&ccbd, &ccsd, &pColorConstantBuffer)); // Bind constant buffer to vertex pContext->PSSetConstantBuffers(0u, 1u, pColorConstantBuffer.GetAddressOf()); // create pixel shader wrl::ComPtr pPixelShader; wrl::ComPtr pBlob; GFX_THROW_INFO(D3DReadFileToBlob(L"PixelShader.cso", &pBlob)); GFX_THROW_INFO(pDevice->CreatePixelShader(pBlob->GetBufferPointer(), pBlob->GetBufferSize(), nullptr, &pPixelShader)); // bind pixel shader pContext->PSSetShader(pPixelShader.Get(), nullptr, 0u); // create vertex shader wrl::ComPtr pVertexShader; GFX_THROW_INFO(D3DReadFileToBlob(L"VertexShader.cso", &pBlob)); GFX_THROW_INFO(pDevice->CreateVertexShader(pBlob->GetBufferPointer(), pBlob->GetBufferSize(), nullptr, &pVertexShader)); // bind vertex shader pContext->VSSetShader(pVertexShader.Get(), nullptr, 0u); // create pixel shader // input (vertex) layout (2d position only) wrl::ComPtr pInputLayout; const D3D11_INPUT_ELEMENT_DESC ied[] = { { "Position",0,DXGI_FORMAT_R32G32B32_FLOAT,0,0,D3D11_INPUT_PER_VERTEX_DATA,0 }, //{ "Color",0,DXGI_FORMAT_R32G32B32_FLOAT,0,12,D3D11_INPUT_PER_VERTEX_DATA,0 }, }; GFX_THROW_INFO(pDevice->CreateInputLayout( ied, (UINT)std::size(ied), pBlob->GetBufferPointer(), pBlob->GetBufferSize(), &pInputLayout )); // bind vertex layout pContext->IASetInputLayout(pInputLayout.Get()); // bind render target // After apply depth stencil view to Output Merger, we remove this one //pContext->OMSetRenderTargets(1u, pTarget.GetAddressOf(), nullptr); // Set primitive topology to triangle list (groups of 3 vertices) pContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); // configure viewport D3D11_VIEWPORT vp; vp.Width = 800; vp.Height = 600; vp.MinDepth = 0; vp.MaxDepth = 1; vp.TopLeftX = 0; vp.TopLeftY = 0; pContext->RSSetViewports(1u, &vp); //GFX_THROW_INFO_ONLY(pContext->Draw((UINT)std::size(vertices), 0u)); GFX_THROW_INFO_ONLY(pContext->DrawIndexed((UINT)std::size(indices), 0u, 0u)); } // Graphics exception stuff Graphics::HrException::HrException(int line, const char* file, HRESULT hr, std::vector infoMsgs) noexcept : Exception(line, file), hr(hr) { // join all info messages with newlines into single string for (const auto& m : infoMsgs) { info += m; info.push_back('\n'); } // remove final newline if exists if (!info.empty()) { info.pop_back(); } } const char* Graphics::HrException::what() const noexcept { std::ostringstream oss; oss << GetType() << std::endl << "[Error Code] 0x" << std::hex << std::uppercase << GetErrorCode() << std::dec << " (" << (unsigned long)GetErrorCode() << ")" << std::endl << "[Error String] " << GetErrorString() << std::endl << "[Description] " << GetErrorDescription() << std::endl; if (!info.empty()) { oss << "\n[Error Info]\n" << GetErrorInfo() << std::endl << std::endl; } oss << GetOriginString(); whatBuffer = oss.str(); return whatBuffer.c_str(); } const char* Graphics::HrException::GetType() const noexcept { return "Chili Graphics Exception"; } HRESULT Graphics::HrException::GetErrorCode() const noexcept { return hr; } std::string Graphics::HrException::GetErrorString() const noexcept { return DXGetErrorString(hr); } std::string Graphics::HrException::GetErrorDescription() const noexcept { char buf[512]; DXGetErrorDescription(hr, buf, sizeof(buf)); return buf; } std::string Graphics::HrException::GetErrorInfo() const noexcept { return info; } const char* Graphics::DeviceRemovedException::GetType() const noexcept { return "Chili Graphics Exception [Device Removed] (DXGI_ERROR_DEVICE_REMOVED)"; } Graphics::InfoException::InfoException(int line, const char* file, std::vector infoMsgs) noexcept : Exception(line, file) { // join all info messages with newlines into single string for (const auto& m : infoMsgs) { info += m; info.push_back('\n'); } // remove final newline if exists if (!info.empty()) { info.pop_back(); } } const char* Graphics::InfoException::what() const noexcept { std::ostringstream oss; oss << GetType() << std::endl << "\n[Error Info]\n" << GetErrorInfo() << std::endl << std::endl; oss << GetOriginString(); whatBuffer = oss.str(); return whatBuffer.c_str(); } const char* Graphics::InfoException::GetType() const noexcept { return "Chili Graphics Info Exception"; } std::string Graphics::InfoException::GetErrorInfo() const noexcept { return info; }