diff --git a/util/test/demos/d3d11/d3d11_swapchain_zoo.cpp b/util/test/demos/d3d11/d3d11_swapchain_zoo.cpp new file mode 100644 index 000000000..4a07106c5 --- /dev/null +++ b/util/test/demos/d3d11/d3d11_swapchain_zoo.cpp @@ -0,0 +1,156 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2019-2020 Baldur Karlsson + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + +#include "../win32/win32_window.h" +#include "d3d11_test.h" + +RD_TEST(D3D11_Swapchain_Zoo, D3D11GraphicsTest) +{ + static constexpr const char *Description = "Tests all types of swapchain that D3D11 supports."; + + int main() + { + // initialise, create window, create device, etc + if(!Init()) + return 3; + + DXGI_SWAP_CHAIN_DESC swapDesc; + ZeroMemory(&swapDesc, sizeof(swapDesc)); + + swapDesc.BufferCount = backbufferCount; + swapDesc.BufferDesc.Width = screenWidth; + swapDesc.BufferDesc.Height = screenHeight; + swapDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT | DXGI_USAGE_SHADER_INPUT; + swapDesc.SampleDesc.Quality = 0; + swapDesc.Windowed = TRUE; + swapDesc.Flags = 0; + + std::vector wins; + std::vector swaps; + std::vector bbs; + std::vector names; + + auto addWindow = [&](std::string name) { + wins.push_back(new Win32Window(screenWidth, screenHeight, screenTitle)); + swaps.push_back({}); + bbs.push_back({}); + names.push_back(name); + swapDesc.OutputWindow = wins.back()->wnd; + fact->CreateSwapChain(dev, &swapDesc, &swaps.back()); + + ID3D11Texture2DPtr bb; + CHECK_HR(swaps.back()->GetBuffer(0, __uuidof(ID3D11Texture2D), (void **)&bb)); + + CHECK_HR(dev->CreateRenderTargetView(bb, NULL, &bbs.back())); + }; + + // always support sequential flip + swapDesc.SwapEffect = DXGI_SWAP_EFFECT_SEQUENTIAL; + swapDesc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; + swapDesc.SampleDesc.Count = 1; + addWindow("SEQUENTIAL"); + + // ditto MSAA + swapDesc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD; + swapDesc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; + swapDesc.SampleDesc.Count = 4; + addWindow("MSAA RGBA8"); + + // ditto FP16 (on feature level 10 and above) + swapDesc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD; + swapDesc.BufferDesc.Format = DXGI_FORMAT_R16G16B16A16_FLOAT; + swapDesc.SampleDesc.Count = 1; + addWindow("RGBA16"); + + // check FP16 and MSAA + swapDesc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD; + swapDesc.BufferDesc.Format = DXGI_FORMAT_R16G16B16A16_FLOAT; + swapDesc.SampleDesc.Count = 4; + addWindow("MSAA RGBA16"); + + IDXGIFactory4Ptr factory4 = fact; + if(factory4) + { + // only test flip effects if we can get factory4, which is windows 10 only. + + swapDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD; + swapDesc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; + swapDesc.SampleDesc.Count = 1; + addWindow("FLIP_DISCARD"); + + swapDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL; + swapDesc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; + swapDesc.SampleDesc.Count = 1; + addWindow("FLIP_SEQUENTIAL"); + } + + ID3DBlobPtr vsblob = Compile(D3DDefaultVertex, "main", "vs_4_0"); + ID3DBlobPtr psblob = Compile(D3DDefaultPixel, "main", "ps_4_0"); + + CreateDefaultInputLayout(vsblob); + + ID3D11VertexShaderPtr vs = CreateVS(vsblob); + ID3D11PixelShaderPtr ps = CreatePS(psblob); + + ID3D11BufferPtr vb = MakeBuffer().Vertex().Data(DefaultTri); + + while(Running()) + { + for(Win32Window *win : wins) + win->Update(); + + ClearRenderTargetView(bbRTV, {0.0f, 0.0f, 0.0f, 1.0f}); + + IASetVertexBuffer(vb, sizeof(DefaultA2V), 0); + ctx->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); + ctx->IASetInputLayout(defaultLayout); + + ctx->VSSetShader(vs, NULL, 0); + ctx->PSSetShader(ps, NULL, 0); + + RSSetViewport({0.0f, 0.0f, (float)screenWidth, (float)screenHeight, 0.0f, 1.0f}); + + ctx->OMSetRenderTargets(1, &bbRTV.GetInterfacePtr(), NULL); + + ctx->Draw(3, 0); + + for(size_t i = 0; i < bbs.size(); i++) + { + ID3D11RenderTargetViewPtr bb = bbs[i]; + setMarker(names[i]); + ctx->OMSetRenderTargets(1, &bb.GetInterfacePtr(), NULL); + ClearRenderTargetView(bb, {0.0f, 0.0f, 0.0f, 1.0f}); + ctx->Draw(3, 0); + } + + Present(); + for(IDXGISwapChainPtr s : swaps) + s->Present(0, 0); + } + + return 0; + } +}; + +REGISTER_TEST(); diff --git a/util/test/demos/d3d11/d3d11_test.cpp b/util/test/demos/d3d11/d3d11_test.cpp index fdc8fb5b6..a2c501018 100644 --- a/util/test/demos/d3d11/d3d11_test.cpp +++ b/util/test/demos/d3d11/d3d11_test.cpp @@ -37,7 +37,7 @@ namespace HMODULE d3d11 = NULL; HMODULE dxgi = NULL; HMODULE d3dcompiler = NULL; -IDXGIFactoryPtr factory; +IDXGIFactory1Ptr factory; std::vector adapters; bool warp = false; @@ -74,7 +74,9 @@ void D3D11GraphicsTest::Prepare(int argc, char **argv) PFN_CREATE_DXGI_FACTORY createFactory = NULL; if(dxgi) - createFactory = (PFN_CREATE_DXGI_FACTORY)GetProcAddress(dxgi, "CreateDXGIFactory"); + { + createFactory = (PFN_CREATE_DXGI_FACTORY)GetProcAddress(dxgi, "CreateDXGIFactory1"); + } if(d3d11 && d3dcompiler) { @@ -91,7 +93,7 @@ void D3D11GraphicsTest::Prepare(int argc, char **argv) if(createFactory) { - hr = createFactory(__uuidof(IDXGIFactory), (void **)&factory); + hr = createFactory(__uuidof(IDXGIFactory1), (void **)&factory); if(SUCCEEDED(hr)) adapters = FindD3DAdapters(factory, argc, argv, warp); @@ -314,6 +316,8 @@ void D3D11GraphicsTest::PostDeviceCreate() ctx3 = ctx; ctx4 = ctx; + fact = factory; + annot = ctx; std::string blitPixel = R"EOSHADER( diff --git a/util/test/demos/d3d11/d3d11_test.h b/util/test/demos/d3d11/d3d11_test.h index 9099f4320..6f1578516 100644 --- a/util/test/demos/d3d11/d3d11_test.h +++ b/util/test/demos/d3d11/d3d11_test.h @@ -181,6 +181,7 @@ struct D3D11GraphicsTest : public GraphicsTest GraphicsWindow *mainWindow = NULL; + IDXGIFactory1Ptr fact; IDXGISwapChainPtr swap; ID3D11InputLayoutPtr defaultLayout; diff --git a/util/test/demos/d3d12/d3d12_swapchain_zoo.cpp b/util/test/demos/d3d12/d3d12_swapchain_zoo.cpp new file mode 100644 index 000000000..25b97a744 --- /dev/null +++ b/util/test/demos/d3d12/d3d12_swapchain_zoo.cpp @@ -0,0 +1,147 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2019-2020 Baldur Karlsson + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + +#include "../win32/win32_window.h" +#include "d3d12_test.h" + +RD_TEST(D3D12_Swapchain_Zoo, D3D12GraphicsTest) +{ + static constexpr const char *Description = "Tests both types of swapchain that D3D12 supports."; + + void Prepare(int argc, char **argv) + { + D3D12GraphicsTest::Prepare(argc, argv); + + if(m_12On7) + Avail = "True swapchains not supportedd on D3D12On7"; + } + + int main() + { + // initialise, create window, create device, etc + if(!Init()) + return 3; + + IDXGIFactory4Ptr factory4 = m_Factory; + + DXGI_SWAP_CHAIN_DESC1 swapDesc = {}; + + swapDesc.BufferCount = 2; + swapDesc.AlphaMode = DXGI_ALPHA_MODE_IGNORE; + swapDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT | DXGI_USAGE_SHADER_INPUT; + swapDesc.Flags = 0; + swapDesc.Format = backbufferFmt; + swapDesc.Width = screenWidth; + swapDesc.Height = screenHeight; + swapDesc.SampleDesc.Count = 1; + swapDesc.SampleDesc.Quality = 0; + swapDesc.Scaling = DXGI_SCALING_STRETCH; + swapDesc.Stereo = FALSE; + swapDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL; + + // make second window + Win32Window *window2 = new Win32Window(screenWidth, screenHeight, screenTitle); + IDXGISwapChain1Ptr window2Swap; + + // make sequential swapchain with normal format + swapDesc.Format = backbufferFmt; + swapDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL; + CHECK_HR( + factory4->CreateSwapChainForHwnd(queue, window2->wnd, &swapDesc, NULL, NULL, &window2Swap)); + + ID3D12ResourcePtr window2Tex[2]; + + CHECK_HR(window2Swap->GetBuffer(0, __uuidof(ID3D12Resource), (void **)&window2Tex[0])); + CHECK_HR(window2Swap->GetBuffer(1, __uuidof(ID3D12Resource), (void **)&window2Tex[1])); + + ID3DBlobPtr vsblob = Compile(D3DDefaultVertex, "main", "vs_4_0"); + ID3DBlobPtr psblob = Compile(D3DDefaultPixel, "main", "ps_4_0"); + + ID3D12ResourcePtr vb = MakeBuffer().Data(DefaultTri); + + ID3D12RootSignaturePtr sig = MakeSig({}); + + ID3D12PipelineStatePtr pso = MakePSO().RootSig(sig).InputLayout().VS(vsblob).PS(psblob); + + ResourceBarrier(vb, D3D12_RESOURCE_STATE_COMMON, D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER); + + while(Running()) + { + window2->Update(); + + D3D12_CPU_DESCRIPTOR_HANDLE rtv; + ID3D12GraphicsCommandListPtr cmd = GetCommandBuffer(); + + Reset(cmd); + + ResourceBarrier(cmd, window2Tex[texIdx], D3D12_RESOURCE_STATE_PRESENT, + D3D12_RESOURCE_STATE_RENDER_TARGET); + + ID3D12ResourcePtr bb = StartUsingBackbuffer(cmd, D3D12_RESOURCE_STATE_RENDER_TARGET); + + rtv = MakeRTV(bb).Format(DXGI_FORMAT_R8G8B8A8_UNORM_SRGB).CreateCPU(0); + + ClearRenderTargetView(cmd, rtv, {0.0f, 0.0f, 0.0f, 1.0f}); + + cmd->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST); + + IASetVertexBuffer(cmd, vb, sizeof(DefaultA2V), 0); + cmd->SetPipelineState(pso); + cmd->SetGraphicsRootSignature(sig); + + RSSetViewport(cmd, {0.0f, 0.0f, (float)screenWidth, (float)screenHeight, 0.0f, 1.0f}); + RSSetScissorRect(cmd, {0, 0, screenWidth, screenHeight}); + + OMSetRenderTargets(cmd, {rtv}, {}); + setMarker(cmd, "Draw 1"); + cmd->DrawInstanced(3, 1, 0, 0); + + rtv = MakeRTV(window2Tex[texIdx]).Format(DXGI_FORMAT_R8G8B8A8_UNORM_SRGB).CreateCPU(0); + + ClearRenderTargetView(cmd, rtv, {0.0f, 0.0f, 0.0f, 1.0f}); + + OMSetRenderTargets(cmd, {rtv}, {}); + setMarker(cmd, "Draw 2"); + cmd->DrawInstanced(3, 1, 0, 0); + + ResourceBarrier(cmd, window2Tex[texIdx], D3D12_RESOURCE_STATE_RENDER_TARGET, + D3D12_RESOURCE_STATE_PRESENT); + + FinishUsingBackbuffer(cmd, D3D12_RESOURCE_STATE_RENDER_TARGET); + + cmd->Close(); + + Submit({cmd}); + + Present(); + window2Swap->Present(0, 0); + } + + delete window2; + + return 0; + } +}; + +REGISTER_TEST(); diff --git a/util/test/demos/demos.vcxproj b/util/test/demos/demos.vcxproj index ab7cb2599..84b812963 100644 --- a/util/test/demos/demos.vcxproj +++ b/util/test/demos/demos.vcxproj @@ -164,6 +164,7 @@ + @@ -195,6 +196,7 @@ + diff --git a/util/test/demos/demos.vcxproj.filters b/util/test/demos/demos.vcxproj.filters index d6aeb1fae..4b4cb5c84 100644 --- a/util/test/demos/demos.vcxproj.filters +++ b/util/test/demos/demos.vcxproj.filters @@ -544,6 +544,12 @@ Vulkan\demos + + D3D12\demos + + + D3D11\demos + diff --git a/util/test/demos/dx/d3d_helpers.h b/util/test/demos/dx/d3d_helpers.h index 511606e60..036f8bbe9 100644 --- a/util/test/demos/dx/d3d_helpers.h +++ b/util/test/demos/dx/d3d_helpers.h @@ -37,6 +37,8 @@ extern std::string D3DDefaultPixel; COM_SMARTPTR(IDXGISwapChain); COM_SMARTPTR(IDXGISwapChain1); +COM_SMARTPTR(IDXGISwapChain2); +COM_SMARTPTR(IDXGISwapChain3); COM_SMARTPTR(IDXGIFactory); COM_SMARTPTR(IDXGIFactory1); COM_SMARTPTR(IDXGIFactory4); diff --git a/util/test/rdtest/capture.py b/util/test/rdtest/capture.py index 02909053e..f5b8a58e1 100644 --- a/util/test/rdtest/capture.py +++ b/util/test/rdtest/capture.py @@ -150,7 +150,7 @@ def run_executable(exe: str, cmdline: str, return res.ident -def run_and_capture(exe: str, cmdline: str, frame: int, *, capture_name=None, opts=rd.GetDefaultCaptureOptions(), +def run_and_capture(exe: str, cmdline: str, frame: int, *, frame_count=1, capture_name=None, opts=rd.GetDefaultCaptureOptions(), timeout=None, logfile=None): """ Helper function to run an executable with a command line, capture a particular frame, and exit. @@ -161,6 +161,7 @@ def run_and_capture(exe: str, cmdline: str, frame: int, *, capture_name=None, op :param exe: The executable to run. :param cmdline: The command line to pass. :param frame: The frame to capture. + :param frame_count: The number of frames to capture. :param capture_name: The name to use creating the captures :param opts: The capture options to use :param timeout: The timeout to wait before killing the process if no capture has happened. @@ -174,10 +175,10 @@ def run_and_capture(exe: str, cmdline: str, frame: int, *, capture_name=None, op control = TargetControl(run_executable(exe, cmdline, cappath=util.get_tmp_path(capture_name), opts=opts), timeout=timeout) - log.print("Queuing capture of frame {} with timeout of {}".format(frame, "default" if timeout is None else timeout)) + log.print("Queuing capture of frame {}..{} with timeout of {}".format(frame, frame+frame_count, "default" if timeout is None else timeout)) # Capture frame - control.queue_capture(frame) + control.queue_capture(frame, frame_count) # By default, runs until the first capture is made control.run() diff --git a/util/test/rdtest/testcase.py b/util/test/rdtest/testcase.py index 9bb01b40c..dc6d70c18 100644 --- a/util/test/rdtest/testcase.py +++ b/util/test/rdtest/testcase.py @@ -134,6 +134,7 @@ class TestCase: internal = False demos_test_name = '' demos_frame_cap = 5 + demos_frame_count = 1 _test_list = {} @staticmethod @@ -203,8 +204,8 @@ class TestCase: if self.demos_test_name != '': logfile = os.path.join(util.get_tmp_dir(), 'demos.log') return capture.run_and_capture(util.get_demos_binary(), self.demos_test_name + " --log " + logfile, - self.demos_frame_cap, logfile=logfile, opts=self.get_capture_options(), - timeout=util.get_demos_timeout()) + self.demos_frame_cap, frame_count=self.demos_frame_count, logfile=logfile, + opts=self.get_capture_options(), timeout=util.get_demos_timeout()) raise NotImplementedError("If run() is not implemented in a test, then" "get_capture() and check_capture() must be.") diff --git a/util/test/tests/D3D11/D3D11_Swapchain_Zoo.py b/util/test/tests/D3D11/D3D11_Swapchain_Zoo.py new file mode 100644 index 000000000..55020e2bb --- /dev/null +++ b/util/test/tests/D3D11/D3D11_Swapchain_Zoo.py @@ -0,0 +1,20 @@ +import renderdoc as rd +import rdtest + + +class D3D11_Swapchain_Zoo(rdtest.TestCase): + demos_test_name = 'D3D11_Swapchain_Zoo' + demos_frame_cap = 50 + demos_frame_count = 10 + + def check_capture(self): + draw = self.find_draw("DrawIndexed") + + while draw is not None: + self.controller.SetFrameEvent(draw.eventId, False) + + self.check_triangle(back=[0.0, 0.0, 0.0, 1.0]) + + rdtest.log.success("OK at {}".format(draw.previous.name)) + + draw = self.find_draw("DrawIndexed", draw.eventId+1) \ No newline at end of file diff --git a/util/test/tests/D3D12/D3D12_Swapchain_Zoo.py b/util/test/tests/D3D12/D3D12_Swapchain_Zoo.py new file mode 100644 index 000000000..fd7993ecc --- /dev/null +++ b/util/test/tests/D3D12/D3D12_Swapchain_Zoo.py @@ -0,0 +1,22 @@ +import renderdoc as rd +import rdtest + + +class D3D12_Swapchain_Zoo(rdtest.TestCase): + demos_test_name = 'D3D12_Swapchain_Zoo' + + def check_capture(self): + draw1 = self.find_draw("Draw 1") + draw2 = self.find_draw("Draw 2") + + self.controller.SetFrameEvent(draw1.next.eventId, False) + + self.check_triangle(back=[0.0, 0.0, 0.0, 1.0]) + + rdtest.log.success("Triangle in first draw (on first window) is OK") + + self.controller.SetFrameEvent(draw2.next.eventId, False) + + self.check_triangle(back=[0.0, 0.0, 0.0, 1.0]) + + rdtest.log.success("Triangle in second draw (on second window) is OK") \ No newline at end of file