From 1516464c8b22a7a05a5fcc9d4bdcc818932c0716 Mon Sep 17 00:00:00 2001 From: Philip Rebohle Date: Sun, 27 Jun 2021 04:17:47 +0200 Subject: [PATCH] [tests] Update D3D11 triangle test Essentially implements a microbenchmark for state changes. --- tests/d3d11/test_d3d11_triangle.cpp | 965 +++++++++++++++------------- 1 file changed, 504 insertions(+), 461 deletions(-) diff --git a/tests/d3d11/test_d3d11_triangle.cpp b/tests/d3d11/test_d3d11_triangle.cpp index 469cc323e..5c2ea78f0 100644 --- a/tests/d3d11/test_d3d11_triangle.cpp +++ b/tests/d3d11/test_d3d11_triangle.cpp @@ -1,112 +1,59 @@ #include -#include +#include +#include #include #include -#include +#include +#include +#include -#include "../../src/util/thread.h" #include "../test_utils.h" using namespace dxvk; -struct Extent2D { - uint32_t w, h; -}; - struct Vertex { - float x, y, z, w; + float x, y; }; -struct Color { - uint8_t r, g, b, a; +struct VsConstants { + float x, y; + float w, h; +}; + +struct VsConstantsPad { + VsConstants data; + uint32_t pad[60]; +}; + +struct PsConstants { + float r, g, b, a; +}; + +struct DrawOptions { + bool mapDiscardOnce; + bool sortByTexture; + bool drawIndexed; }; - bool m_report = false; - const std::string g_vertexShaderCode = - "Buffer buf : register(t0);\n" - "struct vs_out {\n" - " float4 pos : POSITION;\n" - " float4 color : COLOR;\n" + "cbuffer vs_cb : register(b0) {\n" + " float2 v_offset;\n" + " float2 v_scale;\n" "};\n" - "vs_out main(float4 vsIn : IN_POSITION,\n" - " uint vid : SV_VERTEXID,\n" - " uint iid : SV_INSTANCEID) {\n" - " vs_out result;\n" - " result.pos = vsIn;\n" - " result.color.x = buf[vid].x;\n" - " result.color.y = buf[iid * 3].y;\n" - " result.color.z = buf[0].z;\n" - " result.color.w = 1.0f;\n" - " return result;\n" + "float4 main(float4 v_pos : IN_POSITION) : SV_POSITION {\n" + " float2 coord = 2.0f * (v_pos * v_scale + v_offset) - 1.0f;\n" + " return float4(coord, 0.0f, 1.0f);\n" "}\n"; -const std::string g_hullShaderCode = - "struct vs_out {\n" - " float4 pos : POSITION;\n" - " float4 color : COLOR;\n" - "};\n" - "struct hs_vtx {\n" - " float4 pos : POSITION;\n" - "};\n" - "struct hs_patch {\n" - " float4 color : COLOR;\n" - " float tessEdge[3] : SV_TessFactor;\n" - " float tessInner : SV_InsideTessFactor;\n" - "};\n" - "hs_patch main_pc(InputPatch ip) {\n" - " hs_patch ov;\n" - " ov.color = ip[0].color;\n" - " ov.tessEdge[0] = 4.0f;\n" - " ov.tessEdge[1] = 4.0f;\n" - " ov.tessEdge[2] = 4.0f;\n" - " ov.tessInner = 4.0f;\n" - " return ov;\n" - "}\n" - "[domain(\"tri\")]\n" - "[partitioning(\"fractional_odd\")]\n" - "[outputtopology(\"triangle_cw\")]\n" - "[outputcontrolpoints(3)]\n" - "[patchconstantfunc(\"main_pc\")]\n" - "hs_vtx main(InputPatch ip, uint i : SV_OutputControlPointID) {\n" - " hs_vtx ov;\n" - " ov.pos = ip[i].pos;\n" - " return ov;\n" - "}\n"; - -const std::string g_domainShaderCode = - "struct ds_out {\n" - " float4 pos : SV_POSITION;\n" - " float4 color : COLOR;\n" - "};\n" - "struct hs_vtx {\n" - " float4 pos : POSITION;\n" - "};\n" - "struct hs_patch {\n" - " float4 color : COLOR;\n" - " float tessEdge[3] : SV_TessFactor;\n" - " float tessInner : SV_InsideTessFactor;\n" - "};\n" - "[domain(\"tri\")]\n" - "ds_out main(float3 p : SV_DomainLocation, OutputPatch ip, hs_patch pc) {\n" - " ds_out ov;\n" - " ov.pos = ip[0].pos * p.x\n" - " + ip[1].pos * p.y\n" - " + ip[2].pos * p.z;\n" - " ov.color = pc.color;\n" - " return ov;\n" - "}\n"; - - const std::string g_pixelShaderCode = - "struct vs_out {\n" - " float4 pos : SV_POSITION;\n" - " float4 color : COLOR;\n" + "Texture2D tex0 : register(t0);" + "cbuffer ps_cb : register(b0) {\n" + " float4 color;\n" "};\n" - "float4 main(vs_out ps_in) : SV_TARGET {\n" - " return ps_in.color;\n" + "float4 main() : SV_TARGET {\n" + " return color * tex0.Load(int3(0, 0, 0));\n" "}\n"; class TriangleApp { @@ -115,235 +62,227 @@ public: TriangleApp(HINSTANCE instance, HWND window) : m_window(window) { - if (FAILED(CreateDXGIFactory(__uuidof(IDXGIFactory), - reinterpret_cast(&m_factory)))) - throw DxvkError("Failed to create DXGI factory"); - - if (FAILED(m_factory->EnumAdapters(0, &m_adapter))) - throw DxvkError("Failed to enumerate DXGI adapter"); - + Com device; + + D3D_FEATURE_LEVEL fl = D3D_FEATURE_LEVEL_11_1; + HRESULT status = D3D11CreateDevice( - m_adapter.ptr(), - D3D_DRIVER_TYPE_UNKNOWN, - nullptr, 0, - nullptr, 0, - D3D11_SDK_VERSION, - &m_device, - &m_featureLevel, - &m_context); + nullptr, D3D_DRIVER_TYPE_HARDWARE, + nullptr, 0, &fl, 1, D3D11_SDK_VERSION, + &device, nullptr, nullptr); + + if (FAILED(status)) { + std::cerr << "Failed to create D3D11 device" << std::endl; + return; + } - if (FAILED(status)) - throw DxvkError("Failed to create D3D11 device"); + if (FAILED(device->QueryInterface(IID_PPV_ARGS(&m_device)))) { + std::cerr << "Failed to query ID3D11DeviceContext1" << std::endl; + return; + } + + Com dxgiDevice; + + if (FAILED(m_device->QueryInterface(IID_PPV_ARGS(&dxgiDevice)))) { + std::cerr << "Failed to query DXGI device" << std::endl; + return; + } + + if (FAILED(dxgiDevice->GetAdapter(&m_adapter))) { + std::cerr << "Failed to query DXGI adapter" << std::endl; + return; + } + + if (FAILED(m_adapter->GetParent(IID_PPV_ARGS(&m_factory)))) { + std::cerr << "Failed to query DXGI factory" << std::endl; + return; + } + + m_device->GetImmediateContext1(&m_context); + + DXGI_SWAP_CHAIN_DESC1 swapDesc; + swapDesc.Width = m_windowSizeW; + swapDesc.Height = m_windowSizeH; + swapDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; + swapDesc.Stereo = FALSE; + swapDesc.SampleDesc = { 1, 0 }; + swapDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; + swapDesc.BufferCount = 3; + swapDesc.Scaling = DXGI_SCALING_STRETCH; + swapDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD; + swapDesc.AlphaMode = DXGI_ALPHA_MODE_UNSPECIFIED; + swapDesc.Flags = DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT + | DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING; + + DXGI_SWAP_CHAIN_FULLSCREEN_DESC fsDesc; + fsDesc.RefreshRate = { 0, 0 }; + fsDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED; + fsDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED; + fsDesc.Windowed = TRUE; - DXGI_SWAP_CHAIN_DESC swapDesc; - 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; - swapDesc.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED; - swapDesc.SampleDesc.Count = 8; - swapDesc.SampleDesc.Quality = 0; - swapDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; - swapDesc.BufferCount = 2; - swapDesc.OutputWindow = window; - swapDesc.Windowed = true; - swapDesc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD; - swapDesc.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH; - - if (FAILED(m_factory->CreateSwapChain(m_device.ptr(), &swapDesc, &m_swapChain))) - throw DxvkError("Failed to create DXGI swap chain"); - - 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"); - - if (FAILED(m_swapChain->ResizeTarget(&swapDesc.BufferDesc))) - throw DxvkError("Failed to resize window"); - - std::array vertexData = {{ - { -0.25f, -0.15f, 0.0f, 1.0f }, - { -0.50f, -0.65f, 0.0f, 1.0f }, - { -0.75f, -0.15f, 0.0f, 1.0f }, - { 0.75f, -0.15f, 0.0f, 1.0f }, - { 0.50f, -0.65f, 0.0f, 1.0f }, - { 0.25f, -0.15f, 0.0f, 1.0f }, - { -0.75f, 0.15f, 0.0f, 1.0f }, - { -0.50f, 0.65f, 0.0f, 1.0f }, - { -0.25f, 0.15f, 0.0f, 1.0f }, - { 0.25f, 0.15f, 0.0f, 1.0f }, - { 0.50f, 0.65f, 0.0f, 1.0f }, - { 0.75f, 0.15f, 0.0f, 1.0f }, - { 0.25f, 0.75f, 0.0f, 1.0f }, - { 0.00f, 0.25f, 0.0f, 1.0f }, - { -0.25f, 0.75f, 0.0f, 1.0f }, - { -0.25f, -0.75f, 0.0f, 1.0f }, - { 0.00f, -0.25f, 0.0f, 1.0f }, - { 0.25f, -0.75f, 0.0f, 1.0f }, - { -0.25f, -0.25f, 0.0f, 1.0f }, - { 0.00f, 0.25f, 0.0f, 1.0f }, - { 0.25f, -0.25f, 0.0f, 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; - - if (FAILED(m_device->CreateBuffer(&vertexDesc, &vertexDataInfo, &m_vertexBuffer))) - throw DxvkError("Failed to create vertex buffer"); - - std::array indexData = {{ - 0, 1, 2, 0, 1, 2, 2, 1, 0 - }}; - - D3D11_BUFFER_DESC indexDesc; - indexDesc.ByteWidth = sizeof(uint32_t) * indexData.size(); - indexDesc.Usage = D3D11_USAGE_IMMUTABLE; - indexDesc.BindFlags = D3D11_BIND_INDEX_BUFFER; - indexDesc.CPUAccessFlags = 0; - indexDesc.MiscFlags = 0; - indexDesc.StructureByteStride = 0; - - D3D11_SUBRESOURCE_DATA indexDataInfo; - indexDataInfo.pSysMem = indexData.data(); - indexDataInfo.SysMemPitch = 0; - indexDataInfo.SysMemSlicePitch = 0; - - if (FAILED(m_device->CreateBuffer(&indexDesc, &indexDataInfo, &m_indexBuffer))) - throw DxvkError("Failed to create index buffer"); - - std::array resourceData = {{ - { 0x20, 0x20, 0x20, 0xFF }, - { 0x20, 0x20, 0x20, 0xFF }, - { 0x20, 0x20, 0x20, 0xFF }, - { 0xFF, 0xFF, 0x00, 0xFF }, - { 0xFF, 0xFF, 0x00, 0xFF }, - { 0xFF, 0xFF, 0x00, 0xFF }, - }}; - - D3D11_BUFFER_DESC resourceDesc; - resourceDesc.ByteWidth = sizeof(Color) * resourceData.size(); - resourceDesc.Usage = D3D11_USAGE_IMMUTABLE; - resourceDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE; - resourceDesc.CPUAccessFlags = 0; - resourceDesc.MiscFlags = 0; - resourceDesc.StructureByteStride = 0; - - D3D11_SUBRESOURCE_DATA resourceDataInfo; - resourceDataInfo.pSysMem = resourceData.data(); - resourceDataInfo.SysMemPitch = 0; - resourceDataInfo.SysMemSlicePitch = 0; - - if (FAILED(m_device->CreateBuffer(&resourceDesc, &resourceDataInfo, &m_resourceBuffer))) - throw DxvkError("Failed to create resource buffer"); - - D3D11_SHADER_RESOURCE_VIEW_DESC resourceViewDesc; - resourceViewDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; - resourceViewDesc.ViewDimension = D3D11_SRV_DIMENSION_BUFFER; - resourceViewDesc.Buffer.FirstElement = 0; - resourceViewDesc.Buffer.NumElements = resourceData.size(); - - if (FAILED(m_device->CreateShaderResourceView(m_resourceBuffer.ptr(), &resourceViewDesc, &m_resourceView))) - throw DxvkError("Failed to create resource buffer view"); + Com swapChain; + if (FAILED(m_factory->CreateSwapChainForHwnd(m_device.ptr(), m_window, &swapDesc, &fsDesc, nullptr, &swapChain))) { + std::cerr << "Failed to create DXGI swap chain" << std::endl; + return; + } + if (FAILED(swapChain->QueryInterface(IID_PPV_ARGS(&m_swapChain)))) { + std::cerr << "Failed to query DXGI swap chain interface" << std::endl; + return; + } + + m_factory->MakeWindowAssociation(m_window, 0); + Com vertexShaderBlob; - Com hullShaderBlob; - Com domainShaderBlob; 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_vertexShaderCode.data(), g_vertexShaderCode.size(), + "Vertex shader", nullptr, nullptr, "main", "vs_5_0", 0, 0, &vertexShaderBlob, nullptr))) { + std::cerr << "Failed to compile vertex shader" << std::endl; + return; + } - if (FAILED(D3DCompile( - g_hullShaderCode.data(), - g_hullShaderCode.size(), - "Hull shader", - nullptr, nullptr, - "main", "hs_5_0", 0, 0, - &hullShaderBlob, - nullptr))) - throw DxvkError("Failed to compile hull shader"); - - if (FAILED(D3DCompile( - g_domainShaderCode.data(), - g_domainShaderCode.size(), - "Domain shader", - nullptr, nullptr, - "main", "ds_5_0", 0, 0, - &domainShaderBlob, - nullptr))) - throw DxvkError("Failed to compile domain 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(D3DCompile(g_pixelShaderCode.data(), g_pixelShaderCode.size(), + "Pixel shader", nullptr, nullptr, "main", "ps_5_0", 0, 0, &pixelShaderBlob, nullptr))) { + std::cerr << "Failed to compile pixel shader" << std::endl; + return; + } if (FAILED(m_device->CreateVertexShader( - vertexShaderBlob->GetBufferPointer(), - vertexShaderBlob->GetBufferSize(), - nullptr, &m_vertexShader))) - throw DxvkError("Failed to create vertex shader"); - - if (FAILED(m_device->CreateHullShader( - hullShaderBlob->GetBufferPointer(), - hullShaderBlob->GetBufferSize(), - nullptr, &m_hullShader))) - throw DxvkError("Failed to create hull shader"); - - if (FAILED(m_device->CreateDomainShader( - domainShaderBlob->GetBufferPointer(), - domainShaderBlob->GetBufferSize(), - nullptr, &m_domainShader))) - throw DxvkError("Failed to create domain shader"); + vertexShaderBlob->GetBufferPointer(), + vertexShaderBlob->GetBufferSize(), + nullptr, &m_vs))) { + std::cerr << "Failed to create vertex shader" << std::endl; + return; + } if (FAILED(m_device->CreatePixelShader( - pixelShaderBlob->GetBufferPointer(), - pixelShaderBlob->GetBufferSize(), - nullptr, &m_pixelShader))) - throw DxvkError("Failed to create pixel shader"); + pixelShaderBlob->GetBufferPointer(), + pixelShaderBlob->GetBufferSize(), + nullptr, &m_ps))) { + std::cerr << "Failed to create pixel shader" << std::endl; + return; + } std::array vertexFormatDesc = {{ - { "IN_POSITION", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, offsetof(Vertex, x), D3D11_INPUT_PER_VERTEX_DATA, 0 }, + { "IN_POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 0, 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"); - - D3D11_QUERY_DESC queryDesc; - queryDesc.Query = D3D11_QUERY_OCCLUSION; - queryDesc.MiscFlags = 0; - - if (FAILED(m_device->CreateQuery(&queryDesc, &m_query))) - throw DxvkError("Failed to create occlusion query"); + vertexFormatDesc.data(), + vertexFormatDesc.size(), + vertexShaderBlob->GetBufferPointer(), + vertexShaderBlob->GetBufferSize(), + &m_vertexFormat))) { + std::cerr << "Failed to create input layout" << std::endl; + return; + } + + std::array vertexData = {{ + Vertex { -0.3f, 0.1f }, + Vertex { 0.5f, 0.9f }, + Vertex { 1.3f, 0.1f }, + Vertex { -0.3f, 0.9f }, + Vertex { 1.3f, 0.9f }, + Vertex { 0.5f, 0.1f }, + }}; + + D3D11_BUFFER_DESC vboDesc; + vboDesc.ByteWidth = sizeof(vertexData); + vboDesc.Usage = D3D11_USAGE_IMMUTABLE; + vboDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER; + vboDesc.CPUAccessFlags = 0; + vboDesc.MiscFlags = 0; + vboDesc.StructureByteStride = 0; + + D3D11_SUBRESOURCE_DATA vboData; + vboData.pSysMem = vertexData.data(); + vboData.SysMemPitch = vboDesc.ByteWidth; + vboData.SysMemSlicePitch = vboDesc.ByteWidth; + + if (FAILED(m_device->CreateBuffer(&vboDesc, &vboData, &m_vbo))) { + std::cerr << "Failed to create index buffer" << std::endl; + return; + } + + std::array indexData = {{ 0, 1, 2, 3, 4, 5 }}; + + D3D11_BUFFER_DESC iboDesc; + iboDesc.ByteWidth = sizeof(indexData); + iboDesc.Usage = D3D11_USAGE_IMMUTABLE; + iboDesc.BindFlags = D3D11_BIND_INDEX_BUFFER; + iboDesc.CPUAccessFlags = 0; + iboDesc.MiscFlags = 0; + iboDesc.StructureByteStride = 0; + + D3D11_SUBRESOURCE_DATA iboData; + iboData.pSysMem = indexData.data(); + iboData.SysMemPitch = iboDesc.ByteWidth; + iboData.SysMemSlicePitch = iboDesc.ByteWidth; + + if (FAILED(m_device->CreateBuffer(&iboDesc, &iboData, &m_ibo))) { + std::cerr << "Failed to create index buffer" << std::endl; + return; + } + + D3D11_BUFFER_DESC cbDesc; + cbDesc.ByteWidth = sizeof(PsConstants); + cbDesc.Usage = D3D11_USAGE_DYNAMIC; + cbDesc.BindFlags = D3D11_BIND_CONSTANT_BUFFER; + cbDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; + cbDesc.MiscFlags = 0; + cbDesc.StructureByteStride = 0; + + if (FAILED(m_device->CreateBuffer(&cbDesc, nullptr, &m_cbPs))) { + std::cerr << "Failed to create constant buffer" << std::endl; + return; + } + + cbDesc.ByteWidth = sizeof(VsConstantsPad) * 128 * 8; + + if (FAILED(m_device->CreateBuffer(&cbDesc, nullptr, &m_cbVs))) { + std::cerr << "Failed to create constant buffer" << std::endl; + return; + } + + std::array colors = { 0xFFFFFFFF, 0xFFC0C0C0 }; + + D3D11_SUBRESOURCE_DATA texData; + texData.pSysMem = &colors[0]; + texData.SysMemPitch = sizeof(colors[0]); + texData.SysMemSlicePitch = sizeof(colors[0]); + + D3D11_TEXTURE2D_DESC texDesc; + texDesc.Width = 1; + texDesc.Height = 1; + texDesc.MipLevels = 1; + texDesc.ArraySize = 1; + texDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; + texDesc.SampleDesc = { 1, 0 }; + texDesc.Usage = D3D11_USAGE_IMMUTABLE; + texDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE; + texDesc.CPUAccessFlags = 0; + texDesc.MiscFlags = 0; + + if (FAILED(m_device->CreateTexture2D(&texDesc, &texData, &m_tex0))) { + std::cerr << "Failed to create texture" << std::endl; + return; + } + + texData.pSysMem = &colors[1]; + + if (FAILED(m_device->CreateTexture2D(&texDesc, &texData, &m_tex1))) { + std::cerr << "Failed to create texture" << std::endl; + return; + } + + if (FAILED(m_device->CreateShaderResourceView(m_tex0.ptr(), nullptr, &m_srv0)) + || FAILED(m_device->CreateShaderResourceView(m_tex1.ptr(), nullptr, &m_srv1))) { + std::cerr << "Failed to create SRV" << std::endl; + return; + } + + m_initialized = true; } @@ -352,141 +291,266 @@ public: } - void run() { - 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->HSSetShader(m_hullShader.ptr(), nullptr, 0); - m_context->DSSetShader(m_domainShader.ptr(), nullptr, 0); - m_context->PSSetShader(m_pixelShader.ptr(), nullptr, 0); - - m_context->VSSetShaderResources(0, 1, &m_resourceView); - - UINT vsStride = sizeof(Vertex); - UINT vsOffset = 0; - - // Test normal draws with base vertex - m_context->Begin(m_query.ptr()); - m_context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_3_CONTROL_POINT_PATCHLIST); - m_context->IASetInputLayout(m_vertexFormat.ptr()); - m_context->IASetVertexBuffers(0, 1, &m_vertexBuffer, &vsStride, &vsOffset); - m_context->Draw(3, 0); - m_context->Draw(3, 3); - m_context->End(m_query.ptr()); - - // Test instanced draws with base instance and base vertex - vsOffset = 6 * sizeof(Vertex); - m_context->IASetVertexBuffers(0, 1, &m_vertexBuffer, &vsStride, &vsOffset); - m_context->DrawInstanced(3, 1, 0, 1); - m_context->DrawInstanced(3, 1, 3, 1); - - // Test indexed draws with base vertex and base index - vsOffset = 12 * sizeof(Vertex); - m_context->IASetVertexBuffers(0, 1, &m_vertexBuffer, &vsStride, &vsOffset); - m_context->IASetIndexBuffer(m_indexBuffer.ptr(), DXGI_FORMAT_R32_UINT, 0); - m_context->DrawIndexed(3, 0, 0); - m_context->DrawIndexed(3, 3, 3); - - // Test default backface culling - vsOffset = 18 * sizeof(Vertex); - m_context->IASetVertexBuffers(0, 1, &m_vertexBuffer, &vsStride, &vsOffset); - m_context->DrawIndexed(3, 6, 0); - - m_context->OMSetRenderTargets(0, nullptr, nullptr); - - m_swapChain->Present(1, 0); - - // Test query results - while (true) { - UINT64 samplesPassed = 0; - - UINT queryStatus = m_context->GetData( - m_query.ptr(), &samplesPassed, sizeof(samplesPassed), - D3D11_ASYNC_GETDATA_DONOTFLUSH); - - if (queryStatus == S_OK) { - if (samplesPassed == 0) - std::cerr << "Occlusion query returned 0 samples" << std::endl; - break; - } else if (queryStatus == S_FALSE) { - std::this_thread::yield(); - } else { - std::cerr << "Occlusion query failed" << std::endl; - break; + bool run() { + if (!m_initialized) + return false; + + if (m_occluded && (m_occluded = isOccluded())) + return true; + + if (!beginFrame()) + return true; + + std::array colors = {{ + PsConstants { 0.25f, 0.25f, 0.25f, 1.0f }, + PsConstants { 0.40f, 0.40f, 0.40f, 1.0f }, + }}; + + for (uint32_t i = 0; i < 8; i++) { + DrawOptions options; + options.sortByTexture = i & 1; + options.drawIndexed = i & 2; + options.mapDiscardOnce = i & 4; + drawLines(colors[i & 1], options, i); + } + + if (!endFrame()) + return false; + + updateFps(); + return true; + } + + + void drawLines(const PsConstants& psData, const DrawOptions& options, uint32_t baseY) { + D3D11_MAPPED_SUBRESOURCE sr; + + // Update color for the row + m_context->PSSetConstantBuffers(0, 1, &m_cbPs); + m_context->Map(m_cbPs.ptr(), 0, D3D11_MAP_WRITE_DISCARD, 0, &sr); + std::memcpy(sr.pData, &psData, sizeof(psData)); + m_context->Unmap(m_cbPs.ptr(), 0); + + baseY *= 8; + + if (options.mapDiscardOnce) { + uint32_t drawIndex = 0; + + // Discard and map the entire vertex constant buffer + // once, then bind sub-ranges while emitting draw calls + m_context->Map(m_cbVs.ptr(), 0, D3D11_MAP_WRITE_DISCARD, 0, &sr); + auto vsData = reinterpret_cast(sr.pData); + + for (uint32_t y = 0; y < 8; y++) { + for (uint32_t x = 0; x < 128; x++) + vsData[drawIndex++].data = getVsConstants(x, baseY + y); + } + + m_context->Unmap(m_cbVs.ptr(), 0); + } + + if (options.drawIndexed) + m_context->IASetIndexBuffer(m_ibo.ptr(), DXGI_FORMAT_R32_UINT, 0); + + uint32_t vsStride = sizeof(Vertex); + uint32_t vsOffset = 0; + m_context->IASetVertexBuffers(0, 1, &m_vbo, &vsStride, &vsOffset); + + uint32_t maxZ = options.sortByTexture ? 2 : 1; + + for (uint32_t z = 0; z < maxZ; z++) { + uint32_t drawIndex = z; + + if (options.sortByTexture) { + ID3D11ShaderResourceView* view = z ? m_srv1.ptr() : m_srv0.ptr(); + m_context->PSSetShaderResources(0, 1, &view); + } + + for (uint32_t y = 0; y < 8; y++) { + for (uint32_t x = z; x < 128; x += maxZ) { + uint32_t triIndex = (x ^ y) & 1; + + if (!options.mapDiscardOnce) { + D3D11_MAP mapMode = drawIndex ? D3D11_MAP_WRITE_NO_OVERWRITE : D3D11_MAP_WRITE_DISCARD; + m_context->Map(m_cbVs.ptr(), 0, mapMode, 0, &sr); + auto vsData = reinterpret_cast(sr.pData); + vsData[drawIndex].data = getVsConstants(x, baseY + y); + m_context->Unmap(m_cbVs.ptr(), 0); + } + + uint32_t constantOffset = 16 * drawIndex; + uint32_t constantCount = 16; + m_context->VSSetConstantBuffers1(0, 1, &m_cbVs, &constantOffset, &constantCount); + + if (!options.sortByTexture) { + ID3D11ShaderResourceView* view = triIndex ? m_srv1.ptr() : m_srv0.ptr(); + m_context->PSSetShaderResources(0, 1, &view); + } + + // Submit draw call + uint32_t baseIndex = 3 * triIndex; + + if (options.drawIndexed) + m_context->DrawIndexed(3, baseIndex, 0); + else + m_context->Draw(3, baseIndex); + + drawIndex += maxZ; + } } } } - - - void adjustBackBuffer() { + + + static VsConstants getVsConstants(uint32_t x, uint32_t y) { + VsConstants result; + result.x = float(x) / 128.0f; + result.y = float(y) / 64.0f; + result.w = 1.0f / 128.0f; + result.h = 1.0f / 64.0f; + return result; + } + + + bool beginFrame() { + // Make sure we can actually render to the window RECT windowRect = { 0, 0, 1024, 600 }; GetClientRect(m_window, &windowRect); - Extent2D newWindowSize = { - static_cast(windowRect.right - windowRect.left), - static_cast(windowRect.bottom - windowRect.top), - }; + uint32_t newWindowSizeW = uint32_t(windowRect.right - windowRect.left); + uint32_t newWindowSizeH = uint32_t(windowRect.bottom - windowRect.top); - if (m_windowSize.w != newWindowSize.w - || m_windowSize.h != newWindowSize.h) { - m_buffer = nullptr; - m_bufferView = nullptr; + if (m_windowSizeW != newWindowSizeW || m_windowSizeH != newWindowSizeH) { + m_rtv = nullptr; + m_context->ClearState(); + + DXGI_SWAP_CHAIN_DESC1 desc; + m_swapChain->GetDesc1(&desc); + + if (FAILED(m_swapChain->ResizeBuffers(desc.BufferCount, + newWindowSizeW, newWindowSizeH, desc.Format, desc.Flags))) { + std::cerr << "Failed to resize back buffers" << std::endl; + return false; + } - if (FAILED(m_swapChain->ResizeBuffers(0, - newWindowSize.w, newWindowSize.h, DXGI_FORMAT_UNKNOWN, 0))) - throw DxvkError("Failed to resize back buffers"); + Com backBuffer; + if (FAILED(m_swapChain->GetBuffer(0, IID_PPV_ARGS(&backBuffer)))) { + std::cerr << "Failed to get swap chain back buffer" << std::endl; + return false; + } - if (FAILED(m_swapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), reinterpret_cast(&m_buffer)))) - throw DxvkError("Failed to get swap chain back buffer"); + D3D11_RENDER_TARGET_VIEW_DESC rtvDesc; + rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D; + rtvDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM_SRGB; + rtvDesc.Texture2D = { 0u }; - if (FAILED(m_device->CreateRenderTargetView(m_buffer.ptr(), nullptr, &m_bufferView))) - throw DxvkError("Failed to create render target view"); - m_windowSize = newWindowSize; + if (FAILED(m_device->CreateRenderTargetView(backBuffer.ptr(), &rtvDesc, &m_rtv))) { + std::cerr << "Failed to create render target view" << std::endl; + return false; + } + + m_windowSizeW = newWindowSizeW; + m_windowSizeH = newWindowSizeH; } + + // Set up render state + FLOAT color[4] = { 0.5f, 0.5f, 0.5f, 1.0f }; + m_context->OMSetRenderTargets(1, &m_rtv, nullptr); + m_context->ClearRenderTargetView(m_rtv.ptr(), color); + + m_context->VSSetShader(m_vs.ptr(), nullptr, 0); + m_context->PSSetShader(m_ps.ptr(), nullptr, 0); + + m_context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); + m_context->IASetInputLayout(m_vertexFormat.ptr()); + + D3D11_VIEWPORT viewport; + viewport.TopLeftX = 0.0f; + viewport.TopLeftY = 0.0f; + viewport.Width = float(m_windowSizeW); + viewport.Height = float(m_windowSizeH); + viewport.MinDepth = 0.0f; + viewport.MaxDepth = 1.0f; + m_context->RSSetViewports(1, &viewport); + return true; } - + + + bool endFrame() { + HRESULT hr = m_swapChain->Present(0, DXGI_PRESENT_TEST); + + if (hr == S_OK) + hr = m_swapChain->Present(0, 0); + + m_occluded = hr == DXGI_STATUS_OCCLUDED; + return true; + } + + void updateFps() { + if (!m_qpcFrequency.QuadPart) + QueryPerformanceFrequency(&m_qpcFrequency); + + if (!m_qpcLastUpdate.QuadPart) + QueryPerformanceCounter(&m_qpcLastUpdate); + + LARGE_INTEGER now; + QueryPerformanceCounter(&now); + + m_frameCount++; + + if (now.QuadPart - m_qpcLastUpdate.QuadPart < m_qpcFrequency.QuadPart) + return; + + double seconds = double(now.QuadPart - m_qpcLastUpdate.QuadPart) / double(m_qpcFrequency.QuadPart); + double fps = double(m_frameCount) / seconds; + + std::wstringstream str; + str << L"D3D11 triangle (" << fps << L" FPS)"; + + SetWindowTextW(m_window, str.str().c_str()); + + m_qpcLastUpdate = now; + m_frameCount = 0; + } + + bool isOccluded() { + return m_swapChain->Present(0, DXGI_PRESENT_TEST) == DXGI_STATUS_OCCLUDED; + } + private: HWND m_window; - Extent2D m_windowSize = { 1024, 600 }; + uint32_t m_windowSizeW = 1024; + uint32_t m_windowSizeH = 600; + bool m_initialized = false; + bool m_occluded = false; - Com m_factory; + Com m_factory; Com m_adapter; - Com m_device; - Com m_context; - Com m_swapChain; - - Com m_buffer; - Com m_bufferView; - Com m_resourceBuffer; - Com m_resourceView; - Com m_indexBuffer; - Com m_vertexBuffer; + Com m_device; + Com m_context; + Com m_swapChain; + + Com m_rtv; + Com m_ibo; + Com m_vbo; Com m_vertexFormat; + + Com m_tex0; + Com m_tex1; + Com m_srv0; + Com m_srv1; - Com m_vertexShader; - Com m_hullShader; - Com m_domainShader; - Com m_pixelShader; - - Com m_query; - - D3D_FEATURE_LEVEL m_featureLevel; - - uint32_t m_frameId = 0; + Com m_cbPs; + Com m_cbVs; + + Com m_vs; + Com m_ps; + + LARGE_INTEGER m_qpcLastUpdate = { }; + LARGE_INTEGER m_qpcFrequency = { }; + + uint32_t m_frameCount = 0; }; @@ -495,69 +559,48 @@ LRESULT CALLBACK WindowProc(HWND hWnd, WPARAM wParam, LPARAM lParam); -int WINAPI WinMain(HINSTANCE hInstance, - HINSTANCE hPrevInstance, - LPSTR lpCmdLine, - int nCmdShow) { - HWND hWnd; - WNDCLASSEXW wc; - ZeroMemory(&wc, sizeof(WNDCLASSEX)); - wc.cbSize = sizeof(WNDCLASSEX); +int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { + WNDCLASSEXW wc = { }; + wc.cbSize = sizeof(wc); wc.style = CS_HREDRAW | CS_VREDRAW; wc.lpfnWndProc = WindowProc; wc.hInstance = hInstance; wc.hCursor = LoadCursor(nullptr, IDC_ARROW); - wc.hbrBackground = (HBRUSH)COLOR_WINDOW; - wc.lpszClassName = L"WindowClass1"; + wc.hbrBackground = HBRUSH(COLOR_WINDOW); + wc.lpszClassName = L"WindowClass"; RegisterClassExW(&wc); - hWnd = CreateWindowExW(0, - L"WindowClass1", - L"Our First Windowed Program", - WS_OVERLAPPEDWINDOW, - 300, 300, - 640, 480, - nullptr, - nullptr, - hInstance, - nullptr); + HWND hWnd = CreateWindowExW(0, L"WindowClass", L"D3D11 triangle", + WS_OVERLAPPEDWINDOW, 300, 300, 1024, 600, + nullptr, nullptr, hInstance, nullptr); ShowWindow(hWnd, nCmdShow); + TriangleApp app(hInstance, hWnd); + MSG msg; - - try { - TriangleApp app(hInstance, hWnd); - - while (true) { - if (PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE)) { - TranslateMessage(&msg); - DispatchMessage(&msg); - - if (msg.message == WM_QUIT) - return msg.wParam; - } else { - app.run(); - } + + while (true) { + if (PeekMessageW(&msg, nullptr, 0, 0, PM_REMOVE)) { + TranslateMessage(&msg); + DispatchMessageW(&msg); + + if (msg.message == WM_QUIT) + return msg.wParam; + } else { + if (!app.run()) + break; } - } catch (const dxvk::DxvkError& e) { - std::cerr << e.message() << std::endl; - return msg.wParam; } + + return msg.wParam; } LRESULT CALLBACK WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { - if (m_report) { - std::cout << "hwnd: " << hWnd << std::endl; - std::cout << "msg: " << message << std::endl; - std::cout << "wp: " << wParam << std::endl; - std::cout << "lp: " << lParam << std::endl; - } - switch (message) { case WM_CLOSE: PostQuitMessage(0); return 0; } - return DefWindowProc(hWnd, message, wParam, lParam); + return DefWindowProcW(hWnd, message, wParam, lParam); }