1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
|
#pragma once
#include "../renderer-shared.h"
#include "core/slang-basic.h"
#include "d3d-util.h"
#include "slang-gfx.h"
#include <dxgi1_4.h>
namespace gfx
{
class D3DSwapchainBase : public ISwapchain, public Slang::ComObject
{
public:
SLANG_COM_OBJECT_IUNKNOWN_ALL
ISwapchain* getInterface(const Slang::Guid& guid)
{
if (guid == GfxGUID::IID_ISlangUnknown || guid == GfxGUID::IID_ISwapchain)
return static_cast<ISwapchain*>(this);
return nullptr;
}
public:
Result init(const ISwapchain::Desc& desc, WindowHandle window, DXGI_SWAP_EFFECT swapEffect)
{
// Return fail on non-supported platforms.
switch (window.type)
{
case WindowHandle::Type::Win32Handle:
break;
default:
return SLANG_FAIL;
}
m_desc = desc;
m_desc.format = srgbToLinearFormat(m_desc.format);
// Describe the swap chain.
DXGI_SWAP_CHAIN_DESC swapChainDesc = {};
swapChainDesc.BufferCount = desc.imageCount;
swapChainDesc.BufferDesc.Width = desc.width;
swapChainDesc.BufferDesc.Height = desc.height;
swapChainDesc.BufferDesc.Format = D3DUtil::getMapFormat(m_desc.format);
swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
swapChainDesc.SwapEffect = swapEffect;
swapChainDesc.OutputWindow = (HWND)window.handleValues[0];
swapChainDesc.SampleDesc.Count = 1;
swapChainDesc.Windowed = TRUE;
if (!desc.enableVSync)
{
swapChainDesc.Flags |= DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT;
}
// Swap chain needs the queue so that it can force a flush on it.
ComPtr<IDXGIFactory2> dxgiFactory2;
getDXGIFactory()->QueryInterface(IID_PPV_ARGS(dxgiFactory2.writeRef()));
if (!dxgiFactory2)
{
ComPtr<IDXGISwapChain> swapChain;
SLANG_RETURN_ON_FAIL(getDXGIFactory()->CreateSwapChain(
getOwningDevice(),
&swapChainDesc,
swapChain.writeRef()));
SLANG_RETURN_ON_FAIL(getDXGIFactory()->MakeWindowAssociation(
(HWND)window.handleValues[0],
DXGI_MWA_NO_ALT_ENTER));
SLANG_RETURN_ON_FAIL(swapChain->QueryInterface(m_swapChain.writeRef()));
}
else
{
DXGI_SWAP_CHAIN_DESC1 desc1 = {};
desc1.BufferCount = swapChainDesc.BufferCount;
desc1.BufferUsage = swapChainDesc.BufferUsage;
desc1.Flags = swapChainDesc.Flags;
desc1.Format = swapChainDesc.BufferDesc.Format;
desc1.Height = swapChainDesc.BufferDesc.Height;
desc1.Width = swapChainDesc.BufferDesc.Width;
desc1.SampleDesc = swapChainDesc.SampleDesc;
desc1.SwapEffect = swapChainDesc.SwapEffect;
ComPtr<IDXGISwapChain1> swapChain1;
SLANG_RETURN_ON_FAIL(dxgiFactory2->CreateSwapChainForHwnd(
getOwningDevice(),
(HWND)window.handleValues[0],
&desc1,
nullptr,
nullptr,
swapChain1.writeRef()));
SLANG_RETURN_ON_FAIL(swapChain1->QueryInterface(m_swapChain.writeRef()));
}
createSwapchainBufferImages();
return SLANG_OK;
}
virtual SLANG_NO_THROW const Desc& SLANG_MCALL getDesc() override { return m_desc; }
virtual SLANG_NO_THROW Result SLANG_MCALL
getImage(GfxIndex index, ITextureResource** outResource) override
{
returnComPtr(outResource, m_images[index]);
return SLANG_OK;
}
virtual SLANG_NO_THROW Result SLANG_MCALL present() override
{
const auto res = m_swapChain->Present(m_desc.enableVSync ? 1 : 0, 0);
// We may want to wait for crash dump completion for some kinds of debugging scenarios
if (res == DXGI_ERROR_DEVICE_REMOVED || res == DXGI_ERROR_DEVICE_RESET)
{
D3DUtil::waitForCrashDumpCompletion(res);
}
if (SLANG_FAILED(res))
{
return SLANG_FAIL;
}
return SLANG_OK;
}
virtual SLANG_NO_THROW int SLANG_MCALL acquireNextImage() override
{
uint32_t count;
m_swapChain->GetLastPresentCount(&count);
return (int)(count % m_desc.imageCount);
}
virtual SLANG_NO_THROW Result SLANG_MCALL resize(GfxCount width, GfxCount height) override
{
if (width == m_desc.width && height == m_desc.height)
return SLANG_OK;
m_desc.width = width;
m_desc.height = height;
for (auto& image : m_images)
image = nullptr;
m_images.clear();
auto result = m_swapChain->ResizeBuffers(
m_desc.imageCount,
width,
height,
D3DUtil::getMapFormat(m_desc.format),
m_desc.enableVSync ? 0 : DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT);
if (result != 0)
return SLANG_FAIL;
createSwapchainBufferImages();
return SLANG_OK;
}
public:
virtual void createSwapchainBufferImages() = 0;
virtual IDXGIFactory* getDXGIFactory() = 0;
virtual IUnknown* getOwningDevice() = 0;
ISwapchain::Desc m_desc;
ComPtr<IDXGISwapChain2> m_swapChain;
Slang::ShortList<Slang::RefPtr<TextureResource>> m_images;
};
} // namespace gfx
|