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