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