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