CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
hrydgard

CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!

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