Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
hrydgard
GitHub Repository: hrydgard/ppsspp
Path: blob/master/Common/GPU/D3D11/thin3d_d3d11.cpp
5695 views
1
#include "ppsspp_config.h"
2
3
#include "Common/GPU/thin3d.h"
4
#if PPSSPP_PLATFORM(UWP)
5
#define ptr_D3DCompile D3DCompile
6
#else
7
#include "Common/GPU/D3D11/D3D11Loader.h"
8
#endif
9
#include "Common/System/Display.h"
10
11
#include "Common/Data/Convert/ColorConv.h"
12
#include "Common/Data/Convert/SmallDataConvert.h"
13
#include "Common/Data/Encoding/Utf8.h"
14
#include "Common/TimeUtil.h"
15
#include "Common/Log.h"
16
17
#include <map>
18
19
#include <cfloat>
20
#include <D3Dcommon.h>
21
#ifndef __LIBRETRO__ // their build server uses an old SDK
22
#include <dxgi1_5.h>
23
#endif
24
#include <d3d11.h>
25
#include <d3d11_1.h>
26
#include <D3Dcompiler.h>
27
#include <wrl/client.h>
28
29
using namespace Microsoft::WRL;
30
31
namespace Draw {
32
33
static constexpr int MAX_BOUND_TEXTURES = 8;
34
35
// A problem is that we can't get the D3Dcompiler.dll without using a later SDK than 7.1, which was the last that
36
// supported XP. A possible solution might be here:
37
// https://tedwvc.wordpress.com/2014/01/01/how-to-target-xp-with-vc2012-or-vc2013-and-continue-to-use-the-windows-8-x-sdk/
38
39
class D3D11Pipeline;
40
class D3D11BlendState;
41
class D3D11DepthStencilState;
42
class D3D11SamplerState;
43
class D3D11Buffer;
44
class D3D11RasterState;
45
46
// This must stay POD for the memcmp to work reliably.
47
struct D3D11DepthStencilKey {
48
DepthStencilStateDesc desc;
49
u8 writeMask;
50
u8 compareMask;
51
52
bool operator < (const D3D11DepthStencilKey &other) const {
53
return memcmp(this, &other, sizeof(D3D11DepthStencilKey)) < 0;
54
}
55
};
56
57
class D3D11DepthStencilState : public DepthStencilState {
58
public:
59
~D3D11DepthStencilState() = default;
60
DepthStencilStateDesc desc;
61
};
62
63
// A D3D11Framebuffer is a D3D11Framebuffer plus all the textures it owns.
64
class D3D11Framebuffer : public Framebuffer {
65
public:
66
D3D11Framebuffer(int width, int height) {
67
width_ = width;
68
height_ = height;
69
}
70
~D3D11Framebuffer() {
71
}
72
73
ComPtr<ID3D11Texture2D> colorTex;
74
ComPtr<ID3D11RenderTargetView> colorRTView;
75
ComPtr<ID3D11ShaderResourceView> colorSRView;
76
ComPtr<ID3D11ShaderResourceView> depthSRView;
77
ComPtr<ID3D11ShaderResourceView> stencilSRView;
78
DXGI_FORMAT colorFormat = DXGI_FORMAT_UNKNOWN;
79
80
ComPtr<ID3D11Texture2D> depthStencilTex;
81
ComPtr<ID3D11DepthStencilView> depthStencilRTView;
82
DXGI_FORMAT depthStencilFormat = DXGI_FORMAT_UNKNOWN;
83
};
84
85
class D3D11DrawContext : public DrawContext {
86
public:
87
D3D11DrawContext(ComPtr<ID3D11Device> device, ComPtr<ID3D11DeviceContext> deviceContext, ComPtr<ID3D11Device1> device1, ComPtr<ID3D11DeviceContext1> deviceContext1, ComPtr<IDXGISwapChain> swapChain, D3D_FEATURE_LEVEL featureLevel, HWND hWnd, std::vector<std::string> deviceList, int maxInflightFrames);
88
~D3D11DrawContext();
89
90
const DeviceCaps &GetDeviceCaps() const override {
91
return caps_;
92
}
93
std::vector<std::string> GetDeviceList() const override {
94
return deviceList_;
95
}
96
uint32_t GetSupportedShaderLanguages() const override {
97
return (uint32_t)ShaderLanguage::HLSL_D3D11;
98
}
99
uint32_t GetDataFormatSupport(DataFormat fmt) const override;
100
101
InputLayout *CreateInputLayout(const InputLayoutDesc &desc) override;
102
DepthStencilState *CreateDepthStencilState(const DepthStencilStateDesc &desc) override;
103
BlendState *CreateBlendState(const BlendStateDesc &desc) override;
104
SamplerState *CreateSamplerState(const SamplerStateDesc &desc) override;
105
RasterState *CreateRasterState(const RasterStateDesc &desc) override;
106
Buffer *CreateBuffer(size_t size, uint32_t usageFlags) override;
107
Pipeline *CreateGraphicsPipeline(const PipelineDesc &desc, const char *tag) override;
108
Texture *CreateTexture(const TextureDesc &desc) override;
109
ShaderModule *CreateShaderModule(ShaderStage stage, ShaderLanguage language, const uint8_t *data, size_t dataSize, const char *tag) override;
110
Framebuffer *CreateFramebuffer(const FramebufferDesc &desc) override;
111
112
void UpdateBuffer(Buffer *buffer, const uint8_t *data, size_t offset, size_t size, UpdateBufferFlags flags) override;
113
void UpdateTextureLevels(Texture *texture, const uint8_t **data, TextureCallback initDataCallback, int numLevels) override;
114
115
void CopyFramebufferImage(Framebuffer *src, int level, int x, int y, int z, Framebuffer *dst, int dstLevel, int dstX, int dstY, int dstZ, int width, int height, int depth, Aspect aspects, const char *tag) override;
116
bool BlitFramebuffer(Framebuffer *src, int srcX1, int srcY1, int srcX2, int srcY2, Framebuffer *dst, int dstX1, int dstY1, int dstX2, int dstY2, Aspect aspects, FBBlitFilter filter, const char *tag) override;
117
bool CopyFramebufferToMemory(Framebuffer *src, Aspect channelBits, int x, int y, int w, int h, Draw::DataFormat format, void *pixels, int pixelStride, ReadbackMode mode, const char *tag) override;
118
119
// These functions should be self explanatory.
120
void BindFramebufferAsRenderTarget(Framebuffer *fbo, const RenderPassInfo &rp, const char *tag) override;
121
void BindFramebufferAsTexture(Framebuffer *fbo, int binding, Aspect channelBit, int layer) override;
122
123
void GetFramebufferDimensions(Framebuffer *fbo, int *w, int *h) override;
124
125
void Invalidate(InvalidationFlags flags) override;
126
127
void BindTextures(int start, int count, Texture **textures, TextureBindFlags flags) override;
128
void BindNativeTexture(int index, void *nativeTexture) override;
129
void BindSamplerStates(int start, int count, SamplerState **states) override;
130
void BindVertexBuffer(Buffer *buffers, int offset) override;
131
void BindIndexBuffer(Buffer *indexBuffer, int offset) override;
132
void BindPipeline(Pipeline *pipeline) override;
133
134
void UpdateDynamicUniformBuffer(const void *ub, size_t size) override;
135
136
// Raster state
137
void SetScissorRect(int left, int top, int width, int height) override;
138
void SetViewport(const Viewport &viewport) override;
139
void SetBlendFactor(float color[4]) override {
140
if (0 != memcmp(blendFactor_, color, sizeof(float) * 4)) {
141
memcpy(blendFactor_, color, sizeof(float) * 4);
142
blendFactorDirty_ = true;
143
}
144
}
145
void SetStencilParams(uint8_t refValue, uint8_t writeMask, uint8_t compareMask) override {
146
stencilRef_ = refValue;
147
stencilWriteMask_ = writeMask;
148
stencilCompareMask_ = compareMask;
149
stencilDirty_ = true;
150
}
151
152
153
void Draw(int vertexCount, int offset) override;
154
void DrawIndexed(int indexCount, int offset) override;
155
void DrawUP(const void *vdata, int vertexCount) override;
156
void DrawIndexedUP(const void *vdata, int vertexCount, const void *idata, int indexCount) override;
157
void DrawIndexedClippedBatchUP(const void *vdata, int vertexCount, const void *idata, int indexCount, Slice<ClippedDraw> draws, const void *ub, size_t ubSize) override;
158
159
void Clear(Aspect mask, uint32_t colorval, float depthVal, int stencilVal) override;
160
161
void BeginFrame(DebugFlags debugFlags) override;
162
void EndFrame() override;
163
void Present(PresentMode presentMode) override;
164
PresentMode GetCurrentPresentMode() const override {
165
if (currentInterval_ == 1) {
166
return PresentMode::FIFO;
167
} else {
168
return PresentMode::IMMEDIATE;
169
}
170
}
171
172
int GetFrameCount() override { return frameCount_; }
173
174
std::string GetInfoString(InfoField info) const override {
175
switch (info) {
176
case InfoField::APIVERSION: return "Direct3D 11";
177
case InfoField::VENDORSTRING: return adapterDesc_;
178
case InfoField::VENDOR: return "";
179
case InfoField::DRIVER: return "-";
180
case InfoField::SHADELANGVERSION:
181
switch (featureLevel_) {
182
case D3D_FEATURE_LEVEL_9_1: return "Feature Level 9.1";
183
case D3D_FEATURE_LEVEL_9_2: return "Feature Level 9.2";
184
case D3D_FEATURE_LEVEL_9_3: return "Feature Level 9.3";
185
case D3D_FEATURE_LEVEL_10_0: return "Feature Level 10.0";
186
case D3D_FEATURE_LEVEL_10_1: return "Feature Level 10.1";
187
case D3D_FEATURE_LEVEL_11_0: return "Feature Level 11.0";
188
case D3D_FEATURE_LEVEL_11_1: return "Feature Level 11.1";
189
case D3D_FEATURE_LEVEL_12_0: return "Feature Level 12.0";
190
case D3D_FEATURE_LEVEL_12_1: return "Feature Level 12.1";
191
#ifndef __LIBRETRO__
192
case D3D_FEATURE_LEVEL_1_0_CORE: return "Feature Level 1.0 Core"; // This is for compute-only devices. Useless for us.
193
case D3D_FEATURE_LEVEL_12_2: return "Feature Level 12.2";
194
#endif
195
default: return "Feature Level X.X";
196
}
197
return "Unknown feature level";
198
case InfoField::APINAME: return "Direct3D 11";
199
default: return "?";
200
}
201
}
202
203
uint64_t GetNativeObject(NativeObject obj, void *srcObject) override;
204
205
void HandleEvent(Event ev, int width, int height, void *param1, void *param2) override;
206
207
void SetInvalidationCallback(InvalidationCallback callback) override {
208
invalidationCallback_ = callback;
209
}
210
211
private:
212
void ApplyCurrentState();
213
214
HRESULT GetCachedDepthStencilState(const D3D11DepthStencilState *state, uint8_t stencilWriteMask, uint8_t stencilCompareMask, ID3D11DepthStencilState **);
215
216
HWND hWnd_;
217
ComPtr<ID3D11Device> device_;
218
ComPtr<ID3D11Device1> device1_;
219
ComPtr<ID3D11DeviceContext> context_;
220
ComPtr<ID3D11DeviceContext1> context1_;
221
ComPtr<IDXGISwapChain> swapChain_;
222
bool swapChainTearingSupported_ = false;
223
224
ID3D11Texture2D *bbRenderTargetTex_ = nullptr; // NOT OWNED
225
ID3D11RenderTargetView *bbRenderTargetView_ = nullptr ; // NOT OWNED
226
// Strictly speaking we don't need a depth buffer for the backbuffer.
227
ComPtr<ID3D11Texture2D> bbDepthStencilTex_;
228
ComPtr<ID3D11DepthStencilView> bbDepthStencilView_;
229
230
AutoRef<Framebuffer> curRenderTarget_;
231
ComPtr<ID3D11RenderTargetView> curRenderTargetView_;
232
ComPtr<ID3D11DepthStencilView> curDepthStencilView_;
233
// Needed to rotate stencil/viewport rectangles properly
234
int bbWidth_ = 0;
235
int bbHeight_ = 0;
236
int curRTWidth_ = 0;
237
int curRTHeight_ = 0;
238
239
AutoRef<D3D11Pipeline> curPipeline_;
240
DeviceCaps caps_{};
241
242
AutoRef<D3D11BlendState> curBlend_;
243
AutoRef<D3D11DepthStencilState> curDepthStencil_;
244
AutoRef<D3D11RasterState> curRaster_;
245
246
std::map<D3D11DepthStencilKey, ComPtr<ID3D11DepthStencilState>> depthStencilCache_;
247
248
ComPtr<ID3D11InputLayout> curInputLayout_;
249
ComPtr<ID3D11VertexShader> curVS_;
250
ComPtr<ID3D11PixelShader> curPS_;
251
ComPtr<ID3D11GeometryShader> curGS_;
252
D3D11_PRIMITIVE_TOPOLOGY curTopology_ = D3D11_PRIMITIVE_TOPOLOGY_UNDEFINED;
253
254
ComPtr<ID3D11Buffer> nextVertexBuffer_;
255
UINT nextVertexBufferOffset_ = 0;
256
257
bool dirtyIndexBuffer_ = false;
258
ComPtr<ID3D11Buffer> nextIndexBuffer_;
259
UINT nextIndexBufferOffset_ = 0;
260
261
InvalidationCallback invalidationCallback_;
262
int frameCount_ = FRAME_TIME_HISTORY_LENGTH;
263
264
// Dynamic state
265
float blendFactor_[4]{};
266
bool blendFactorDirty_ = false;
267
uint8_t stencilRef_ = 0;
268
uint8_t stencilWriteMask_ = 0xFF;
269
uint8_t stencilCompareMask_ = 0xFF;
270
271
bool stencilDirty_ = true;
272
273
// Temporaries
274
ComPtr<ID3D11Texture2D> packTexture_;
275
Buffer *upBuffer_ = nullptr;
276
Buffer *upIBuffer_ = nullptr;
277
278
// System info
279
D3D_FEATURE_LEVEL featureLevel_;
280
std::string adapterDesc_;
281
std::vector<std::string> deviceList_;
282
283
int currentInterval_ = -1;
284
};
285
286
D3D11DrawContext::D3D11DrawContext(ComPtr<ID3D11Device> device, ComPtr<ID3D11DeviceContext> deviceContext, ComPtr<ID3D11Device1> device1, ComPtr<ID3D11DeviceContext1> deviceContext1, ComPtr<IDXGISwapChain> swapChain, D3D_FEATURE_LEVEL featureLevel, HWND hWnd, std::vector<std::string> deviceList, int maxInflightFrames)
287
: hWnd_(hWnd),
288
device_(device),
289
context_(deviceContext1),
290
device1_(device1),
291
context1_(deviceContext1),
292
featureLevel_(featureLevel),
293
swapChain_(swapChain),
294
deviceList_(std::move(deviceList)) {
295
296
// We no longer support Windows Phone.
297
_assert_(featureLevel_ >= D3D_FEATURE_LEVEL_9_3);
298
299
caps_.coordConvention = CoordConvention::Direct3D11;
300
301
switch (featureLevel_) {
302
case D3D_FEATURE_LEVEL_11_1:
303
case D3D_FEATURE_LEVEL_11_0:
304
caps_.maxTextureSize = 16384;
305
break;
306
case D3D_FEATURE_LEVEL_10_1:
307
case D3D_FEATURE_LEVEL_10_0:
308
caps_.maxTextureSize = 8192;
309
break;
310
case D3D_FEATURE_LEVEL_9_3:
311
caps_.maxTextureSize = 4096;
312
break;
313
case D3D_FEATURE_LEVEL_9_2:
314
case D3D_FEATURE_LEVEL_9_1:
315
default:
316
caps_.maxTextureSize = 2048;
317
break;
318
}
319
caps_.maxClipPlanes = 8;
320
321
// Seems like a fair approximation...
322
caps_.dualSourceBlend = featureLevel_ >= D3D_FEATURE_LEVEL_10_0;
323
caps_.depthClampSupported = featureLevel_ >= D3D_FEATURE_LEVEL_10_0;
324
// SV_ClipDistance# seems to be 10+.
325
caps_.clipDistanceSupported = featureLevel_ >= D3D_FEATURE_LEVEL_10_0;
326
caps_.cullDistanceSupported = featureLevel_ >= D3D_FEATURE_LEVEL_10_0;
327
328
caps_.depthRangeMinusOneToOne = false;
329
caps_.framebufferBlitSupported = false;
330
caps_.framebufferCopySupported = true;
331
caps_.framebufferDepthBlitSupported = false;
332
caps_.framebufferStencilBlitSupported = false;
333
caps_.framebufferDepthCopySupported = true;
334
caps_.framebufferSeparateDepthCopySupported = false; // Though could be emulated with a draw.
335
caps_.preferredDepthBufferFormat = DataFormat::D24_S8;
336
caps_.textureDepthSupported = true;
337
caps_.texture3DSupported = true;
338
caps_.fragmentShaderInt32Supported = true;
339
caps_.anisoSupported = true;
340
caps_.textureNPOTFullySupported = true;
341
caps_.fragmentShaderDepthWriteSupported = true;
342
caps_.fragmentShaderStencilWriteSupported = false;
343
caps_.blendMinMaxSupported = true;
344
caps_.multiSampleLevelsMask = 1; // More could be supported with some work.
345
346
caps_.provokingVertexLast = false; // D3D has it first, unfortunately. (and no way to change it).
347
348
caps_.presentInstantModeChange = true;
349
caps_.presentMaxInterval = 4;
350
caps_.presentModesSupported = PresentMode::FIFO | PresentMode::IMMEDIATE;
351
352
D3D11_FEATURE_DATA_D3D11_OPTIONS options{};
353
HRESULT result = device_->CheckFeatureSupport(D3D11_FEATURE_D3D11_OPTIONS, &options, sizeof(options));
354
if (SUCCEEDED(result)) {
355
if (options.OutputMergerLogicOp) {
356
// Actually, need to check that the format supports logic ops as well.
357
// Which normal UNORM formats don't seem to do in D3D11. So meh. We can't enable logicOp support.
358
// caps_.logicOpSupported = true;
359
}
360
}
361
362
ComPtr<IDXGIDevice> dxgiDevice;
363
ComPtr<IDXGIAdapter> adapter;
364
HRESULT hr = device_.As(&dxgiDevice);
365
if (SUCCEEDED(hr)) {
366
hr = dxgiDevice->GetAdapter(&adapter);
367
if (SUCCEEDED(hr)) {
368
DXGI_ADAPTER_DESC desc;
369
adapter->GetDesc(&desc);
370
adapterDesc_ = ConvertWStringToUTF8(desc.Description);
371
switch (desc.VendorId) {
372
case 0x10DE: caps_.vendor = GPUVendor::VENDOR_NVIDIA; break;
373
case 0x1002:
374
case 0x1022: caps_.vendor = GPUVendor::VENDOR_AMD; break;
375
case 0x163C:
376
case 0x8086:
377
case 0x8087: caps_.vendor = GPUVendor::VENDOR_INTEL; break;
378
// TODO: There are Windows ARM devices that could have Qualcomm here too.
379
// Not sure where I'll find the vendor codes for those though...
380
default:
381
caps_.vendor = GPUVendor::VENDOR_UNKNOWN;
382
}
383
caps_.deviceID = desc.DeviceId;
384
}
385
}
386
387
caps_.isTilingGPU = false;
388
389
#ifndef __LIBRETRO__ // their build server uses an old SDK
390
if (swapChain_) {
391
DXGI_SWAP_CHAIN_DESC swapChainDesc;
392
swapChain_->GetDesc(&swapChainDesc);
393
394
if (swapChainDesc.Flags & DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING) {
395
swapChainTearingSupported_ = true;
396
}
397
}
398
#endif
399
400
// Temp texture for read-back of small images. Custom textures are created on demand for larger ones.
401
// TODO: Should really benchmark if this extra complexity has any benefit.
402
D3D11_TEXTURE2D_DESC packDesc{};
403
packDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
404
packDesc.BindFlags = 0;
405
packDesc.Width = 512;
406
packDesc.Height = 512;
407
packDesc.ArraySize = 1;
408
packDesc.MipLevels = 1;
409
packDesc.Usage = D3D11_USAGE_STAGING;
410
packDesc.SampleDesc.Count = 1;
411
packDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
412
hr = device_->CreateTexture2D(&packDesc, nullptr, &packTexture_);
413
_assert_(SUCCEEDED(hr));
414
415
shaderLanguageDesc_.Init(HLSL_D3D11);
416
417
const size_t UP_MAX_BYTES = 65536 * 24;
418
419
upBuffer_ = D3D11DrawContext::CreateBuffer(UP_MAX_BYTES, BufferUsageFlag::DYNAMIC | BufferUsageFlag::VERTEXDATA);
420
upIBuffer_ = D3D11DrawContext::CreateBuffer(UP_MAX_BYTES, BufferUsageFlag::DYNAMIC | BufferUsageFlag::INDEXDATA);
421
422
ComPtr<IDXGIDevice1> dxgiDevice1;
423
hr = device_.As(&dxgiDevice1);
424
if (SUCCEEDED(hr)) {
425
caps_.setMaxFrameLatencySupported = true;
426
dxgiDevice1->SetMaximumFrameLatency(maxInflightFrames);
427
}
428
}
429
430
D3D11DrawContext::~D3D11DrawContext() {
431
DestroyPresets();
432
433
upBuffer_->Release();
434
upIBuffer_->Release();
435
436
// Release references.
437
ID3D11RenderTargetView *view = nullptr;
438
context_->OMSetRenderTargets(1, &view, nullptr);
439
ID3D11ShaderResourceView *srv[2]{};
440
context_->PSSetShaderResources(0, 2, srv);
441
}
442
443
void D3D11DrawContext::HandleEvent(Event ev, int width, int height, void *param1, void *param2) {
444
switch (ev) {
445
case Event::LOST_BACKBUFFER: {
446
if (curRenderTargetView_.Get() == bbRenderTargetView_ || curDepthStencilView_ == bbDepthStencilView_) {
447
ID3D11RenderTargetView *view = nullptr;
448
context_->OMSetRenderTargets(1, &view, nullptr);
449
curRenderTargetView_.Reset();
450
curDepthStencilView_.Reset();
451
}
452
bbDepthStencilView_.Reset();
453
bbDepthStencilTex_.Reset();
454
curRTWidth_ = 0;
455
curRTHeight_ = 0;
456
break;
457
}
458
case Event::GOT_BACKBUFFER: {
459
bbRenderTargetView_ = (ID3D11RenderTargetView *)param1;
460
bbRenderTargetTex_ = (ID3D11Texture2D *)param2;
461
bbWidth_ = width;
462
bbHeight_ = height;
463
464
// Create matching depth stencil texture. This is not really needed for PPSSPP though,
465
// and probably not for most other renderers either as you're usually rendering to other render targets and
466
// then blitting them with a shader to the screen.
467
D3D11_TEXTURE2D_DESC descDepth{};
468
descDepth.Width = width;
469
descDepth.Height = height;
470
descDepth.MipLevels = 1;
471
descDepth.ArraySize = 1;
472
descDepth.Format = DXGI_FORMAT_D24_UNORM_S8_UINT;
473
descDepth.SampleDesc.Count = 1;
474
descDepth.SampleDesc.Quality = 0;
475
descDepth.Usage = D3D11_USAGE_DEFAULT;
476
descDepth.BindFlags = D3D11_BIND_DEPTH_STENCIL;
477
descDepth.CPUAccessFlags = 0;
478
descDepth.MiscFlags = 0;
479
HRESULT hr = device_->CreateTexture2D(&descDepth, nullptr, &bbDepthStencilTex_);
480
481
// Create the depth stencil view
482
D3D11_DEPTH_STENCIL_VIEW_DESC descDSV{};
483
descDSV.Format = descDepth.Format;
484
descDSV.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2D;
485
descDSV.Texture2D.MipSlice = 0;
486
hr = device_->CreateDepthStencilView(bbDepthStencilTex_.Get(), &descDSV, &bbDepthStencilView_);
487
488
context_->OMSetRenderTargets(1, &bbRenderTargetView_, bbDepthStencilView_.Get());
489
490
curRenderTargetView_ = bbRenderTargetView_;
491
curDepthStencilView_ = bbDepthStencilView_;
492
curRTWidth_ = width;
493
curRTHeight_ = height;
494
break;
495
}
496
case Event::LOST_DEVICE:
497
case Event::GOT_DEVICE:
498
case Event::RESIZED:
499
case Event::PRESENTED:
500
break;
501
}
502
}
503
504
void D3D11DrawContext::EndFrame() {
505
// Fake a submit time.
506
frameTimeHistory_[frameCount_].firstSubmit = time_now_d();
507
curPipeline_ = nullptr;
508
}
509
510
void D3D11DrawContext::Present(PresentMode presentMode) {
511
frameTimeHistory_[frameCount_].queuePresent = time_now_d();
512
513
// Safety for libretro
514
if (swapChain_) {
515
uint32_t interval = 1;
516
uint32_t flags = 0;
517
if (presentMode != PresentMode::FIFO) {
518
interval = 0;
519
#ifndef __LIBRETRO__ // their build server uses an old SDK
520
flags |= swapChainTearingSupported_ ? DXGI_PRESENT_ALLOW_TEARING : 0; // Assume "vsync off" also means "allow tearing"
521
#endif
522
}
523
swapChain_->Present(interval, flags);
524
currentInterval_ = interval;
525
}
526
527
curRenderTargetView_.Reset();
528
curDepthStencilView_.Reset();
529
frameCount_++;
530
}
531
532
void D3D11DrawContext::SetViewport(const Viewport &viewport) {
533
DisplayRect<float> rc{ viewport.TopLeftX , viewport.TopLeftY, viewport.Width, viewport.Height };
534
if (curRenderTargetView_.Get() == bbRenderTargetView_) // Only the backbuffer is actually rotated wrong!
535
RotateRectToDisplay(rc, curRTWidth_, curRTHeight_);
536
D3D11_VIEWPORT vp;
537
vp.TopLeftX = rc.x;
538
vp.TopLeftY = rc.y;
539
vp.Width = rc.w;
540
vp.Height = rc.h;
541
vp.MinDepth = viewport.MinDepth;
542
vp.MaxDepth = viewport.MaxDepth;
543
context_->RSSetViewports(1, &vp);
544
}
545
546
void D3D11DrawContext::SetScissorRect(int left, int top, int width, int height) {
547
_assert_(width >= 0);
548
_assert_(height >= 0);
549
DisplayRect<float> frc{ (float)left, (float)top, (float)width, (float)height };
550
if (curRenderTargetView_.Get() == bbRenderTargetView_) // Only the backbuffer is actually rotated wrong!
551
RotateRectToDisplay(frc, curRTWidth_, curRTHeight_);
552
D3D11_RECT rc{};
553
rc.left = (INT)frc.x;
554
rc.top = (INT)frc.y;
555
rc.right = (INT)(frc.x + frc.w);
556
rc.bottom = (INT)(frc.y + frc.h);
557
context_->RSSetScissorRects(1, &rc);
558
}
559
560
static const D3D11_COMPARISON_FUNC compareToD3D11[] = {
561
D3D11_COMPARISON_NEVER,
562
D3D11_COMPARISON_LESS,
563
D3D11_COMPARISON_EQUAL,
564
D3D11_COMPARISON_LESS_EQUAL,
565
D3D11_COMPARISON_GREATER,
566
D3D11_COMPARISON_NOT_EQUAL,
567
D3D11_COMPARISON_GREATER_EQUAL,
568
D3D11_COMPARISON_ALWAYS
569
};
570
571
static const D3D11_STENCIL_OP stencilOpToD3D11[] = {
572
D3D11_STENCIL_OP_KEEP,
573
D3D11_STENCIL_OP_ZERO,
574
D3D11_STENCIL_OP_REPLACE,
575
D3D11_STENCIL_OP_INCR_SAT,
576
D3D11_STENCIL_OP_DECR_SAT,
577
D3D11_STENCIL_OP_INVERT,
578
D3D11_STENCIL_OP_INCR,
579
D3D11_STENCIL_OP_DECR,
580
};
581
582
static DXGI_FORMAT dataFormatToD3D11(DataFormat format) {
583
switch (format) {
584
case DataFormat::R32_FLOAT: return DXGI_FORMAT_R32_FLOAT;
585
case DataFormat::R32G32_FLOAT: return DXGI_FORMAT_R32G32_FLOAT;
586
case DataFormat::R32G32B32_FLOAT: return DXGI_FORMAT_R32G32B32_FLOAT;
587
case DataFormat::R32G32B32A32_FLOAT: return DXGI_FORMAT_R32G32B32A32_FLOAT;
588
case DataFormat::A4R4G4B4_UNORM_PACK16: return DXGI_FORMAT_B4G4R4A4_UNORM;
589
case DataFormat::A1R5G5B5_UNORM_PACK16: return DXGI_FORMAT_B5G5R5A1_UNORM;
590
case DataFormat::R5G6B5_UNORM_PACK16: return DXGI_FORMAT_B5G6R5_UNORM;
591
case DataFormat::R8G8B8A8_UNORM: return DXGI_FORMAT_R8G8B8A8_UNORM;
592
case DataFormat::R8G8B8A8_UNORM_SRGB: return DXGI_FORMAT_R8G8B8A8_UNORM_SRGB;
593
case DataFormat::B8G8R8A8_UNORM: return DXGI_FORMAT_B8G8R8A8_UNORM;
594
case DataFormat::B8G8R8A8_UNORM_SRGB: return DXGI_FORMAT_B8G8R8A8_UNORM_SRGB;
595
case DataFormat::R16_UNORM: return DXGI_FORMAT_R16_UNORM;
596
case DataFormat::R16_FLOAT: return DXGI_FORMAT_R16_FLOAT;
597
case DataFormat::R16G16_FLOAT: return DXGI_FORMAT_R16G16_FLOAT;
598
case DataFormat::R16G16B16A16_FLOAT: return DXGI_FORMAT_R16G16B16A16_FLOAT;
599
case DataFormat::D24_S8: return DXGI_FORMAT_D24_UNORM_S8_UINT;
600
case DataFormat::D16: return DXGI_FORMAT_D16_UNORM;
601
case DataFormat::D32F: return DXGI_FORMAT_D32_FLOAT;
602
case DataFormat::D32F_S8: return DXGI_FORMAT_D32_FLOAT_S8X24_UINT;
603
case DataFormat::BC1_RGBA_UNORM_BLOCK: return DXGI_FORMAT_BC1_UNORM;
604
case DataFormat::BC2_UNORM_BLOCK: return DXGI_FORMAT_BC2_UNORM;
605
case DataFormat::BC3_UNORM_BLOCK: return DXGI_FORMAT_BC3_UNORM;
606
case DataFormat::BC4_UNORM_BLOCK: return DXGI_FORMAT_BC4_UNORM;
607
case DataFormat::BC5_UNORM_BLOCK: return DXGI_FORMAT_BC5_UNORM;
608
case DataFormat::BC7_UNORM_BLOCK: return DXGI_FORMAT_BC7_UNORM;
609
default:
610
return DXGI_FORMAT_UNKNOWN;
611
}
612
}
613
614
static D3D11_PRIMITIVE_TOPOLOGY primToD3D11[] = {
615
D3D11_PRIMITIVE_TOPOLOGY_POINTLIST,
616
D3D11_PRIMITIVE_TOPOLOGY_LINELIST,
617
D3D11_PRIMITIVE_TOPOLOGY_LINESTRIP,
618
D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST,
619
D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP,
620
D3D11_PRIMITIVE_TOPOLOGY_UNDEFINED,
621
// Tesselation shader only
622
D3D11_PRIMITIVE_TOPOLOGY_1_CONTROL_POINT_PATCHLIST, // ???
623
// These are for geometry shaders only.
624
D3D11_PRIMITIVE_TOPOLOGY_LINELIST_ADJ,
625
D3D11_PRIMITIVE_TOPOLOGY_LINESTRIP_ADJ,
626
D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST_ADJ,
627
D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP_ADJ,
628
};
629
630
inline void CopyStencilSide(D3D11_DEPTH_STENCILOP_DESC &side, const StencilSetup &input) {
631
side.StencilFunc = compareToD3D11[(int)input.compareOp];
632
side.StencilDepthFailOp = stencilOpToD3D11[(int)input.depthFailOp];
633
side.StencilFailOp = stencilOpToD3D11[(int)input.failOp];
634
side.StencilPassOp = stencilOpToD3D11[(int)input.passOp];
635
}
636
637
static const D3D11_BLEND_OP blendOpToD3D11[] = {
638
D3D11_BLEND_OP_ADD,
639
D3D11_BLEND_OP_SUBTRACT,
640
D3D11_BLEND_OP_REV_SUBTRACT,
641
D3D11_BLEND_OP_MIN,
642
D3D11_BLEND_OP_MAX,
643
};
644
645
static const D3D11_BLEND blendToD3D11[] = {
646
D3D11_BLEND_ZERO,
647
D3D11_BLEND_ONE,
648
D3D11_BLEND_SRC_COLOR,
649
D3D11_BLEND_INV_SRC_COLOR,
650
D3D11_BLEND_DEST_COLOR,
651
D3D11_BLEND_INV_DEST_COLOR,
652
D3D11_BLEND_SRC_ALPHA,
653
D3D11_BLEND_INV_SRC_ALPHA,
654
D3D11_BLEND_DEST_ALPHA,
655
D3D11_BLEND_INV_DEST_ALPHA,
656
D3D11_BLEND_BLEND_FACTOR,
657
D3D11_BLEND_INV_BLEND_FACTOR,
658
D3D11_BLEND_BLEND_FACTOR,
659
D3D11_BLEND_INV_BLEND_FACTOR,
660
D3D11_BLEND_SRC1_COLOR,
661
D3D11_BLEND_INV_SRC1_COLOR,
662
D3D11_BLEND_SRC1_ALPHA,
663
D3D11_BLEND_INV_SRC1_ALPHA,
664
};
665
666
class D3D11BlendState : public BlendState {
667
public:
668
~D3D11BlendState() {
669
}
670
ComPtr<ID3D11BlendState> bs;
671
float blendFactor[4];
672
};
673
674
HRESULT D3D11DrawContext::GetCachedDepthStencilState(const D3D11DepthStencilState *state, uint8_t stencilWriteMask, uint8_t stencilCompareMask,
675
ID3D11DepthStencilState **ppDepthStencilState) {
676
D3D11DepthStencilKey key;
677
key.desc = state->desc;
678
key.writeMask = stencilWriteMask;
679
key.compareMask = stencilCompareMask;
680
681
auto findResult = depthStencilCache_.find(key);
682
683
if (findResult != depthStencilCache_.end()) {
684
findResult->second->AddRef();
685
*ppDepthStencilState = findResult->second.Get();
686
return S_OK;
687
}
688
689
// OK, create and insert.
690
D3D11_DEPTH_STENCIL_DESC d3ddesc{};
691
d3ddesc.DepthEnable = state->desc.depthTestEnabled;
692
d3ddesc.DepthWriteMask = state->desc.depthWriteEnabled ? D3D11_DEPTH_WRITE_MASK_ALL : D3D11_DEPTH_WRITE_MASK_ZERO;
693
d3ddesc.DepthFunc = compareToD3D11[(int)state->desc.depthCompare];
694
d3ddesc.StencilEnable = state->desc.stencilEnabled;
695
d3ddesc.StencilReadMask = stencilCompareMask;
696
d3ddesc.StencilWriteMask = stencilWriteMask;
697
if (d3ddesc.StencilEnable) {
698
CopyStencilSide(d3ddesc.FrontFace, state->desc.stencil);
699
CopyStencilSide(d3ddesc.BackFace, state->desc.stencil);
700
}
701
702
HRESULT hr = device_->CreateDepthStencilState(&d3ddesc, ppDepthStencilState);
703
if (SUCCEEDED(hr)) {
704
depthStencilCache_[key] = *ppDepthStencilState;
705
}
706
return hr;
707
}
708
709
DepthStencilState *D3D11DrawContext::CreateDepthStencilState(const DepthStencilStateDesc &desc) {
710
D3D11DepthStencilState *dss = new D3D11DepthStencilState();
711
dss->desc = desc;
712
return static_cast<DepthStencilState *>(dss);
713
}
714
715
BlendState *D3D11DrawContext::CreateBlendState(const BlendStateDesc &desc) {
716
D3D11BlendState *bs = new D3D11BlendState();
717
D3D11_BLEND_DESC d3ddesc{};
718
d3ddesc.AlphaToCoverageEnable = FALSE;
719
d3ddesc.IndependentBlendEnable = FALSE;
720
d3ddesc.RenderTarget[0].BlendEnable = desc.enabled;
721
d3ddesc.RenderTarget[0].RenderTargetWriteMask = desc.colorMask;
722
d3ddesc.RenderTarget[0].BlendOp = blendOpToD3D11[(int)desc.eqCol];
723
d3ddesc.RenderTarget[0].BlendOpAlpha = blendOpToD3D11[(int)desc.eqAlpha];
724
d3ddesc.RenderTarget[0].SrcBlend = blendToD3D11[(int)desc.srcCol];
725
d3ddesc.RenderTarget[0].SrcBlendAlpha = blendToD3D11[(int)desc.srcAlpha];
726
d3ddesc.RenderTarget[0].DestBlend = blendToD3D11[(int)desc.dstCol];
727
d3ddesc.RenderTarget[0].DestBlendAlpha = blendToD3D11[(int)desc.dstAlpha];
728
if (SUCCEEDED(device_->CreateBlendState(&d3ddesc, &bs->bs)))
729
return bs;
730
delete bs;
731
return nullptr;
732
}
733
734
class D3D11RasterState : public RasterState {
735
public:
736
~D3D11RasterState() {
737
}
738
ComPtr<ID3D11RasterizerState> rs;
739
};
740
741
RasterState *D3D11DrawContext::CreateRasterState(const RasterStateDesc &desc) {
742
D3D11RasterState *rs = new D3D11RasterState();
743
D3D11_RASTERIZER_DESC d3ddesc{};
744
d3ddesc.FillMode = D3D11_FILL_SOLID;
745
switch (desc.cull) {
746
case CullMode::BACK: d3ddesc.CullMode = D3D11_CULL_BACK; break;
747
case CullMode::FRONT: d3ddesc.CullMode = D3D11_CULL_FRONT; break;
748
default:
749
case CullMode::NONE: d3ddesc.CullMode = D3D11_CULL_NONE; break;
750
}
751
d3ddesc.FrontCounterClockwise = desc.frontFace == Facing::CCW;
752
d3ddesc.ScissorEnable = true; // We always run with scissor enabled
753
d3ddesc.DepthClipEnable = true;
754
if (SUCCEEDED(device_->CreateRasterizerState(&d3ddesc, &rs->rs)))
755
return rs;
756
delete rs;
757
return nullptr;
758
}
759
760
class D3D11SamplerState : public SamplerState {
761
public:
762
~D3D11SamplerState() {
763
}
764
ComPtr<ID3D11SamplerState> ss;
765
};
766
767
static const D3D11_TEXTURE_ADDRESS_MODE taddrToD3D11[] = {
768
D3D11_TEXTURE_ADDRESS_WRAP,
769
D3D11_TEXTURE_ADDRESS_MIRROR,
770
D3D11_TEXTURE_ADDRESS_CLAMP,
771
D3D11_TEXTURE_ADDRESS_BORDER,
772
};
773
774
SamplerState *D3D11DrawContext::CreateSamplerState(const SamplerStateDesc &desc) {
775
D3D11SamplerState *ss = new D3D11SamplerState();
776
D3D11_SAMPLER_DESC d3ddesc{};
777
d3ddesc.AddressU = taddrToD3D11[(int)desc.wrapU];
778
d3ddesc.AddressV = taddrToD3D11[(int)desc.wrapV];
779
d3ddesc.AddressW = taddrToD3D11[(int)desc.wrapW];
780
// TODO: Needs improvement
781
d3ddesc.Filter = desc.magFilter == TextureFilter::LINEAR ? D3D11_FILTER_MIN_MAG_MIP_LINEAR : D3D11_FILTER_MIN_MAG_MIP_POINT;
782
d3ddesc.MaxAnisotropy = 1.0f; // (UINT)desc.maxAniso;
783
d3ddesc.MinLOD = -FLT_MAX;
784
d3ddesc.MaxLOD = FLT_MAX;
785
d3ddesc.ComparisonFunc = compareToD3D11[(int)desc.shadowCompareFunc];
786
for (int i = 0; i < 4; i++) {
787
d3ddesc.BorderColor[i] = 1.0f;
788
}
789
if (SUCCEEDED(device_->CreateSamplerState(&d3ddesc, &ss->ss)))
790
return ss;
791
delete ss;
792
return nullptr;
793
}
794
795
// Input layout creation is delayed to pipeline creation, as we need the vertex shader bytecode.
796
class D3D11InputLayout : public InputLayout {
797
public:
798
D3D11InputLayout() {}
799
InputLayoutDesc desc;
800
std::vector<D3D11_INPUT_ELEMENT_DESC> elements;
801
UINT stride; // type to match function parameter
802
};
803
804
const char *semanticToD3D11(int semantic, UINT *index) {
805
*index = 0;
806
switch (semantic) {
807
case SEM_POSITION: return "POSITION";
808
case SEM_COLOR0: *index = 0; return "COLOR";
809
case SEM_COLOR1: *index = 1; return "COLOR";
810
case SEM_TEXCOORD0: *index = 0; return "TEXCOORD";
811
case SEM_TEXCOORD1: *index = 1; return "TEXCOORD";
812
case SEM_NORMAL: return "NORMAL";
813
case SEM_TANGENT: return "TANGENT";
814
case SEM_BINORMAL: return "BINORMAL"; // really BITANGENT
815
default: return "UNKNOWN";
816
}
817
}
818
819
InputLayout *D3D11DrawContext::CreateInputLayout(const InputLayoutDesc &desc) {
820
D3D11InputLayout *inputLayout = new D3D11InputLayout();
821
inputLayout->desc = desc;
822
823
// Translate to D3D11 elements;
824
for (size_t i = 0; i < desc.attributes.size(); i++) {
825
D3D11_INPUT_ELEMENT_DESC el;
826
el.AlignedByteOffset = desc.attributes[i].offset;
827
el.Format = dataFormatToD3D11(desc.attributes[i].format);
828
el.InstanceDataStepRate = 0;
829
el.InputSlot = 0;
830
el.SemanticName = semanticToD3D11(desc.attributes[i].location, &el.SemanticIndex);
831
el.InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA;
832
inputLayout->elements.push_back(el);
833
}
834
inputLayout->stride = desc.stride;
835
return inputLayout;
836
}
837
838
class D3D11ShaderModule : public ShaderModule {
839
public:
840
D3D11ShaderModule(std::string_view tag) : tag_(tag) { }
841
~D3D11ShaderModule() {
842
}
843
ShaderStage GetStage() const override { return stage; }
844
845
std::vector<uint8_t> byteCode_;
846
ShaderStage stage;
847
std::string tag_;
848
849
ComPtr<ID3D11VertexShader> vs;
850
ComPtr<ID3D11PixelShader> ps;
851
ComPtr<ID3D11GeometryShader> gs;
852
};
853
854
class D3D11Pipeline : public Pipeline {
855
public:
856
~D3D11Pipeline() {
857
for (D3D11ShaderModule *shaderModule : shaderModules) {
858
shaderModule->Release();
859
}
860
}
861
862
AutoRef<D3D11InputLayout> input;
863
ComPtr<ID3D11InputLayout> il;
864
AutoRef<D3D11BlendState> blend;
865
AutoRef<D3D11RasterState> raster;
866
867
// Combined with dynamic state to key into cached D3D11DepthStencilState, to emulate dynamic parameters.
868
AutoRef<D3D11DepthStencilState> depthStencil;
869
870
ComPtr<ID3D11VertexShader> vs;
871
ComPtr<ID3D11PixelShader> ps;
872
ComPtr<ID3D11GeometryShader> gs;
873
D3D11_PRIMITIVE_TOPOLOGY topology = D3D11_PRIMITIVE_TOPOLOGY_UNDEFINED;
874
875
std::vector<D3D11ShaderModule *> shaderModules;
876
877
size_t dynamicUniformsSize = 0;
878
ComPtr<ID3D11Buffer> dynamicUniforms;
879
};
880
881
class D3D11Texture : public Texture {
882
public:
883
D3D11Texture(const TextureDesc &desc) {
884
width_ = desc.width;
885
height_ = desc.height;
886
depth_ = desc.depth;
887
format_ = desc.format;
888
mipLevels_ = desc.mipLevels;
889
}
890
~D3D11Texture() {
891
}
892
893
bool Create(ID3D11DeviceContext *context, ID3D11Device *device, const TextureDesc &desc, bool generateMips);
894
895
bool CreateStagingTexture(ID3D11Device *device);
896
void UpdateTextureLevels(ID3D11DeviceContext *context, ID3D11Device *device, Texture *texture, const uint8_t *const *data, TextureCallback initDataCallback, int numLevels);
897
898
ID3D11ShaderResourceView *View() { return view_.Get(); }
899
900
private:
901
bool FillLevel(ID3D11DeviceContext *context, int level, int w, int h, int d, const uint8_t *const *data, TextureCallback initDataCallback);
902
903
ComPtr<ID3D11Texture2D> tex_;
904
ComPtr<ID3D11Texture2D> stagingTex_;
905
ComPtr<ID3D11ShaderResourceView> view_;
906
int mipLevels_ = 0;
907
};
908
909
bool D3D11Texture::FillLevel(ID3D11DeviceContext *context, int level, int w, int h, int d, const uint8_t *const *data, TextureCallback initDataCallback) {
910
D3D11_MAPPED_SUBRESOURCE mapped;
911
HRESULT hr = context->Map(stagingTex_.Get(), level, D3D11_MAP_WRITE, 0, &mapped);
912
if (!SUCCEEDED(hr)) {
913
tex_.Reset();
914
return false;
915
}
916
917
if (!initDataCallback((uint8_t *)mapped.pData, data[level], w, h, d, mapped.RowPitch, mapped.DepthPitch)) {
918
for (int s = 0; s < d; ++s) {
919
for (int y = 0; y < h; ++y) {
920
void *dest = (uint8_t *)mapped.pData + mapped.DepthPitch * s + mapped.RowPitch * y;
921
uint32_t byteStride = w * (uint32_t)DataFormatSizeInBytes(format_);
922
const void *src = data[level] + byteStride * (y + h * s);
923
memcpy(dest, src, byteStride);
924
}
925
}
926
}
927
context->Unmap(stagingTex_.Get(), level);
928
return true;
929
}
930
931
bool D3D11Texture::CreateStagingTexture(ID3D11Device *device) {
932
if (stagingTex_)
933
return true;
934
D3D11_TEXTURE2D_DESC descColor{};
935
descColor.Width = width_;
936
descColor.Height = height_;
937
descColor.MipLevels = mipLevels_;
938
descColor.ArraySize = 1;
939
descColor.Format = dataFormatToD3D11(format_);
940
descColor.SampleDesc.Count = 1;
941
descColor.SampleDesc.Quality = 0;
942
descColor.Usage = D3D11_USAGE_STAGING;
943
descColor.BindFlags = 0;
944
descColor.MiscFlags = 0;
945
descColor.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
946
947
return SUCCEEDED(device->CreateTexture2D(&descColor, nullptr, &stagingTex_));
948
}
949
950
bool D3D11Texture::Create(ID3D11DeviceContext *context, ID3D11Device *device, const TextureDesc &desc, bool generateMips) {
951
D3D11_TEXTURE2D_DESC descColor{};
952
descColor.Width = desc.width;
953
descColor.Height = desc.height;
954
descColor.MipLevels = desc.mipLevels;
955
descColor.ArraySize = 1;
956
descColor.Format = dataFormatToD3D11(desc.format);
957
descColor.SampleDesc.Count = 1;
958
descColor.SampleDesc.Quality = 0;
959
descColor.Usage = D3D11_USAGE_DEFAULT;
960
descColor.BindFlags = generateMips ? (D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET) : D3D11_BIND_SHADER_RESOURCE;
961
descColor.MiscFlags = generateMips ? D3D11_RESOURCE_MISC_GENERATE_MIPS : 0;
962
descColor.CPUAccessFlags = 0;
963
964
// Make sure we have a staging texture if we'll need it.
965
if (desc.initDataCallback && !CreateStagingTexture(device)) {
966
return false;
967
}
968
969
D3D11_SUBRESOURCE_DATA *initDataParam = nullptr;
970
D3D11_SUBRESOURCE_DATA initData[12]{};
971
std::vector<uint8_t> initDataBuffer[12];
972
if (desc.initData.size() && !generateMips && !desc.initDataCallback) {
973
int w = desc.width;
974
int h = desc.height;
975
int d = desc.depth;
976
for (int i = 0; i < (int)desc.initData.size(); i++) {
977
uint32_t byteStride = w * (uint32_t)DataFormatSizeInBytes(desc.format);
978
initData[i].pSysMem = desc.initData[i];
979
initData[i].SysMemPitch = (UINT)byteStride;
980
initData[i].SysMemSlicePitch = (UINT)(h * byteStride);
981
w = (w + 1) / 2;
982
h = (h + 1) / 2;
983
d = (d + 1) / 2;
984
}
985
initDataParam = initData;
986
}
987
988
HRESULT hr = device->CreateTexture2D(&descColor, initDataParam, &tex_);
989
if (!SUCCEEDED(hr)) {
990
tex_ = nullptr;
991
return false;
992
}
993
hr = device->CreateShaderResourceView(tex_.Get(), nullptr, &view_);
994
if (!SUCCEEDED(hr)) {
995
return false;
996
}
997
998
if (generateMips && desc.initData.size() >= 1) {
999
if (desc.initDataCallback) {
1000
if (!FillLevel(context, 0, desc.width, desc.height, desc.depth, desc.initData.data(), desc.initDataCallback)) {
1001
tex_.Reset();
1002
return false;
1003
}
1004
1005
context->CopyResource(tex_.Get(), stagingTex_.Get());
1006
stagingTex_.Reset();
1007
} else {
1008
uint32_t byteStride = desc.width * (uint32_t)DataFormatSizeInBytes(desc.format);
1009
context->UpdateSubresource(tex_.Get(), 0, nullptr, desc.initData[0], byteStride, 0);
1010
}
1011
context->GenerateMips(view_.Get());
1012
} else if (desc.initDataCallback) {
1013
int w = desc.width;
1014
int h = desc.height;
1015
int d = desc.depth;
1016
for (int i = 0; i < (int)desc.initData.size(); i++) {
1017
if (!FillLevel(context, i, w, h, d, desc.initData.data(), desc.initDataCallback)) {
1018
if (i == 0) {
1019
return false;
1020
} else {
1021
break;
1022
}
1023
}
1024
1025
w = (w + 1) / 2;
1026
h = (h + 1) / 2;
1027
d = (d + 1) / 2;
1028
}
1029
1030
context->CopyResource(tex_.Get(), stagingTex_.Get());
1031
stagingTex_.Reset();
1032
}
1033
return true;
1034
}
1035
1036
void D3D11Texture::UpdateTextureLevels(ID3D11DeviceContext *context, ID3D11Device *device, Texture *texture, const uint8_t * const*data, TextureCallback initDataCallback, int numLevels) {
1037
if (!CreateStagingTexture(device)) {
1038
return;
1039
}
1040
1041
int w = width_;
1042
int h = height_;
1043
int d = depth_;
1044
for (int i = 0; i < numLevels; i++) {
1045
if (!FillLevel(context, i, w, h, d, data, initDataCallback)) {
1046
break;
1047
}
1048
1049
w = (w + 1) / 2;
1050
h = (h + 1) / 2;
1051
d = (d + 1) / 2;
1052
}
1053
1054
context->CopyResource(tex_.Get(), stagingTex_.Get());
1055
stagingTex_.Reset();
1056
}
1057
1058
Texture *D3D11DrawContext::CreateTexture(const TextureDesc &desc) {
1059
if (!(GetDataFormatSupport(desc.format) & FMT_TEXTURE)) {
1060
// D3D11 does not support this format as a texture format.
1061
return nullptr;
1062
}
1063
1064
D3D11Texture *tex = new D3D11Texture(desc);
1065
bool generateMips = desc.generateMips;
1066
if (desc.generateMips && !(GetDataFormatSupport(desc.format) & FMT_AUTOGEN_MIPS)) {
1067
// D3D11 does not support autogenerating mipmaps for this format.
1068
generateMips = false;
1069
}
1070
if (!tex->Create(context_.Get(), device_.Get(), desc, generateMips)) {
1071
tex->Release();
1072
return nullptr;
1073
}
1074
1075
return tex;
1076
}
1077
1078
1079
void D3D11DrawContext::UpdateTextureLevels(Texture *texture, const uint8_t **data, TextureCallback initDataCallback, int numLevels) {
1080
D3D11Texture *tex = (D3D11Texture *)texture;
1081
tex->UpdateTextureLevels(context_.Get(), device_.Get(), texture, data, initDataCallback, numLevels);
1082
}
1083
1084
ShaderModule *D3D11DrawContext::CreateShaderModule(ShaderStage stage, ShaderLanguage language, const uint8_t *data, size_t dataSize, const char *tag) {
1085
if (language != ShaderLanguage::HLSL_D3D11) {
1086
ERROR_LOG(Log::G3D, "Unsupported shader language");
1087
return nullptr;
1088
}
1089
1090
const char *vertexModel = "vs_4_0";
1091
const char *fragmentModel = "ps_4_0";
1092
const char *geometryModel = "gs_4_0";
1093
if (featureLevel_ <= D3D_FEATURE_LEVEL_9_3) {
1094
vertexModel = "vs_4_0_level_9_1";
1095
fragmentModel = "ps_4_0_level_9_1";
1096
geometryModel = nullptr;
1097
}
1098
1099
std::string compiled;
1100
std::string errors;
1101
const char *target = nullptr;
1102
switch (stage) {
1103
case ShaderStage::Fragment: target = fragmentModel; break;
1104
case ShaderStage::Vertex: target = vertexModel; break;
1105
case ShaderStage::Geometry:
1106
if (!geometryModel)
1107
return nullptr;
1108
target = geometryModel;
1109
break;
1110
case ShaderStage::Compute:
1111
default:
1112
Crash();
1113
break;
1114
}
1115
if (!target) {
1116
return nullptr;
1117
}
1118
1119
ComPtr<ID3DBlob> compiledCode;
1120
ComPtr<ID3DBlob> errorMsgs;
1121
int flags = D3DCOMPILE_ENABLE_BACKWARDS_COMPATIBILITY;
1122
HRESULT result = ptr_D3DCompile(data, dataSize, nullptr, nullptr, nullptr, "main", target, flags, 0, &compiledCode, &errorMsgs);
1123
if (compiledCode) {
1124
compiled = std::string((const char *)compiledCode->GetBufferPointer(), compiledCode->GetBufferSize());
1125
}
1126
if (errorMsgs) {
1127
errors = std::string((const char *)errorMsgs->GetBufferPointer(), errorMsgs->GetBufferSize());
1128
ERROR_LOG(Log::G3D, "Failed compiling %s:\n%s\n%s", tag, data, errors.c_str());
1129
}
1130
1131
if (result != S_OK) {
1132
return nullptr;
1133
}
1134
1135
// OK, we can now proceed
1136
data = (const uint8_t *)compiled.c_str();
1137
dataSize = compiled.size();
1138
D3D11ShaderModule *module = new D3D11ShaderModule(tag);
1139
module->stage = stage;
1140
module->byteCode_ = std::vector<uint8_t>(data, data + dataSize);
1141
switch (stage) {
1142
case ShaderStage::Vertex:
1143
result = device_->CreateVertexShader(data, dataSize, nullptr, &module->vs);
1144
break;
1145
case ShaderStage::Fragment:
1146
result = device_->CreatePixelShader(data, dataSize, nullptr, &module->ps);
1147
break;
1148
case ShaderStage::Geometry:
1149
result = device_->CreateGeometryShader(data, dataSize, nullptr, &module->gs);
1150
break;
1151
default:
1152
ERROR_LOG(Log::G3D, "Unsupported shader stage");
1153
result = S_FALSE;
1154
break;
1155
}
1156
if (result == S_OK) {
1157
return module;
1158
} else {
1159
delete module;
1160
return nullptr;
1161
}
1162
return nullptr;
1163
}
1164
1165
Pipeline *D3D11DrawContext::CreateGraphicsPipeline(const PipelineDesc &desc, const char *tag) {
1166
D3D11Pipeline *dPipeline = new D3D11Pipeline();
1167
dPipeline->blend = (D3D11BlendState *)desc.blend;
1168
dPipeline->depthStencil = (D3D11DepthStencilState *)desc.depthStencil;
1169
dPipeline->input = (D3D11InputLayout *)desc.inputLayout;
1170
dPipeline->raster = (D3D11RasterState *)desc.raster;
1171
dPipeline->topology = primToD3D11[(int)desc.prim];
1172
if (desc.uniformDesc) {
1173
dPipeline->dynamicUniformsSize = desc.uniformDesc->uniformBufferSize;
1174
D3D11_BUFFER_DESC bufdesc{};
1175
bufdesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
1176
// We just round up to 16 here. If we get some garbage, that's fine.
1177
bufdesc.ByteWidth = ((UINT)dPipeline->dynamicUniformsSize + 15) & ~15;
1178
bufdesc.StructureByteStride = bufdesc.ByteWidth;
1179
bufdesc.Usage = D3D11_USAGE_DYNAMIC;
1180
bufdesc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
1181
HRESULT hr = device_->CreateBuffer(&bufdesc, nullptr, &dPipeline->dynamicUniforms);
1182
if (FAILED(hr)) {
1183
dPipeline->Release();
1184
return nullptr;
1185
}
1186
}
1187
1188
std::vector<D3D11ShaderModule *> shaders;
1189
D3D11ShaderModule *vshader = nullptr;
1190
for (auto iter : desc.shaders) {
1191
iter->AddRef();
1192
1193
D3D11ShaderModule *module = (D3D11ShaderModule *)iter;
1194
shaders.push_back(module);
1195
switch (module->GetStage()) {
1196
case ShaderStage::Vertex:
1197
vshader = module;
1198
dPipeline->vs = module->vs;
1199
break;
1200
case ShaderStage::Fragment:
1201
dPipeline->ps = module->ps;
1202
break;
1203
case ShaderStage::Geometry:
1204
dPipeline->gs = module->gs;
1205
break;
1206
case ShaderStage::Compute:
1207
break;
1208
}
1209
}
1210
dPipeline->shaderModules = shaders;
1211
1212
if (!vshader) {
1213
// No vertex shader - no graphics
1214
dPipeline->Release();
1215
return nullptr;
1216
}
1217
1218
// Can finally create the input layout
1219
if (dPipeline->input != nullptr) {
1220
const std::vector<D3D11_INPUT_ELEMENT_DESC> &elements = dPipeline->input->elements;
1221
HRESULT hr = device_->CreateInputLayout(elements.data(), (UINT)elements.size(), vshader->byteCode_.data(), vshader->byteCode_.size(), &dPipeline->il);
1222
if (!SUCCEEDED(hr)) {
1223
Crash();
1224
}
1225
} else {
1226
dPipeline->il.Reset();
1227
}
1228
return dPipeline;
1229
}
1230
1231
void D3D11DrawContext::UpdateDynamicUniformBuffer(const void *ub, size_t size) {
1232
if (curPipeline_->dynamicUniformsSize != size) {
1233
Crash();
1234
}
1235
D3D11_MAPPED_SUBRESOURCE map{};
1236
context_->Map(curPipeline_->dynamicUniforms.Get(), 0, D3D11_MAP_WRITE_DISCARD, 0, &map);
1237
memcpy(map.pData, ub, size);
1238
context_->Unmap(curPipeline_->dynamicUniforms.Get(), 0);
1239
}
1240
1241
void D3D11DrawContext::Invalidate(InvalidationFlags flags) {
1242
if (flags & InvalidationFlags::CACHED_RENDER_STATE) {
1243
// This is a signal to forget all our state caching.
1244
curBlend_ = nullptr;
1245
curDepthStencil_ = nullptr;
1246
curRaster_ = nullptr;
1247
curPS_.Reset();
1248
curVS_.Reset();
1249
curGS_.Reset();
1250
curInputLayout_.Reset();
1251
curTopology_ = D3D11_PRIMITIVE_TOPOLOGY_UNDEFINED;
1252
curPipeline_= nullptr;
1253
}
1254
}
1255
1256
void D3D11DrawContext::BindPipeline(Pipeline *pipeline) {
1257
D3D11Pipeline *dPipeline = (D3D11Pipeline *)pipeline;
1258
if (curPipeline_ == dPipeline)
1259
return;
1260
curPipeline_ = dPipeline;
1261
}
1262
1263
void D3D11DrawContext::ApplyCurrentState() {
1264
if (curBlend_ != curPipeline_->blend || blendFactorDirty_) {
1265
context_->OMSetBlendState(curPipeline_->blend->bs.Get(), blendFactor_, 0xFFFFFFFF);
1266
curBlend_ = curPipeline_->blend;
1267
blendFactorDirty_ = false;
1268
}
1269
if (curDepthStencil_ != curPipeline_->depthStencil || stencilDirty_) {
1270
ComPtr<ID3D11DepthStencilState> dss;
1271
GetCachedDepthStencilState(curPipeline_->depthStencil, stencilWriteMask_, stencilCompareMask_, &dss);
1272
context_->OMSetDepthStencilState(dss.Get(), stencilRef_);
1273
curDepthStencil_ = curPipeline_->depthStencil;
1274
stencilDirty_ = false;
1275
}
1276
if (curRaster_ != curPipeline_->raster) {
1277
context_->RSSetState(curPipeline_->raster->rs.Get());
1278
curRaster_ = curPipeline_->raster;
1279
}
1280
if (curInputLayout_ != curPipeline_->il) {
1281
context_->IASetInputLayout(curPipeline_->il.Get());
1282
curInputLayout_ = curPipeline_->il;
1283
}
1284
if (curVS_ != curPipeline_->vs) {
1285
context_->VSSetShader(curPipeline_->vs.Get(), nullptr, 0);
1286
curVS_ = curPipeline_->vs;
1287
}
1288
if (curPS_ != curPipeline_->ps) {
1289
context_->PSSetShader(curPipeline_->ps.Get(), nullptr, 0);
1290
curPS_ = curPipeline_->ps;
1291
}
1292
if (curGS_ != curPipeline_->gs) {
1293
context_->GSSetShader(curPipeline_->gs.Get(), nullptr, 0);
1294
curGS_ = curPipeline_->gs;
1295
}
1296
if (curTopology_ != curPipeline_->topology) {
1297
context_->IASetPrimitiveTopology(curPipeline_->topology);
1298
curTopology_ = curPipeline_->topology;
1299
}
1300
1301
if (curPipeline_->input != nullptr) {
1302
context_->IASetVertexBuffers(0, 1, nextVertexBuffer_.GetAddressOf(), &curPipeline_->input->stride, &nextVertexBufferOffset_);
1303
}
1304
if (dirtyIndexBuffer_) {
1305
context_->IASetIndexBuffer(nextIndexBuffer_.Get(), DXGI_FORMAT_R16_UINT, nextIndexBufferOffset_);
1306
dirtyIndexBuffer_ = false;
1307
}
1308
if (curPipeline_->dynamicUniforms) {
1309
context_->VSSetConstantBuffers(0, 1, curPipeline_->dynamicUniforms.GetAddressOf());
1310
context_->PSSetConstantBuffers(0, 1, curPipeline_->dynamicUniforms.GetAddressOf());
1311
}
1312
}
1313
1314
class D3D11Buffer : public Buffer {
1315
public:
1316
~D3D11Buffer() {
1317
}
1318
ComPtr<ID3D11Buffer> buf;
1319
ComPtr<ID3D11ShaderResourceView> srView;
1320
size_t size;
1321
};
1322
1323
Buffer *D3D11DrawContext::CreateBuffer(size_t size, uint32_t usageFlags) {
1324
D3D11Buffer *b = new D3D11Buffer();
1325
D3D11_BUFFER_DESC desc{};
1326
desc.ByteWidth = (UINT)size;
1327
desc.BindFlags = 0;
1328
if (usageFlags & VERTEXDATA)
1329
desc.BindFlags |= D3D11_BIND_VERTEX_BUFFER;
1330
if (usageFlags & INDEXDATA)
1331
desc.BindFlags |= D3D11_BIND_INDEX_BUFFER;
1332
if (usageFlags & UNIFORM)
1333
desc.BindFlags |= D3D11_BIND_CONSTANT_BUFFER;
1334
1335
desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
1336
desc.Usage = D3D11_USAGE_DYNAMIC;
1337
1338
b->size = size;
1339
HRESULT hr = device_->CreateBuffer(&desc, nullptr, &b->buf);
1340
if (FAILED(hr)) {
1341
delete b;
1342
return nullptr;
1343
}
1344
return b;
1345
}
1346
1347
void D3D11DrawContext::UpdateBuffer(Buffer *buffer, const uint8_t *data, size_t offset, size_t size, UpdateBufferFlags flags) {
1348
D3D11Buffer *buf = (D3D11Buffer *)buffer;
1349
if ((flags & UPDATE_DISCARD) || (offset == 0 && size == buf->size)) {
1350
// Can just discard the old contents. This is only allowed for DYNAMIC buffers.
1351
D3D11_MAPPED_SUBRESOURCE map;
1352
context_->Map(buf->buf.Get(), 0, D3D11_MAP_WRITE_DISCARD, 0, &map);
1353
memcpy(map.pData, data, size);
1354
context_->Unmap(buf->buf.Get(), 0);
1355
return;
1356
}
1357
1358
// Should probably avoid this case.
1359
D3D11_BOX box{};
1360
box.left = (UINT)offset;
1361
box.right = (UINT)(offset + size);
1362
box.bottom = 1;
1363
box.back = 1;
1364
context_->UpdateSubresource(buf->buf.Get(), 0, &box, data, 0, 0);
1365
}
1366
1367
void D3D11DrawContext::BindVertexBuffer(Buffer *buffer, int offset) {
1368
// Lazy application
1369
D3D11Buffer *buf = (D3D11Buffer *)buffer;
1370
nextVertexBuffer_ = buf->buf;
1371
nextVertexBufferOffset_ = offset;
1372
}
1373
1374
void D3D11DrawContext::BindIndexBuffer(Buffer *indexBuffer, int offset) {
1375
D3D11Buffer *buf = (D3D11Buffer *)indexBuffer;
1376
// Lazy application
1377
dirtyIndexBuffer_ = true;
1378
nextIndexBuffer_ = buf ? buf->buf : nullptr;
1379
nextIndexBufferOffset_ = buf ? offset : 0;
1380
}
1381
1382
void D3D11DrawContext::Draw(int vertexCount, int offset) {
1383
ApplyCurrentState();
1384
context_->Draw(vertexCount, offset);
1385
}
1386
1387
void D3D11DrawContext::DrawIndexed(int indexCount, int offset) {
1388
ApplyCurrentState();
1389
context_->DrawIndexed(indexCount, offset, 0);
1390
}
1391
1392
void D3D11DrawContext::DrawUP(const void *vdata, int vertexCount) {
1393
int byteSize = vertexCount * curPipeline_->input->stride;
1394
1395
UpdateBuffer(upBuffer_, (const uint8_t *)vdata, 0, byteSize, Draw::UPDATE_DISCARD);
1396
BindVertexBuffer(upBuffer_, 0);
1397
int offset = 0;
1398
Draw(vertexCount, offset);
1399
}
1400
1401
void D3D11DrawContext::DrawIndexedUP(const void *vdata, int vertexCount, const void *idata, int indexCount) {
1402
int vbyteSize = vertexCount * curPipeline_->input->stride;
1403
int ibyteSize = indexCount * sizeof(u16);
1404
1405
UpdateBuffer(upBuffer_, (const uint8_t *)vdata, 0, vbyteSize, Draw::UPDATE_DISCARD);
1406
BindVertexBuffer(upBuffer_, 0);
1407
1408
UpdateBuffer(upIBuffer_, (const uint8_t *)idata, 0, ibyteSize, Draw::UPDATE_DISCARD);
1409
BindIndexBuffer(upIBuffer_, 0);
1410
DrawIndexed(indexCount, 0);
1411
}
1412
1413
void D3D11DrawContext::DrawIndexedClippedBatchUP(const void *vdata, int vertexCount, const void *idata, int indexCount, Slice<ClippedDraw> draws, const void *ub, size_t ubSize) {
1414
if (draws.is_empty() || !vertexCount || !indexCount) {
1415
return;
1416
}
1417
1418
curPipeline_ = (D3D11Pipeline *)draws[0].pipeline;
1419
1420
int vbyteSize = vertexCount * curPipeline_->input->stride;
1421
int ibyteSize = indexCount * sizeof(u16);
1422
1423
UpdateBuffer(upBuffer_, (const uint8_t *)vdata, 0, vbyteSize, Draw::UPDATE_DISCARD);
1424
BindVertexBuffer(upBuffer_, 0);
1425
1426
UpdateBuffer(upIBuffer_, (const uint8_t *)idata, 0, ibyteSize, Draw::UPDATE_DISCARD);
1427
BindIndexBuffer(upIBuffer_, 0);
1428
1429
UpdateDynamicUniformBuffer(ub, ubSize);
1430
ApplyCurrentState();
1431
1432
for (int i = 0; i < draws.size(); i++) {
1433
if (draws[i].pipeline != curPipeline_) {
1434
curPipeline_ = (D3D11Pipeline *)draws[i].pipeline;
1435
ApplyCurrentState();
1436
UpdateDynamicUniformBuffer(ub, ubSize);
1437
}
1438
1439
if (draws[i].bindTexture) {
1440
ComPtr<ID3D11ShaderResourceView> view = ((D3D11Texture *)draws[i].bindTexture)->View();
1441
context_->PSSetShaderResources(0, 1, view.GetAddressOf());
1442
} else if (draws[i].bindFramebufferAsTex) {
1443
ComPtr<ID3D11ShaderResourceView> view = ((D3D11Framebuffer *)draws[i].bindFramebufferAsTex)->colorSRView;
1444
switch (draws[i].aspect) {
1445
case Aspect::DEPTH_BIT:
1446
view = ((D3D11Framebuffer *)draws[i].bindFramebufferAsTex)->depthSRView;
1447
break;
1448
case Aspect::STENCIL_BIT:
1449
view = ((D3D11Framebuffer *)draws[i].bindFramebufferAsTex)->stencilSRView;
1450
break;
1451
default:
1452
break;
1453
}
1454
context_->PSSetShaderResources(0, 1, view.GetAddressOf());
1455
}
1456
ComPtr<ID3D11SamplerState> sstate = ((D3D11SamplerState *)draws[i].samplerState)->ss;
1457
context_->PSSetSamplers(0, 1, sstate.GetAddressOf());
1458
D3D11_RECT rc;
1459
rc.left = draws[i].clipx;
1460
rc.top = draws[i].clipy;
1461
rc.right = draws[i].clipx + draws[i].clipw;
1462
rc.bottom = draws[i].clipy + draws[i].cliph;
1463
context_->RSSetScissorRects(1, &rc);
1464
context_->DrawIndexed(draws[i].indexCount, draws[i].indexOffset, 0);
1465
}
1466
}
1467
1468
uint32_t D3D11DrawContext::GetDataFormatSupport(DataFormat fmt) const {
1469
DXGI_FORMAT giFmt = dataFormatToD3D11(fmt);
1470
if (giFmt == DXGI_FORMAT_UNKNOWN)
1471
return 0;
1472
UINT giSupport = 0;
1473
HRESULT result = device_->CheckFormatSupport(giFmt, &giSupport);
1474
if (FAILED(result))
1475
return 0;
1476
uint32_t support = 0;
1477
if (giSupport & D3D11_FORMAT_SUPPORT_TEXTURE2D)
1478
support |= FMT_TEXTURE;
1479
if (giSupport & D3D11_FORMAT_SUPPORT_RENDER_TARGET)
1480
support |= FMT_RENDERTARGET;
1481
if (giSupport & D3D11_FORMAT_SUPPORT_IA_VERTEX_BUFFER)
1482
support |= FMT_INPUTLAYOUT;
1483
if (giSupport & D3D11_FORMAT_SUPPORT_DEPTH_STENCIL)
1484
support |= FMT_DEPTHSTENCIL;
1485
if (giSupport & D3D11_FORMAT_SUPPORT_MIP_AUTOGEN)
1486
support |= FMT_AUTOGEN_MIPS;
1487
return support;
1488
}
1489
1490
Framebuffer *D3D11DrawContext::CreateFramebuffer(const FramebufferDesc &desc) {
1491
HRESULT hr;
1492
D3D11Framebuffer *fb = new D3D11Framebuffer(desc.width, desc.height);
1493
1494
// We don't (yet?) support multiview for D3D11. Not sure if there's a way to do it.
1495
// Texture arrays are supported but we don't have any other use cases yet.
1496
_dbg_assert_(desc.numLayers == 1);
1497
1498
fb->colorFormat = DXGI_FORMAT_R8G8B8A8_UNORM;
1499
D3D11_TEXTURE2D_DESC descColor{};
1500
descColor.Width = desc.width;
1501
descColor.Height = desc.height;
1502
descColor.MipLevels = 1;
1503
descColor.ArraySize = 1;
1504
descColor.Format = fb->colorFormat;
1505
descColor.SampleDesc.Count = 1;
1506
descColor.SampleDesc.Quality = 0;
1507
descColor.Usage = D3D11_USAGE_DEFAULT;
1508
descColor.BindFlags = D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE;
1509
descColor.CPUAccessFlags = 0;
1510
descColor.MiscFlags = 0;
1511
hr = device_->CreateTexture2D(&descColor, nullptr, &fb->colorTex);
1512
if (FAILED(hr)) {
1513
delete fb;
1514
return nullptr;
1515
}
1516
hr = device_->CreateRenderTargetView(fb->colorTex.Get(), nullptr, &fb->colorRTView);
1517
if (FAILED(hr)) {
1518
delete fb;
1519
return nullptr;
1520
}
1521
hr = device_->CreateShaderResourceView(fb->colorTex.Get(), nullptr, &fb->colorSRView);
1522
if (FAILED(hr)) {
1523
delete fb;
1524
return nullptr;
1525
}
1526
1527
if (desc.z_stencil) {
1528
fb->depthStencilFormat = DXGI_FORMAT_D24_UNORM_S8_UINT;
1529
D3D11_TEXTURE2D_DESC descDepth{};
1530
descDepth.Width = desc.width;
1531
descDepth.Height = desc.height;
1532
descDepth.MipLevels = 1;
1533
descDepth.ArraySize = 1;
1534
descDepth.Format = DXGI_FORMAT_R24G8_TYPELESS; // so we can create an R24X8 view of it.
1535
descDepth.SampleDesc.Count = 1;
1536
descDepth.SampleDesc.Quality = 0;
1537
descDepth.Usage = D3D11_USAGE_DEFAULT;
1538
descDepth.BindFlags = D3D11_BIND_DEPTH_STENCIL | D3D11_BIND_SHADER_RESOURCE;
1539
descDepth.CPUAccessFlags = 0;
1540
descDepth.MiscFlags = 0;
1541
hr = device_->CreateTexture2D(&descDepth, nullptr, &fb->depthStencilTex);
1542
if (FAILED(hr)) {
1543
delete fb;
1544
return nullptr;
1545
}
1546
D3D11_DEPTH_STENCIL_VIEW_DESC descDSV{};
1547
descDSV.Format = DXGI_FORMAT_D24_UNORM_S8_UINT;
1548
descDSV.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2D;
1549
descDSV.Texture2D.MipSlice = 0;
1550
hr = device_->CreateDepthStencilView(fb->depthStencilTex.Get(), &descDSV, &fb->depthStencilRTView);
1551
if (FAILED(hr)) {
1552
delete fb;
1553
return nullptr;
1554
}
1555
1556
D3D11_SHADER_RESOURCE_VIEW_DESC depthViewDesc{};
1557
depthViewDesc.Format = DXGI_FORMAT_R24_UNORM_X8_TYPELESS;
1558
depthViewDesc.Texture2D.MostDetailedMip = 0;
1559
depthViewDesc.Texture2D.MipLevels = 1;
1560
depthViewDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
1561
hr = device_->CreateShaderResourceView(fb->depthStencilTex.Get(), &depthViewDesc, &fb->depthSRView);
1562
if (FAILED(hr)) {
1563
WARN_LOG(Log::G3D, "Failed to create SRV for depth buffer.");
1564
fb->depthSRView = nullptr;
1565
}
1566
1567
1568
D3D11_SHADER_RESOURCE_VIEW_DESC depthStencilViewDesc{};
1569
depthStencilViewDesc.Format = DXGI_FORMAT_R24G8_TYPELESS;
1570
depthStencilViewDesc.Texture2D.MostDetailedMip = 0;
1571
depthStencilViewDesc.Texture2D.MipLevels = 1;
1572
depthStencilViewDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
1573
hr = device_->CreateShaderResourceView(fb->depthStencilTex.Get(), &depthViewDesc, &fb->stencilSRView);
1574
if (FAILED(hr)) {
1575
WARN_LOG(Log::G3D, "Failed to create SRV for depth+stencil buffer.");
1576
fb->depthSRView = nullptr;
1577
}
1578
}
1579
1580
return fb;
1581
}
1582
1583
void D3D11DrawContext::BindTextures(int start, int count, Texture **textures, TextureBindFlags flags) {
1584
// Collect the resource views from the textures.
1585
ID3D11ShaderResourceView *views[MAX_BOUND_TEXTURES];
1586
_assert_(start + count <= ARRAY_SIZE(views));
1587
for (int i = 0; i < count; i++) {
1588
D3D11Texture *tex = (D3D11Texture *)textures[i];
1589
views[i] = tex ? tex->View() : nullptr;
1590
}
1591
context_->PSSetShaderResources(start, count, views);
1592
}
1593
1594
void D3D11DrawContext::BindNativeTexture(int index, void *nativeTexture) {
1595
// Collect the resource views from the textures.
1596
ID3D11ShaderResourceView *view = (ID3D11ShaderResourceView *)nativeTexture;
1597
context_->PSSetShaderResources(index, 1, &view);
1598
}
1599
1600
void D3D11DrawContext::BindSamplerStates(int start, int count, SamplerState **states) {
1601
ID3D11SamplerState *samplers[MAX_BOUND_TEXTURES];
1602
_assert_(start + count <= ARRAY_SIZE(samplers));
1603
for (int i = 0; i < count; i++) {
1604
D3D11SamplerState *samp = (D3D11SamplerState *)states[i];
1605
samplers[i] = samp ? samp->ss.Get() : nullptr;
1606
}
1607
context_->PSSetSamplers(start, count, samplers);
1608
}
1609
1610
void D3D11DrawContext::Clear(Aspect mask, uint32_t colorval, float depthVal, int stencilVal) {
1611
if ((mask & Aspect::COLOR_BIT) && curRenderTargetView_) {
1612
float colorRGBA[4];
1613
Uint8x4ToFloat4(colorRGBA, colorval);
1614
context_->ClearRenderTargetView(curRenderTargetView_.Get(), colorRGBA);
1615
}
1616
if ((mask & (Aspect::DEPTH_BIT | Aspect::STENCIL_BIT)) && curDepthStencilView_) {
1617
UINT clearFlag = 0;
1618
if (mask & Aspect::DEPTH_BIT)
1619
clearFlag |= D3D11_CLEAR_DEPTH;
1620
if (mask & Aspect::STENCIL_BIT)
1621
clearFlag |= D3D11_CLEAR_STENCIL;
1622
context_->ClearDepthStencilView(curDepthStencilView_.Get(), clearFlag, depthVal, stencilVal);
1623
}
1624
}
1625
1626
void D3D11DrawContext::BeginFrame(DebugFlags debugFlags) {
1627
FrameTimeData &frameTimeData = frameTimeHistory_.Add(frameCount_);
1628
frameTimeData.afterFenceWait = time_now_d();
1629
frameTimeData.frameBegin = frameTimeData.afterFenceWait;
1630
1631
context_->OMSetRenderTargets(1, curRenderTargetView_.GetAddressOf(), curDepthStencilView_.Get());
1632
1633
if (curBlend_ != nullptr) {
1634
context_->OMSetBlendState(curBlend_->bs.Get(), blendFactor_, 0xFFFFFFFF);
1635
}
1636
if (curDepthStencil_ != nullptr) {
1637
ComPtr<ID3D11DepthStencilState> dss;
1638
GetCachedDepthStencilState(curDepthStencil_, stencilWriteMask_, stencilCompareMask_, &dss);
1639
context_->OMSetDepthStencilState(dss.Get(), stencilRef_);
1640
}
1641
if (curRaster_ != nullptr) {
1642
context_->RSSetState(curRaster_->rs.Get());
1643
}
1644
context_->IASetInputLayout(curInputLayout_.Get());
1645
context_->VSSetShader(curVS_.Get(), nullptr, 0);
1646
context_->PSSetShader(curPS_.Get(), nullptr, 0);
1647
context_->GSSetShader(curGS_.Get(), nullptr, 0);
1648
if (curTopology_ != D3D11_PRIMITIVE_TOPOLOGY_UNDEFINED) {
1649
context_->IASetPrimitiveTopology(curTopology_);
1650
}
1651
if (curPipeline_ != nullptr) {
1652
context_->IASetVertexBuffers(0, 1, nextVertexBuffer_.GetAddressOf(), &curPipeline_->input->stride, &nextVertexBufferOffset_);
1653
context_->IASetIndexBuffer(nextIndexBuffer_.Get(), DXGI_FORMAT_R16_UINT, nextIndexBufferOffset_);
1654
if (curPipeline_->dynamicUniforms) {
1655
context_->VSSetConstantBuffers(0, 1, curPipeline_->dynamicUniforms.GetAddressOf());
1656
context_->PSSetConstantBuffers(0, 1, curPipeline_->dynamicUniforms.GetAddressOf());
1657
}
1658
}
1659
}
1660
1661
void D3D11DrawContext::CopyFramebufferImage(Framebuffer *srcfb, int level, int x, int y, int z, Framebuffer *dstfb, int dstLevel, int dstX, int dstY, int dstZ, int width, int height, int depth, Aspect aspect, const char *tag) {
1662
D3D11Framebuffer *src = (D3D11Framebuffer *)srcfb;
1663
D3D11Framebuffer *dst = (D3D11Framebuffer *)dstfb;
1664
1665
ComPtr<ID3D11Texture2D> srcTex;
1666
ComPtr<ID3D11Texture2D> dstTex;
1667
switch (aspect) {
1668
case Aspect::COLOR_BIT:
1669
srcTex = src->colorTex;
1670
dstTex = dst->colorTex;
1671
break;
1672
case Aspect::DEPTH_BIT:
1673
srcTex = src->depthStencilTex;
1674
dstTex = dst->depthStencilTex;
1675
break;
1676
case Aspect::NO_BIT:
1677
case Aspect::STENCIL_BIT:
1678
case Aspect::VIEW_BIT:
1679
case Aspect::FORMAT_BIT:
1680
break;
1681
}
1682
_assert_(srcTex && dstTex);
1683
1684
// TODO: Check for level too!
1685
if (width == src->Width() && width == dst->Width() && height == src->Height() && height == dst->Height() && x == 0 && y == 0 && z == 0 && dstX == 0 && dstY == 0 && dstZ == 0) {
1686
// Don't need to specify region. This might be faster, too.
1687
context_->CopyResource(dstTex.Get(), srcTex.Get());
1688
return;
1689
}
1690
1691
if (aspect != Aspect::DEPTH_BIT) {
1692
// Non-full copies are not supported for the depth channel.
1693
// Note that we need to clip the source box.
1694
if (x < 0) {
1695
width += x; // note that x is negative
1696
dstX -= x;
1697
x = 0;
1698
}
1699
if (y < 0) {
1700
height += y; // note that y is negative
1701
dstY -= y;
1702
y = 0;
1703
}
1704
if (x + width > src->Width()) {
1705
width = src->Width() - x;
1706
}
1707
if (y + height > src->Height()) {
1708
height = src->Height() - y;
1709
}
1710
D3D11_BOX srcBox{ (UINT)x, (UINT)y, (UINT)z, (UINT)(x + width), (UINT)(y + height), (UINT)(z + depth) };
1711
context_->CopySubresourceRegion(dstTex.Get(), dstLevel, dstX, dstY, dstZ, srcTex.Get(), level, &srcBox);
1712
}
1713
}
1714
1715
bool D3D11DrawContext::BlitFramebuffer(Framebuffer *srcfb, int srcX1, int srcY1, int srcX2, int srcY2, Framebuffer *dstfb, int dstX1, int dstY1, int dstX2, int dstY2, Aspect aspects, FBBlitFilter filter, const char *tag) {
1716
// Unfortunately D3D11 has no equivalent to this, gotta render a quad. Well, in some cases we can issue a copy instead.
1717
Crash();
1718
return false;
1719
}
1720
1721
bool D3D11DrawContext::CopyFramebufferToMemory(Framebuffer *src, Aspect channelBits, int bx, int by, int bw, int bh, Draw::DataFormat destFormat, void *pixels, int pixelStride, ReadbackMode mode, const char *tag) {
1722
D3D11Framebuffer *fb = (D3D11Framebuffer *)src;
1723
1724
if (fb) {
1725
_assert_(fb->colorFormat == DXGI_FORMAT_R8G8B8A8_UNORM);
1726
1727
// TODO: Figure out where the badness really comes from.
1728
if (bx + bw > fb->Width()) {
1729
bw -= (bx + bw) - fb->Width();
1730
}
1731
if (by + bh > fb->Height()) {
1732
bh -= (by + bh) - fb->Height();
1733
}
1734
}
1735
1736
if (bh <= 0 || bw <= 0)
1737
return true;
1738
1739
bool useGlobalPacktex = (bx + bw <= 512 && by + bh <= 512) && channelBits == Aspect::COLOR_BIT;
1740
1741
ComPtr<ID3D11Texture2D> packTex;
1742
if (!useGlobalPacktex) {
1743
D3D11_TEXTURE2D_DESC packDesc{};
1744
packDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
1745
packDesc.BindFlags = 0;
1746
packDesc.Width = bw;
1747
packDesc.Height = bh;
1748
packDesc.ArraySize = 1;
1749
packDesc.MipLevels = 1;
1750
packDesc.Usage = D3D11_USAGE_STAGING;
1751
packDesc.SampleDesc.Count = 1;
1752
switch (channelBits) {
1753
case Aspect::COLOR_BIT:
1754
packDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; // TODO: fb->colorFormat;
1755
break;
1756
case Aspect::DEPTH_BIT:
1757
case Aspect::STENCIL_BIT:
1758
if (!fb) {
1759
// Not supported.
1760
return false;
1761
}
1762
packDesc.Format = fb->depthStencilFormat;
1763
break;
1764
default:
1765
_assert_(false);
1766
}
1767
device_->CreateTexture2D(&packDesc, nullptr, &packTex);
1768
} else {
1769
switch (channelBits) {
1770
case Aspect::DEPTH_BIT:
1771
case Aspect::STENCIL_BIT:
1772
if (!fb)
1773
return false;
1774
break;
1775
default:
1776
break;
1777
}
1778
packTex = packTexture_;
1779
}
1780
1781
if (!packTex)
1782
return false;
1783
1784
D3D11_BOX srcBox{ (UINT)bx, (UINT)by, 0, (UINT)(bx + bw), (UINT)(by + bh), 1 };
1785
DataFormat srcFormat = DataFormat::UNDEFINED;
1786
switch (channelBits) {
1787
case Aspect::COLOR_BIT:
1788
context_->CopySubresourceRegion(packTex.Get(), 0, bx, by, 0, fb ? fb->colorTex.Get() : bbRenderTargetTex_, 0, &srcBox);
1789
srcFormat = DataFormat::R8G8B8A8_UNORM;
1790
break;
1791
case Aspect::DEPTH_BIT:
1792
case Aspect::STENCIL_BIT:
1793
// For depth/stencil buffers, we can't reliably copy subrectangles, so just copy the whole resource.
1794
_assert_(fb); // Can't copy depth/stencil from backbuffer. Shouldn't happen thanks to checks above.
1795
context_->CopyResource(packTex.Get(), fb->depthStencilTex.Get());
1796
srcFormat = Draw::DataFormat::D24_S8;
1797
break;
1798
default:
1799
_assert_(false);
1800
break;
1801
}
1802
1803
// Ideally, we'd round robin between two packTexture_, and simply use the other one. Though if the game
1804
// does a once-off copy, that won't work at all.
1805
1806
// BIG GPU STALL
1807
D3D11_MAPPED_SUBRESOURCE map;
1808
HRESULT result = context_->Map(packTex.Get(), 0, D3D11_MAP_READ, 0, &map);
1809
if (FAILED(result)) {
1810
return false;
1811
}
1812
1813
const size_t srcByteOffset = by * map.RowPitch + bx * DataFormatSizeInBytes(srcFormat);
1814
const uint8_t *srcWithOffset = (const uint8_t *)map.pData + srcByteOffset;
1815
switch ((Aspect)channelBits) {
1816
case Aspect::COLOR_BIT:
1817
// Pixel size always 4 here because we always request BGRA8888.
1818
ConvertFromRGBA8888((uint8_t *)pixels, srcWithOffset, pixelStride, map.RowPitch / sizeof(uint32_t), bw, bh, destFormat);
1819
break;
1820
case Aspect::DEPTH_BIT:
1821
if (srcFormat == destFormat) {
1822
// Can just memcpy when it matches no matter the format!
1823
uint8_t *dst = (uint8_t *)pixels;
1824
const uint8_t *src = (const uint8_t *)srcWithOffset;
1825
for (int y = 0; y < bh; ++y) {
1826
memcpy(dst, src, bw * DataFormatSizeInBytes(srcFormat));
1827
dst += pixelStride * DataFormatSizeInBytes(srcFormat);
1828
src += map.RowPitch;
1829
}
1830
} else if (destFormat == DataFormat::D32F) {
1831
ConvertToD32F((uint8_t *)pixels, srcWithOffset, pixelStride, map.RowPitch / sizeof(uint32_t), bw, bh, srcFormat);
1832
} else if (destFormat == DataFormat::D16) {
1833
ConvertToD16((uint8_t *)pixels, srcWithOffset, pixelStride, map.RowPitch / sizeof(uint32_t), bw, bh, srcFormat);
1834
} else {
1835
_assert_(false);
1836
}
1837
break;
1838
case Aspect::STENCIL_BIT:
1839
if (srcFormat == destFormat) {
1840
// Can just memcpy when it matches no matter the format!
1841
uint8_t *dst = (uint8_t *)pixels;
1842
const uint8_t *src = (const uint8_t *)srcWithOffset;
1843
for (int y = 0; y < bh; ++y) {
1844
memcpy(dst, src, bw * DataFormatSizeInBytes(srcFormat));
1845
dst += pixelStride * DataFormatSizeInBytes(srcFormat);
1846
src += map.RowPitch;
1847
}
1848
} else if (destFormat == DataFormat::S8) {
1849
for (int y = 0; y < bh; y++) {
1850
uint8_t *destStencil = (uint8_t *)pixels + y * pixelStride;
1851
const uint32_t *src = (const uint32_t *)(srcWithOffset + map.RowPitch * y);
1852
for (int x = 0; x < bw; x++) {
1853
destStencil[x] = src[x] >> 24;
1854
}
1855
}
1856
} else {
1857
_assert_(false);
1858
}
1859
break;
1860
case Aspect::NO_BIT:
1861
case Aspect::VIEW_BIT:
1862
case Aspect::FORMAT_BIT:
1863
break;
1864
}
1865
1866
context_->Unmap(packTex.Get(), 0);
1867
1868
return true;
1869
}
1870
1871
void D3D11DrawContext::BindFramebufferAsRenderTarget(Framebuffer *fbo, const RenderPassInfo &rp, const char *tag) {
1872
// TODO: deviceContext1 can actually discard. Useful on Windows Mobile.
1873
if (fbo) {
1874
D3D11Framebuffer *fb = (D3D11Framebuffer *)fbo;
1875
if (curRenderTargetView_ == fb->colorRTView && curDepthStencilView_ == fb->depthStencilRTView) {
1876
// No need to switch, but let's fallthrough to clear!
1877
} else {
1878
// It's not uncommon that the first slot happens to have the new render target bound as a texture,
1879
// so unbind to make the validation layers happy.
1880
ID3D11ShaderResourceView *empty[1] = {};
1881
context_->PSSetShaderResources(0, ARRAY_SIZE(empty), empty);
1882
context_->OMSetRenderTargets(1, fb->colorRTView.GetAddressOf(), fb->depthStencilRTView.Get());
1883
curRenderTargetView_ = fb->colorRTView;
1884
curDepthStencilView_ = fb->depthStencilRTView;
1885
curRTWidth_ = fb->Width();
1886
curRTHeight_ = fb->Height();
1887
}
1888
curRenderTarget_ = fb;
1889
} else {
1890
if (curRenderTargetView_.Get() == bbRenderTargetView_ && curDepthStencilView_ == bbDepthStencilView_) {
1891
// No need to switch, but let's fallthrough to clear!
1892
} else {
1893
context_->OMSetRenderTargets(1, &bbRenderTargetView_, bbDepthStencilView_.Get());
1894
curRenderTargetView_ = bbRenderTargetView_;
1895
curDepthStencilView_ = bbDepthStencilView_;
1896
curRTWidth_ = bbWidth_;
1897
curRTHeight_ = bbHeight_;
1898
}
1899
curRenderTarget_ = nullptr;
1900
}
1901
if (rp.color == RPAction::CLEAR && curRenderTargetView_) {
1902
float cv[4]{};
1903
if (rp.clearColor)
1904
Uint8x4ToFloat4(cv, rp.clearColor);
1905
context_->ClearRenderTargetView(curRenderTargetView_.Get(), cv);
1906
}
1907
int mask = 0;
1908
if (rp.depth == RPAction::CLEAR) {
1909
mask |= D3D11_CLEAR_DEPTH;
1910
}
1911
if (rp.stencil == RPAction::CLEAR) {
1912
mask |= D3D11_CLEAR_STENCIL;
1913
}
1914
if (mask && curDepthStencilView_) {
1915
context_->ClearDepthStencilView(curDepthStencilView_.Get(), mask, rp.clearDepth, rp.clearStencil);
1916
}
1917
1918
if (invalidationCallback_) {
1919
invalidationCallback_(InvalidationCallbackFlags::RENDER_PASS_STATE);
1920
}
1921
}
1922
1923
void D3D11DrawContext::BindFramebufferAsTexture(Framebuffer *fbo, int binding, Aspect channelBit, int layer) {
1924
_dbg_assert_(binding < MAX_BOUND_TEXTURES);
1925
_dbg_assert_(layer == ALL_LAYERS || layer == 0); // No multiple layer support on D3D
1926
D3D11Framebuffer *fb = (D3D11Framebuffer *)fbo;
1927
switch (channelBit) {
1928
case Aspect::COLOR_BIT:
1929
context_->PSSetShaderResources(binding, 1, fb->colorSRView.GetAddressOf());
1930
break;
1931
case Aspect::DEPTH_BIT:
1932
if (fb->depthSRView) {
1933
context_->PSSetShaderResources(binding, 1, fb->depthSRView.GetAddressOf());
1934
}
1935
break;
1936
default:
1937
break;
1938
}
1939
}
1940
1941
uint64_t D3D11DrawContext::GetNativeObject(NativeObject obj, void *srcObject) {
1942
switch (obj) {
1943
case NativeObject::DEVICE:
1944
return (uint64_t)(uintptr_t)device_.Get();
1945
case NativeObject::CONTEXT:
1946
return (uint64_t)(uintptr_t)context_.Get();
1947
case NativeObject::DEVICE_EX:
1948
return (uint64_t)(uintptr_t)device1_.Get();
1949
case NativeObject::CONTEXT_EX:
1950
return (uint64_t)(uintptr_t)context1_.Get();
1951
case NativeObject::BACKBUFFER_COLOR_TEX:
1952
return (uint64_t)(uintptr_t)bbRenderTargetTex_;
1953
case NativeObject::BACKBUFFER_DEPTH_TEX:
1954
return (uint64_t)(uintptr_t)bbDepthStencilTex_.Get();
1955
case NativeObject::BACKBUFFER_COLOR_VIEW:
1956
return (uint64_t)(uintptr_t)bbRenderTargetView_;
1957
case NativeObject::BACKBUFFER_DEPTH_VIEW:
1958
return (uint64_t)(uintptr_t)bbDepthStencilView_.Get();
1959
case NativeObject::FEATURE_LEVEL:
1960
return (uint64_t)(uintptr_t)featureLevel_;
1961
case NativeObject::TEXTURE_VIEW:
1962
return (uint64_t)(((D3D11Texture *)srcObject)->View());
1963
default:
1964
return 0;
1965
}
1966
}
1967
1968
void D3D11DrawContext::GetFramebufferDimensions(Framebuffer *fbo, int *w, int *h) {
1969
D3D11Framebuffer *fb = (D3D11Framebuffer *)fbo;
1970
if (fb) {
1971
*w = fb->Width();
1972
*h = fb->Height();
1973
} else {
1974
*w = bbWidth_;
1975
*h = bbHeight_;
1976
}
1977
}
1978
1979
DrawContext *T3DCreateD3D11Context(ComPtr<ID3D11Device> device, ComPtr<ID3D11DeviceContext> context, ComPtr<ID3D11Device1> device1, ComPtr<ID3D11DeviceContext1> context1, ComPtr<IDXGISwapChain> swapChain, D3D_FEATURE_LEVEL featureLevel, HWND hWnd, const std::vector<std::string> &adapterNames, int maxInflightFrames) {
1980
return new D3D11DrawContext(device, context, device1, context1, swapChain, featureLevel, hWnd, adapterNames, maxInflightFrames);
1981
}
1982
1983
} // namespace Draw
1984
1985