#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 = 2; sd.OutputWindow = hWnd; sd.Windowed = TRUE; sd.SwapEffect = DXGI_SWAP_EFFECT_FLIP_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)); } 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); } void Graphics::DrawTestTriangle(float angle, float x, float y) { namespace wrl = Microsoft::WRL; HRESULT hr; struct Vertex { struct { float x; float y; } pos; struct { float r; float g; float b; } color; }; // create vertex buffer (1 2d triangle at center of screen) const Vertex vertices[] = { // center { 0.0f, 0.5f, 1.0f, 0.0f, 0.0f }, { 0.5f, -0.5f, 0.0f, 1.0f, 0.0f }, { -0.5f, -0.5f, 0.0f, 0.0f, 1.0f }, // left top { -0.3f, 0.3f, 0.0f, 1.0f, 0.0f }, // right top { 0.3f, 0.3f, 0.0f, 0.0f, 1.0f }, // center bottom { 0.0f, -0.8f, 1.0f, 0.0f, 0.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[] = { 0, 1, 2, 0, 2, 3, 0, 4, 1, 2, 1, 5, }; 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) // scale to avoid distortion * dx::XMMatrixScaling(3.0f / 4.0f, 1.0f, 1.0f) // attach the image to mouse * dx::XMMatrixTranslation( x, y, 0.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 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_R32G32_FLOAT,0,0,D3D11_INPUT_PER_VERTEX_DATA,0 }, { "Color",0,DXGI_FORMAT_R32G32B32_FLOAT,0,8,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 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; }