diff --git a/README.md b/README.md index b7f7b0d3..e3334623 100644 --- a/README.md +++ b/README.md @@ -36,4 +36,13 @@ The behaviour of DXVK can be modified with environment variables. - `DXVK_SHADER_DUMP_PATH=directory` Writes all DXBC and SPIR-V shaders to the given directory - `DXVK_SHADER_READS_PATH=directory` Reads SPIR-V shaders from the given directory instead of compiling the DXBC shader. -- `DXVK_DEBUG_LAYERS=1` Enables Vulkan debug layers. Highly recommended for troubleshooting and debugging purposes. \ No newline at end of file +- `DXVK_DEBUG_LAYERS=1` Enables Vulkan debug layers. Highly recommended for troubleshooting and debugging purposes. + +## Samples and executables +In addition to the DLLs, the following standalone programs are included in the project: + +- `d3d11-triangle`: Renders a triangle using D3D11. Requires native `d3dcompiler_47.dll`. +- `dxgi-factory`: Enumerates DXGI adapters and outputs for debugging purposes. +- `dxbc-dcompiler`: Compiles a DXBC shader to SPIR-V. +- `dxbc-disasm`: Disassembles a DXBC shader. Requires native `d3dcompiler_47.dll`. +- `dxvk-triangle`: Renders a triangle using pure DXVK, which is the Vulkan-based state tracker that the D3D11 implementation is based on. \ No newline at end of file diff --git a/src/d3d11/d3d11_device.cpp b/src/d3d11/d3d11_device.cpp index bab8af5e..b93dcc07 100644 --- a/src/d3d11/d3d11_device.cpp +++ b/src/d3d11/d3d11_device.cpp @@ -366,6 +366,7 @@ namespace dxvk { pInputElementDescs[i].Format).actual; attrib.offset = pInputElementDescs[i].AlignedByteOffset; + // TODO implement D3D11_APPEND_ALIGNED_ELEMENT if (attrib.offset == D3D11_APPEND_ALIGNED_ELEMENT) { Logger::err("D3D11Device::CreateInputLayout: D3D11_APPEND_ALIGNED_ELEMENT not supported yet"); return E_INVALIDARG; diff --git a/tests/d3d11/meson.build b/tests/d3d11/meson.build index 4898aa1f..8ce823cb 100644 --- a/tests/d3d11/meson.build +++ b/tests/d3d11/meson.build @@ -1,4 +1,4 @@ -test_d3d11_deps = [ util_dep, lib_dxgi, lib_d3d11 ] +test_d3d11_deps = [ util_dep, lib_dxgi, lib_d3d11, lib_d3dcompiler_47 ] executable('d3d11-compute', files('test_d3d11_compute.cpp'), dependencies : test_d3d11_deps, install : true) executable('d3d11-triangle', files('test_d3d11_triangle.cpp'), dependencies : test_d3d11_deps, install : true) \ No newline at end of file diff --git a/tests/d3d11/test_d3d11_triangle.cpp b/tests/d3d11/test_d3d11_triangle.cpp index f16b3103..11c10941 100644 --- a/tests/d3d11/test_d3d11_triangle.cpp +++ b/tests/d3d11/test_d3d11_triangle.cpp @@ -1,3 +1,4 @@ +#include #include #include @@ -7,11 +8,46 @@ using namespace dxvk; +struct Extent2D { + uint32_t w, h; +}; + +struct Vertex { + float x, y, z, w; + float r, g, b, a; +}; + +const std::string g_vertexShaderCode = + "struct VsInput {\n" + " float4 position : IN_POSITION;\n" + " float4 color : IN_COLOR;\n" + "};\n" + "struct VsOutput {\n" + " float4 position : SV_POSITION;\n" + " float4 color : PS_COLOR;\n" + "};\n" + "VsOutput main(VsInput vsIn) {\n" + " VsOutput vsOut;\n" + " vsOut.position = vsIn.position;\n" + " vsOut.color = vsIn.color;\n" + " return vsOut;\n" + "}\n"; + +const std::string g_pixelShaderCode = + "struct PsInput {\n" + " float4 position : SV_POSITION;\n" + " float4 color : PS_COLOR;\n" + "};\n" + "float4 main(PsInput psIn) : SV_TARGET {\n" + " return psIn.color;\n" + "}\n"; + class TriangleApp { public: - TriangleApp(HINSTANCE instance, HWND window) { + TriangleApp(HINSTANCE instance, HWND window) + : m_window(window) { if (FAILED(CreateDXGIFactory(__uuidof(IDXGIFactory), reinterpret_cast(&m_factory)))) throw DxvkError("Failed to create DXGI factory"); @@ -33,8 +69,8 @@ public: throw DxvkError("Failed to create D3D11 device"); DXGI_SWAP_CHAIN_DESC swapDesc; - swapDesc.BufferDesc.Width = 1024; - swapDesc.BufferDesc.Height = 600; + swapDesc.BufferDesc.Width = m_windowSize.w; + swapDesc.BufferDesc.Height = m_windowSize.h; swapDesc.BufferDesc.RefreshRate = { 60, 1 }; swapDesc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM_SRGB; swapDesc.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED; @@ -42,7 +78,7 @@ public: swapDesc.SampleDesc.Count = 1; swapDesc.SampleDesc.Quality = 0; swapDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; - swapDesc.BufferCount = 1; + swapDesc.BufferCount = 2; swapDesc.OutputWindow = window; swapDesc.Windowed = true; swapDesc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD; @@ -60,6 +96,77 @@ public: if (FAILED(m_swapChain->ResizeTarget(&swapDesc.BufferDesc))) throw DxvkError("Failed to resize window"); + std::array vertexData = {{ + { -0.5f, -0.5f, 0.0f, 1.0f, 0.03f, 0.03f, 0.03f, 1.0f }, + { 0.0f, 0.5f, 0.0f, 1.0f, 0.03f, 0.03f, 0.03f, 1.0f }, + { 0.5f, -0.5f, 0.0f, 1.0f, 0.03f, 0.03f, 0.03f, 1.0f }, + }}; + + D3D11_BUFFER_DESC vertexDesc; + vertexDesc.ByteWidth = sizeof(Vertex) * vertexData.size(); + vertexDesc.Usage = D3D11_USAGE_IMMUTABLE; + vertexDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER; + vertexDesc.CPUAccessFlags = 0; + vertexDesc.MiscFlags = 0; + vertexDesc.StructureByteStride = 0; + + D3D11_SUBRESOURCE_DATA vertexDataInfo; + vertexDataInfo.pSysMem = vertexData.data(); + vertexDataInfo.SysMemPitch = 0; + vertexDataInfo.SysMemSlicePitch = 0; + + Com vertexShaderBlob; + Com pixelShaderBlob; + + if (FAILED(D3DCompile( + g_vertexShaderCode.data(), + g_vertexShaderCode.size(), + "Vertex shader", + nullptr, nullptr, + "main", "vs_5_0", 0, 0, + &vertexShaderBlob, + nullptr))) + throw DxvkError("Failed to compile vertex shader"); + + if (FAILED(D3DCompile( + g_pixelShaderCode.data(), + g_pixelShaderCode.size(), + "Pixel shader", + nullptr, nullptr, + "main", "ps_5_0", 0, 0, + &pixelShaderBlob, + nullptr))) + throw DxvkError("Failed to compile pixel shader"); + + if (FAILED(m_device->CreateVertexShader( + vertexShaderBlob->GetBufferPointer(), + vertexShaderBlob->GetBufferSize(), + nullptr, &m_vertexShader))) + throw DxvkError("Failed to create vertex shader"); + + if (FAILED(m_device->CreatePixelShader( + pixelShaderBlob->GetBufferPointer(), + pixelShaderBlob->GetBufferSize(), + nullptr, &m_pixelShader))) + throw DxvkError("Failed to create pixel shader"); + + + if (FAILED(m_device->CreateBuffer(&vertexDesc, &vertexDataInfo, &m_vertexBuffer))) + throw DxvkError("Failed to create vertex buffer"); + + std::array vertexFormatDesc = {{ + { "IN_POSITION", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, offsetof(Vertex, x), D3D11_INPUT_PER_VERTEX_DATA, 0 }, + { "IN_COLOR", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, offsetof(Vertex, r), D3D11_INPUT_PER_VERTEX_DATA, 0 }, + }}; + + if (FAILED(m_device->CreateInputLayout( + vertexFormatDesc.data(), + vertexFormatDesc.size(), + vertexShaderBlob->GetBufferPointer(), + vertexShaderBlob->GetBufferSize(), + &m_vertexFormat))) + throw DxvkError("Failed to create input layout"); + } @@ -69,15 +176,69 @@ public: void run() { - FLOAT color[4] = { 0.5f, 0.5f, 0.5f, 1.0f }; + this->adjustBackBuffer(); + D3D11_VIEWPORT viewport; + viewport.TopLeftX = 0.0f; + viewport.TopLeftY = 0.0f; + viewport.Width = static_cast(m_windowSize.w); + viewport.Height = static_cast(m_windowSize.h); + viewport.MinDepth = 0.0f; + viewport.MaxDepth = 1.0f; + m_context->RSSetViewports(1, &viewport); + + FLOAT color[4] = { 0.5f, 0.5f, 0.5f, 1.0f }; m_context->OMSetRenderTargets(1, &m_bufferView, nullptr); m_context->ClearRenderTargetView(m_bufferView.ptr(), color); + + m_context->VSSetShader(m_vertexShader.ptr(), nullptr, 0); + m_context->PSSetShader(m_pixelShader.ptr(), nullptr, 0); + + UINT vsStride = sizeof(Vertex); + UINT vsOffset = 0; + + m_context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); + m_context->IASetInputLayout(m_vertexFormat.ptr()); + m_context->IASetVertexBuffers(0, 1, &m_vertexBuffer, &vsStride, &vsOffset); + m_context->Draw(3, 0); + m_context->OMSetRenderTargets(0, nullptr, nullptr); + m_swapChain->Present(0, 0); } + + void adjustBackBuffer() { + RECT windowRect = { 0, 0, 1024, 600 }; + GetClientRect(m_window, &windowRect); + + Extent2D newWindowSize = { + static_cast(windowRect.right - windowRect.left), + static_cast(windowRect.bottom - windowRect.top), + }; + + if (m_windowSize.w != newWindowSize.w + || m_windowSize.h != newWindowSize.h) { + m_buffer = nullptr; + m_bufferView = nullptr; + + if (FAILED(m_swapChain->ResizeBuffers(0, + newWindowSize.w, newWindowSize.h, DXGI_FORMAT_UNKNOWN, 0))) + throw DxvkError("Failed to resize back buffers"); + + if (FAILED(m_swapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), reinterpret_cast(&m_buffer)))) + throw DxvkError("Failed to get swap chain back buffer"); + + if (FAILED(m_device->CreateRenderTargetView(m_buffer.ptr(), nullptr, &m_bufferView))) + throw DxvkError("Failed to create render target view"); + m_windowSize = newWindowSize; + } + } + private: + HWND m_window; + Extent2D m_windowSize = { 1024, 600 }; + Com m_factory; Com m_adapter; Com m_device; @@ -86,8 +247,13 @@ private: Com m_buffer; Com m_bufferView; + Com m_vertexBuffer; + Com m_vertexFormat; - D3D_FEATURE_LEVEL m_featureLevel; + Com m_vertexShader; + Com m_pixelShader; + + D3D_FEATURE_LEVEL m_featureLevel; };