CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
hrydgard

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

GitHub Repository: hrydgard/ppsspp
Path: blob/master/Common/GPU/D3D9/thin3d_d3d9.cpp
Views: 1401
1
#include <vector>
2
#include <cstdio>
3
#include <cstdint>
4
5
#include "ppsspp_config.h"
6
7
#ifdef _DEBUG
8
#define D3D_DEBUG_INFO
9
#endif
10
11
#include <d3d9.h>
12
#ifdef USE_CRT_DBG
13
#undef new
14
#endif
15
16
#include <D3Dcompiler.h>
17
#include "Common/GPU/D3D9/D3DCompilerLoader.h"
18
19
#ifndef D3DXERR_INVALIDDATA
20
#define D3DXERR_INVALIDDATA 0x88760b59
21
#endif
22
23
#include "Common/Math/lin/matrix4x4.h"
24
#include "Common/GPU/thin3d.h"
25
#include "Common/GPU/D3D9/D3D9StateCache.h"
26
#include "Common/OSVersion.h"
27
#include "Common/StringUtils.h"
28
#include "Common/TimeUtil.h"
29
30
#include "Common/Log.h"
31
#include <wrl/client.h>
32
33
using namespace Microsoft::WRL;
34
35
namespace Draw {
36
37
static constexpr int MAX_BOUND_TEXTURES = 8;
38
39
// Could be declared as u8
40
static const D3DCMPFUNC compareToD3D9[] = {
41
D3DCMP_NEVER,
42
D3DCMP_LESS,
43
D3DCMP_EQUAL,
44
D3DCMP_LESSEQUAL,
45
D3DCMP_GREATER,
46
D3DCMP_NOTEQUAL,
47
D3DCMP_GREATEREQUAL,
48
D3DCMP_ALWAYS
49
};
50
51
// Could be declared as u8
52
static const D3DBLENDOP blendEqToD3D9[] = {
53
D3DBLENDOP_ADD,
54
D3DBLENDOP_SUBTRACT,
55
D3DBLENDOP_REVSUBTRACT,
56
D3DBLENDOP_MIN,
57
D3DBLENDOP_MAX,
58
};
59
60
// Could be declared as u8
61
static const D3DBLEND blendFactorToD3D9[] = {
62
D3DBLEND_ZERO,
63
D3DBLEND_ONE,
64
D3DBLEND_SRCCOLOR,
65
D3DBLEND_INVSRCCOLOR,
66
D3DBLEND_DESTCOLOR,
67
D3DBLEND_INVDESTCOLOR,
68
D3DBLEND_SRCALPHA,
69
D3DBLEND_INVSRCALPHA,
70
D3DBLEND_DESTALPHA,
71
D3DBLEND_INVDESTALPHA,
72
D3DBLEND_BLENDFACTOR,
73
D3DBLEND_INVBLENDFACTOR,
74
D3DBLEND_BLENDFACTOR,
75
D3DBLEND_INVBLENDFACTOR,
76
D3DBLEND_ZERO,
77
D3DBLEND_ZERO,
78
D3DBLEND_ZERO,
79
D3DBLEND_ZERO,
80
};
81
82
static const D3DTEXTUREADDRESS texWrapToD3D9[] = {
83
D3DTADDRESS_WRAP,
84
D3DTADDRESS_MIRROR,
85
D3DTADDRESS_CLAMP,
86
D3DTADDRESS_BORDER,
87
};
88
89
static const D3DTEXTUREFILTERTYPE texFilterToD3D9[] = {
90
D3DTEXF_POINT,
91
D3DTEXF_LINEAR,
92
};
93
94
static const D3DPRIMITIVETYPE primToD3D9[] = {
95
D3DPT_POINTLIST,
96
D3DPT_LINELIST,
97
D3DPT_LINESTRIP,
98
D3DPT_TRIANGLELIST,
99
D3DPT_TRIANGLESTRIP,
100
D3DPT_TRIANGLEFAN,
101
// These aren't available.
102
D3DPT_POINTLIST, // tess
103
D3DPT_POINTLIST, // geom ...
104
D3DPT_POINTLIST,
105
D3DPT_POINTLIST,
106
D3DPT_POINTLIST,
107
};
108
109
static const D3DSTENCILOP stencilOpToD3D9[] = {
110
D3DSTENCILOP_KEEP,
111
D3DSTENCILOP_ZERO,
112
D3DSTENCILOP_REPLACE,
113
D3DSTENCILOP_INCRSAT,
114
D3DSTENCILOP_DECRSAT,
115
D3DSTENCILOP_INVERT,
116
D3DSTENCILOP_INCR,
117
D3DSTENCILOP_DECR,
118
};
119
120
static D3DFORMAT FormatToD3DFMT(DataFormat fmt) {
121
switch (fmt) {
122
case DataFormat::R16_UNORM: return D3DFMT_L16; // closest match, should be a fine substitution if we ignore channels except R.
123
case DataFormat::R8G8B8A8_UNORM: return D3DFMT_A8R8G8B8;
124
case DataFormat::B8G8R8A8_UNORM: return D3DFMT_A8R8G8B8;
125
case DataFormat::R4G4B4A4_UNORM_PACK16: return D3DFMT_A4R4G4B4; // emulated
126
case DataFormat::B4G4R4A4_UNORM_PACK16: return D3DFMT_A4R4G4B4; // native
127
case DataFormat::A4R4G4B4_UNORM_PACK16: return D3DFMT_A4R4G4B4; // emulated
128
case DataFormat::R5G6B5_UNORM_PACK16: return D3DFMT_R5G6B5;
129
case DataFormat::A1R5G5B5_UNORM_PACK16: return D3DFMT_A1R5G5B5;
130
case DataFormat::D24_S8: return D3DFMT_D24S8;
131
case DataFormat::D16: return D3DFMT_D16;
132
case DataFormat::BC1_RGBA_UNORM_BLOCK: return D3DFMT_DXT1;
133
case DataFormat::BC2_UNORM_BLOCK: return D3DFMT_DXT3; // DXT3 is indeed BC2.
134
case DataFormat::BC3_UNORM_BLOCK: return D3DFMT_DXT5; // DXT5 is indeed BC3
135
default: return D3DFMT_UNKNOWN;
136
}
137
}
138
139
static int FormatToD3DDeclType(DataFormat type) {
140
switch (type) {
141
case DataFormat::R32_FLOAT: return D3DDECLTYPE_FLOAT1;
142
case DataFormat::R32G32_FLOAT: return D3DDECLTYPE_FLOAT2;
143
case DataFormat::R32G32B32_FLOAT: return D3DDECLTYPE_FLOAT3;
144
case DataFormat::R32G32B32A32_FLOAT: return D3DDECLTYPE_FLOAT4;
145
case DataFormat::R8G8B8A8_UNORM: return D3DDECLTYPE_UBYTE4N; // D3DCOLOR has a different byte ordering.
146
default: return D3DDECLTYPE_UNUSED;
147
}
148
}
149
150
class D3D9Buffer;
151
152
class D3D9DepthStencilState : public DepthStencilState {
153
public:
154
BOOL depthTestEnabled;
155
BOOL depthWriteEnabled;
156
D3DCMPFUNC depthCompare;
157
BOOL stencilEnabled;
158
D3DSTENCILOP stencilFail;
159
D3DSTENCILOP stencilZFail;
160
D3DSTENCILOP stencilPass;
161
D3DCMPFUNC stencilCompareOp;
162
163
void Apply(LPDIRECT3DDEVICE9 device, uint8_t stencilRef, uint8_t stencilWriteMask, uint8_t stencilCompareMask) {
164
dxstate.depthTest.set(depthTestEnabled);
165
if (depthTestEnabled) {
166
dxstate.depthWrite.set(depthWriteEnabled);
167
dxstate.depthFunc.set(depthCompare);
168
}
169
dxstate.stencilTest.set(stencilEnabled);
170
if (stencilEnabled) {
171
dxstate.stencilOp.set(stencilFail, stencilZFail, stencilPass);
172
dxstate.stencilFunc.set(stencilCompareOp);
173
dxstate.stencilRef.set(stencilRef);
174
dxstate.stencilCompareMask.set(stencilCompareMask);
175
dxstate.stencilWriteMask.set(stencilWriteMask);
176
}
177
}
178
};
179
180
class D3D9RasterState : public RasterState {
181
public:
182
DWORD cullMode; // D3DCULL_*
183
184
void Apply(LPDIRECT3DDEVICE9 device) {
185
dxstate.cullMode.set(cullMode);
186
dxstate.scissorTest.enable();
187
// Force user clipping off.
188
dxstate.clipPlaneEnable.set(0);
189
}
190
};
191
192
class D3D9BlendState : public BlendState {
193
public:
194
bool enabled;
195
D3DBLENDOP eqCol, eqAlpha;
196
D3DBLEND srcCol, srcAlpha, dstCol, dstAlpha;
197
uint32_t colorMask;
198
199
void Apply(LPDIRECT3DDEVICE9 device) {
200
dxstate.blend.set(enabled);
201
dxstate.blendFunc.set(srcCol, dstCol, srcAlpha, dstAlpha);
202
dxstate.blendEquation.set(eqCol, eqAlpha);
203
dxstate.colorMask.set(colorMask);
204
}
205
};
206
207
class D3D9SamplerState : public SamplerState {
208
public:
209
D3DTEXTUREADDRESS wrapS, wrapT;
210
D3DTEXTUREFILTERTYPE magFilt, minFilt, mipFilt;
211
212
void Apply(LPDIRECT3DDEVICE9 device, int index) {
213
if (index == 0) {
214
dxstate.texAddressU.set(wrapS);
215
dxstate.texAddressV.set(wrapT);
216
dxstate.texMagFilter.set(magFilt);
217
dxstate.texMinFilter.set(minFilt);
218
dxstate.texMipFilter.set(mipFilt);
219
} else {
220
pD3Ddevice9->SetSamplerState(index, D3DSAMP_ADDRESSU, wrapS);
221
pD3Ddevice9->SetSamplerState(index, D3DSAMP_ADDRESSV, wrapT);
222
pD3Ddevice9->SetSamplerState(index, D3DSAMP_MAGFILTER, magFilt);
223
pD3Ddevice9->SetSamplerState(index, D3DSAMP_MINFILTER, minFilt);
224
pD3Ddevice9->SetSamplerState(index, D3DSAMP_MIPFILTER, mipFilt);
225
}
226
}
227
};
228
229
class D3D9InputLayout : public InputLayout {
230
public:
231
D3D9InputLayout(LPDIRECT3DDEVICE9 device, const InputLayoutDesc &desc);
232
~D3D9InputLayout() {
233
}
234
int GetStride() const { return stride_; }
235
void Apply(LPDIRECT3DDEVICE9 device) {
236
device->SetVertexDeclaration(decl_.Get());
237
}
238
239
private:
240
ComPtr<IDirect3DVertexDeclaration9> decl_;
241
int stride_;
242
};
243
244
class D3D9ShaderModule : public ShaderModule {
245
public:
246
D3D9ShaderModule(ShaderStage stage, const std::string &tag) : stage_(stage), tag_(tag) {}
247
~D3D9ShaderModule() {
248
}
249
bool Compile(LPDIRECT3DDEVICE9 device, const uint8_t *data, size_t size);
250
void Apply(LPDIRECT3DDEVICE9 device) {
251
if (stage_ == ShaderStage::Fragment) {
252
device->SetPixelShader(pshader_.Get());
253
} else {
254
device->SetVertexShader(vshader_.Get());
255
}
256
}
257
ShaderStage GetStage() const override { return stage_; }
258
259
private:
260
ShaderStage stage_;
261
ComPtr<IDirect3DVertexShader9> vshader_;
262
ComPtr<IDirect3DPixelShader9> pshader_;
263
std::string tag_;
264
};
265
266
class D3D9Pipeline : public Pipeline {
267
public:
268
D3D9Pipeline() {}
269
~D3D9Pipeline() {
270
}
271
272
D3D9ShaderModule *vshader = nullptr;
273
D3D9ShaderModule *pshader = nullptr;
274
275
D3DPRIMITIVETYPE prim{};
276
AutoRef<D3D9InputLayout> inputLayout;
277
AutoRef<D3D9DepthStencilState> depthStencil;
278
AutoRef<D3D9BlendState> blend;
279
AutoRef<D3D9RasterState> raster;
280
UniformBufferDesc dynamicUniforms{};
281
282
void Apply(LPDIRECT3DDEVICE9 device, uint8_t stencilRef, uint8_t stencilWriteMask, uint8_t stencilCompareMask);
283
};
284
285
class D3D9Texture : public Texture {
286
public:
287
D3D9Texture(LPDIRECT3DDEVICE9 device, LPDIRECT3DDEVICE9EX deviceEx, const TextureDesc &desc);
288
~D3D9Texture();
289
void SetToSampler(LPDIRECT3DDEVICE9 device, int sampler);
290
LPDIRECT3DBASETEXTURE9 TexturePtr() const {
291
// TODO: Cleanup
292
if (tex_) {
293
return tex_.Get();
294
} else if (volTex_) {
295
return volTex_.Get();
296
} else if (cubeTex_) {
297
return cubeTex_.Get();
298
} else {
299
return nullptr;
300
}
301
}
302
void UpdateTextureLevels(const uint8_t * const *data, int numLevels, TextureCallback initDataCallback);
303
304
private:
305
void SetImageData(int x, int y, int z, int width, int height, int depth, int level, int stride, const uint8_t *data, TextureCallback initDataCallback);
306
bool Create(const TextureDesc &desc);
307
ComPtr<IDirect3DDevice9> device_;
308
ComPtr<IDirect3DDevice9Ex> deviceEx_;
309
TextureType type_;
310
D3DFORMAT d3dfmt_;
311
ComPtr<IDirect3DTexture9> tex_;
312
ComPtr<IDirect3DVolumeTexture9> volTex_;
313
ComPtr<IDirect3DCubeTexture9> cubeTex_;
314
};
315
316
D3D9Texture::D3D9Texture(LPDIRECT3DDEVICE9 device, LPDIRECT3DDEVICE9EX deviceEx, const TextureDesc &desc)
317
: device_(device), deviceEx_(deviceEx), tex_(nullptr), volTex_(nullptr), cubeTex_(nullptr) {
318
Create(desc);
319
}
320
321
D3D9Texture::~D3D9Texture() {
322
}
323
324
bool D3D9Texture::Create(const TextureDesc &desc) {
325
width_ = desc.width;
326
height_ = desc.height;
327
depth_ = desc.depth;
328
type_ = desc.type;
329
format_ = desc.format;
330
tex_ = nullptr;
331
d3dfmt_ = FormatToD3DFMT(desc.format);
332
333
if (d3dfmt_ == D3DFMT_UNKNOWN) {
334
return false;
335
}
336
HRESULT hr = E_FAIL;
337
338
D3DPOOL pool = D3DPOOL_MANAGED;
339
int usage = 0;
340
if (deviceEx_ != nullptr) {
341
pool = D3DPOOL_DEFAULT;
342
usage = D3DUSAGE_DYNAMIC;
343
}
344
if (desc.generateMips)
345
usage |= D3DUSAGE_AUTOGENMIPMAP;
346
switch (type_) {
347
case TextureType::LINEAR1D:
348
case TextureType::LINEAR2D:
349
hr = device_->CreateTexture(desc.width, desc.height, desc.generateMips ? 0 : desc.mipLevels, usage, d3dfmt_, pool, &tex_, NULL);
350
break;
351
case TextureType::LINEAR3D:
352
hr = device_->CreateVolumeTexture(desc.width, desc.height, desc.depth, desc.mipLevels, usage, d3dfmt_, pool, &volTex_, NULL);
353
break;
354
case TextureType::CUBE:
355
hr = device_->CreateCubeTexture(desc.width, desc.mipLevels, usage, d3dfmt_, pool, &cubeTex_, NULL);
356
break;
357
}
358
if (FAILED(hr)) {
359
ERROR_LOG(Log::G3D, "D3D9 Texture creation failed");
360
return false;
361
}
362
363
if (desc.initData.size()) {
364
// In D3D9, after setting D3DUSAGE_AUTOGENMIPS, we can only access the top layer. The rest will be
365
// automatically generated.
366
int numLevels = desc.generateMips ? 1 : (int)desc.initData.size();
367
UpdateTextureLevels(desc.initData.data(), numLevels, desc.initDataCallback);
368
}
369
return true;
370
}
371
372
void D3D9Texture::UpdateTextureLevels(const uint8_t * const *data, int numLevels, TextureCallback initDataCallback) {
373
int w = width_;
374
int h = height_;
375
int d = depth_;
376
for (int i = 0; i < numLevels; i++) {
377
SetImageData(0, 0, 0, w, h, d, i, 0, data[i], initDataCallback);
378
w = (w + 1) / 2;
379
h = (h + 1) / 2;
380
d = (d + 1) / 2;
381
}
382
}
383
384
// Just switches R and G.
385
inline uint32_t Shuffle8888(uint32_t x) {
386
return (x & 0xFF00FF00) | ((x >> 16) & 0xFF) | ((x << 16) & 0xFF0000);
387
}
388
389
void D3D9Texture::SetImageData(int x, int y, int z, int width, int height, int depth, int level, int stride, const uint8_t *data, TextureCallback callback) {
390
if (!tex_)
391
return;
392
393
if (level == 0) {
394
width_ = width;
395
height_ = height;
396
depth_ = depth;
397
}
398
399
if (!stride) {
400
stride = width * (int)DataFormatSizeInBytes(format_);
401
}
402
403
switch (type_) {
404
case TextureType::LINEAR2D:
405
{
406
D3DLOCKED_RECT rect;
407
if (x == 0 && y == 0) {
408
tex_->LockRect(level, &rect, NULL, D3DLOCK_DISCARD);
409
410
if (callback) {
411
if (callback((uint8_t *)rect.pBits, data, width, height, depth, rect.Pitch, height * rect.Pitch)) {
412
// Now this is the source. All conversions below support in-place.
413
data = (const uint8_t *)rect.pBits;
414
stride = rect.Pitch;
415
}
416
}
417
418
for (int i = 0; i < height; i++) {
419
uint8_t *dest = (uint8_t *)rect.pBits + rect.Pitch * i;
420
const uint8_t *source = data + stride * i;
421
int j;
422
switch (format_) {
423
case DataFormat::B4G4R4A4_UNORM_PACK16: // We emulate support for this format.
424
for (j = 0; j < width; j++) {
425
uint16_t color = ((const uint16_t *)source)[j];
426
((uint16_t *)dest)[j] = (color << 12) | (color >> 4);
427
}
428
break;
429
case DataFormat::A4R4G4B4_UNORM_PACK16:
430
case DataFormat::A1R5G5B5_UNORM_PACK16:
431
case DataFormat::R5G6B5_UNORM_PACK16:
432
// Native
433
if (data != rect.pBits)
434
memcpy(dest, source, width * sizeof(uint16_t));
435
break;
436
437
case DataFormat::R8G8B8A8_UNORM:
438
for (j = 0; j < width; j++) {
439
((uint32_t *)dest)[j] = Shuffle8888(((uint32_t *)source)[j]);
440
}
441
break;
442
443
case DataFormat::B8G8R8A8_UNORM:
444
if (data != rect.pBits)
445
memcpy(dest, source, sizeof(uint32_t) * width);
446
break;
447
448
case DataFormat::R8_UNORM:
449
if (data != rect.pBits)
450
memcpy(dest, source, width);
451
break;
452
453
case DataFormat::R16_UNORM:
454
if (data != rect.pBits)
455
memcpy(dest, source, sizeof(uint16_t) * width);
456
break;
457
458
default:
459
// Unhandled data format copy.
460
DebugBreak();
461
break;
462
}
463
}
464
tex_->UnlockRect(level);
465
}
466
break;
467
}
468
469
default:
470
ERROR_LOG(Log::G3D, "Non-LINEAR2D textures not yet supported");
471
break;
472
}
473
}
474
475
void D3D9Texture::SetToSampler(LPDIRECT3DDEVICE9 device, int sampler) {
476
switch (type_) {
477
case TextureType::LINEAR1D:
478
case TextureType::LINEAR2D:
479
device->SetTexture(sampler, tex_.Get());
480
break;
481
482
case TextureType::LINEAR3D:
483
device->SetTexture(sampler, volTex_.Get());
484
break;
485
486
case TextureType::CUBE:
487
device->SetTexture(sampler, cubeTex_.Get());
488
break;
489
}
490
}
491
492
class D3D9Context : public DrawContext {
493
public:
494
D3D9Context(IDirect3D9 *d3d, IDirect3D9Ex *d3dEx, int adapterId, IDirect3DDevice9 *device, IDirect3DDevice9Ex *deviceEx);
495
~D3D9Context();
496
497
const DeviceCaps &GetDeviceCaps() const override {
498
return caps_;
499
}
500
uint32_t GetSupportedShaderLanguages() const override {
501
return (uint32_t)ShaderLanguage::HLSL_D3D9;
502
}
503
uint32_t GetDataFormatSupport(DataFormat fmt) const override;
504
505
ShaderModule *CreateShaderModule(ShaderStage stage, ShaderLanguage language, const uint8_t *data, size_t dataSize, const char *tag) override;
506
DepthStencilState *CreateDepthStencilState(const DepthStencilStateDesc &desc) override;
507
BlendState *CreateBlendState(const BlendStateDesc &desc) override;
508
SamplerState *CreateSamplerState(const SamplerStateDesc &desc) override;
509
RasterState *CreateRasterState(const RasterStateDesc &desc) override;
510
Buffer *CreateBuffer(size_t size, uint32_t usageFlags) override;
511
Pipeline *CreateGraphicsPipeline(const PipelineDesc &desc, const char *tag) override;
512
InputLayout *CreateInputLayout(const InputLayoutDesc &desc) override;
513
Texture *CreateTexture(const TextureDesc &desc) override;
514
515
Framebuffer *CreateFramebuffer(const FramebufferDesc &desc) override;
516
517
void UpdateBuffer(Buffer *buffer, const uint8_t *data, size_t offset, size_t size, UpdateBufferFlags flags) override;
518
void UpdateTextureLevels(Texture *texture, const uint8_t **data, TextureCallback initDataCallback, int numLevels) override;
519
520
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 {
521
// Not implemented
522
}
523
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;
524
bool CopyFramebufferToMemory(Framebuffer *src, int channelBits, int x, int y, int w, int h, Draw::DataFormat format, void *pixels, int pixelStride, ReadbackMode mode, const char *tag) override;
525
526
// These functions should be self explanatory.
527
void BindFramebufferAsRenderTarget(Framebuffer *fbo, const RenderPassInfo &rp, const char *tag) override;
528
void BindFramebufferAsTexture(Framebuffer *fbo, int binding, FBChannel channelBit, int layer) override;
529
530
uintptr_t GetFramebufferAPITexture(Framebuffer *fbo, int channelBits, int attachment) override;
531
532
void GetFramebufferDimensions(Framebuffer *fbo, int *w, int *h) override;
533
534
void BindTextures(int start, int count, Texture **textures, TextureBindFlags flags) override;
535
void BindNativeTexture(int index, void *nativeTexture) override;
536
537
void BindSamplerStates(int start, int count, SamplerState **states) override {
538
_assert_(start + count <= MAX_BOUND_TEXTURES);
539
for (int i = 0; i < count; ++i) {
540
D3D9SamplerState *s = static_cast<D3D9SamplerState *>(states[i]);
541
if (s)
542
s->Apply(device_, start + i);
543
}
544
}
545
void BindVertexBuffer(Buffer *vertexBuffer, int offset) override {
546
curVBuffer_ = (D3D9Buffer *)vertexBuffer;
547
curVBufferOffset_ = offset;
548
}
549
void BindIndexBuffer(Buffer *indexBuffer, int offset) override {
550
curIBuffer_ = (D3D9Buffer *)indexBuffer;
551
curIBufferOffset_ = offset;
552
}
553
554
void BindPipeline(Pipeline *pipeline) override {
555
curPipeline_ = (D3D9Pipeline *)pipeline;
556
}
557
558
void BeginFrame(Draw::DebugFlags debugFlags) override;
559
void EndFrame() override;
560
void Present(PresentMode presentMode, int vblanks) override;
561
562
int GetFrameCount() override { return frameCount_; }
563
564
void UpdateDynamicUniformBuffer(const void *ub, size_t size) override;
565
566
// Raster state
567
void SetScissorRect(int left, int top, int width, int height) override;
568
void SetViewport(const Viewport &viewport) override;
569
void SetBlendFactor(float color[4]) override;
570
void SetStencilParams(uint8_t refValue, uint8_t writeMask, uint8_t compareMask) override;
571
572
void ApplyDynamicState();
573
void Draw(int vertexCount, int offset) override;
574
void DrawIndexed(int vertexCount, int offset) override;
575
void DrawUP(const void *vdata, int vertexCount) override;
576
void Clear(int mask, uint32_t colorval, float depthVal, int stencilVal) override;
577
578
uint64_t GetNativeObject(NativeObject obj, void *srcObject) override {
579
switch (obj) {
580
case NativeObject::CONTEXT:
581
return (uint64_t)(uintptr_t)d3d_;
582
case NativeObject::DEVICE:
583
return (uint64_t)(uintptr_t)device_;
584
case NativeObject::DEVICE_EX:
585
return (uint64_t)(uintptr_t)deviceEx_;
586
case NativeObject::TEXTURE_VIEW:
587
return (uint64_t)(((D3D9Texture *)srcObject)->TexturePtr());
588
default:
589
return 0;
590
}
591
}
592
593
std::string GetInfoString(InfoField info) const override {
594
switch (info) {
595
case InfoField::APIVERSION: return "DirectX 9.0";
596
case InfoField::VENDORSTRING: return identifier_.Description;
597
case InfoField::VENDOR: return "";
598
case InfoField::DRIVER: return identifier_.Driver; // eh, sort of
599
case InfoField::SHADELANGVERSION: return shadeLangVersion_;
600
case InfoField::APINAME: return "Direct3D 9";
601
default: return "?";
602
}
603
}
604
605
void HandleEvent(Event ev, int width, int height, void *param1, void *param2) override;
606
607
void Invalidate(InvalidationFlags flags) override;
608
609
void SetInvalidationCallback(InvalidationCallback callback) override {
610
invalidationCallback_ = callback;
611
}
612
613
private:
614
LPDIRECT3D9 d3d_;
615
LPDIRECT3D9EX d3dEx_;
616
LPDIRECT3DDEVICE9 device_;
617
LPDIRECT3DDEVICE9EX deviceEx_;
618
int adapterId_ = -1;
619
D3DADAPTER_IDENTIFIER9 identifier_{};
620
D3DCAPS9 d3dCaps_;
621
char shadeLangVersion_[64]{};
622
DeviceCaps caps_{};
623
int frameCount_ = FRAME_TIME_HISTORY_LENGTH;
624
625
// Bound state
626
AutoRef<D3D9Pipeline> curPipeline_;
627
AutoRef<D3D9Buffer> curVBuffer_;
628
int curVBufferOffset_ = 0;
629
AutoRef<D3D9Buffer> curIBuffer_;
630
int curIBufferOffset_ = 0;
631
AutoRef<Framebuffer> curRenderTarget_;
632
633
u8 stencilRefValue_ = 0;
634
u8 stencilCompareMask_ = 0xFF;
635
u8 stencilWriteMask_ = 0xFF;
636
637
// Framebuffer state
638
ComPtr<IDirect3DSurface9> deviceRTsurf;
639
ComPtr<IDirect3DSurface9> deviceDSsurf;
640
bool supportsINTZ = false;
641
642
// Dynamic state
643
uint8_t stencilRef_ = 0;
644
645
InvalidationCallback invalidationCallback_;
646
};
647
648
void D3D9Context::Invalidate(InvalidationFlags flags) {
649
if (flags & InvalidationFlags::CACHED_RENDER_STATE) {
650
curPipeline_ = nullptr;
651
}
652
}
653
654
// TODO: Move this detection elsewhere when it's needed elsewhere, not before. It's ugly.
655
// Source: https://envytools.readthedocs.io/en/latest/hw/pciid.html#gf100
656
enum NVIDIAGeneration {
657
NV_PRE_KEPLER,
658
NV_KEPLER,
659
NV_MAXWELL,
660
NV_PASCAL,
661
NV_VOLTA,
662
NV_TURING, // or later
663
};
664
665
static NVIDIAGeneration NVIDIAGetDeviceGeneration(int deviceID) {
666
if (deviceID >= 0x1180 && deviceID <= 0x11bf)
667
return NV_KEPLER; // GK104
668
if (deviceID >= 0x11c0 && deviceID <= 0x11fa)
669
return NV_KEPLER; // GK106
670
if (deviceID >= 0x0fc0 && deviceID <= 0x0fff)
671
return NV_KEPLER; // GK107
672
if (deviceID >= 0x1003 && deviceID <= 0x1028)
673
return NV_KEPLER; // GK110(B)
674
if (deviceID >= 0x1280 && deviceID <= 0x12ba)
675
return NV_KEPLER; // GK208
676
if (deviceID >= 0x1381 && deviceID <= 0x13b0)
677
return NV_MAXWELL; // GM107
678
if (deviceID >= 0x1340 && deviceID <= 0x134d)
679
return NV_MAXWELL; // GM108
680
if (deviceID >= 0x13c0 && deviceID <= 0x13d9)
681
return NV_MAXWELL; // GM204
682
if (deviceID >= 0x1401 && deviceID <= 0x1427)
683
return NV_MAXWELL; // GM206
684
if (deviceID >= 0x15f7 && deviceID <= 0x15f9)
685
return NV_PASCAL; // GP100
686
if (deviceID >= 0x15f7 && deviceID <= 0x15f9)
687
return NV_PASCAL; // GP100
688
if (deviceID >= 0x1b00 && deviceID <= 0x1b38)
689
return NV_PASCAL; // GP102
690
if (deviceID >= 0x1b80 && deviceID <= 0x1be1)
691
return NV_PASCAL; // GP104
692
if (deviceID >= 0x1c02 && deviceID <= 0x1c62)
693
return NV_PASCAL; // GP106
694
if (deviceID >= 0x1c81 && deviceID <= 0x1c92)
695
return NV_PASCAL; // GP107
696
if (deviceID >= 0x1d01 && deviceID <= 0x1d12)
697
return NV_PASCAL; // GP108
698
if (deviceID >= 0x1d81 && deviceID <= 0x1dba)
699
return NV_VOLTA; // GV100
700
if (deviceID >= 0x1e02 && deviceID <= 0x1e3c)
701
return NV_TURING; // TU102
702
if (deviceID >= 0x1e82 && deviceID <= 0x1ed0)
703
return NV_TURING; // TU104
704
if (deviceID >= 0x1f02 && deviceID <= 0x1f51)
705
return NV_TURING; // TU104
706
if (deviceID >= 0x1e02)
707
return NV_TURING; // More TU models or later, probably.
708
return NV_PRE_KEPLER;
709
}
710
711
#define FB_DIV 1
712
#define FOURCC_INTZ ((D3DFORMAT)(MAKEFOURCC('I', 'N', 'T', 'Z')))
713
714
D3D9Context::D3D9Context(IDirect3D9 *d3d, IDirect3D9Ex *d3dEx, int adapterId, IDirect3DDevice9 *device, IDirect3DDevice9Ex *deviceEx)
715
: d3d_(d3d), d3dEx_(d3dEx), device_(device), deviceEx_(deviceEx), adapterId_(adapterId), caps_{} {
716
if (FAILED(d3d->GetAdapterIdentifier(adapterId, 0, &identifier_))) {
717
ERROR_LOG(Log::G3D, "Failed to get adapter identifier: %d", adapterId);
718
}
719
switch (identifier_.VendorId) {
720
case 0x10DE: caps_.vendor = GPUVendor::VENDOR_NVIDIA; break;
721
case 0x1002:
722
case 0x1022: caps_.vendor = GPUVendor::VENDOR_AMD; break;
723
case 0x163C:
724
case 0x8086:
725
case 0x8087: caps_.vendor = GPUVendor::VENDOR_INTEL; break;
726
default:
727
caps_.vendor = GPUVendor::VENDOR_UNKNOWN;
728
}
729
730
D3DCAPS9 caps;
731
ZeroMemory(&caps, sizeof(caps));
732
HRESULT result = 0;
733
if (deviceEx_) {
734
result = deviceEx_->GetDeviceCaps(&caps);
735
} else {
736
result = device_->GetDeviceCaps(&caps);
737
}
738
739
if (SUCCEEDED(result)) {
740
snprintf(shadeLangVersion_, sizeof(shadeLangVersion_), "PS: %04x VS: %04x", d3dCaps_.PixelShaderVersion & 0xFFFF, d3dCaps_.VertexShaderVersion & 0xFFFF);
741
} else {
742
WARN_LOG(Log::G3D, "Direct3D9: Failed to get the device caps!");
743
truncate_cpy(shadeLangVersion_, "N/A");
744
}
745
746
caps_.deviceID = identifier_.DeviceId;
747
caps_.depthRangeMinusOneToOne = false;
748
caps_.preferredDepthBufferFormat = DataFormat::D24_S8;
749
caps_.dualSourceBlend = false;
750
caps_.tesselationShaderSupported = false;
751
caps_.framebufferBlitSupported = true;
752
caps_.framebufferCopySupported = false;
753
caps_.framebufferDepthBlitSupported = false;
754
caps_.framebufferStencilBlitSupported = false;
755
caps_.framebufferDepthCopySupported = false;
756
caps_.framebufferSeparateDepthCopySupported = false;
757
caps_.texture3DSupported = true;
758
caps_.fragmentShaderDepthWriteSupported = true;
759
caps_.requiresHalfPixelOffset = true;
760
caps_.fragmentShaderStencilWriteSupported = false;
761
caps_.blendMinMaxSupported = true;
762
caps_.isTilingGPU = false;
763
caps_.multiSampleLevelsMask = 1; // More could be supported with some work.
764
765
caps_.clipPlanesSupported = caps.MaxUserClipPlanes;
766
caps_.presentInstantModeChange = false;
767
caps_.presentMaxInterval = 1;
768
caps_.presentModesSupported = PresentMode::FIFO;
769
770
caps_.provokingVertexLast = false; // D3D has it first, unfortunately (and no way to change it).
771
772
if ((caps.RasterCaps & D3DPRASTERCAPS_ANISOTROPY) != 0 && caps.MaxAnisotropy > 1) {
773
caps_.anisoSupported = true;
774
}
775
if ((caps.TextureCaps & (D3DPTEXTURECAPS_NONPOW2CONDITIONAL | D3DPTEXTURECAPS_POW2)) == 0) {
776
caps_.textureNPOTFullySupported = true;
777
}
778
779
caps_.supportsD3D9 = true;
780
if (!strcmp(identifier_.Description, "Intel(R) Iris(R) Xe Graphics")) {
781
caps_.supportsD3D9 = false;
782
}
783
784
// VS range culling (killing triangles in the vertex shader using NaN) causes problems on Intel.
785
// Also causes problems on old NVIDIA.
786
switch (caps_.vendor) {
787
case Draw::GPUVendor::VENDOR_INTEL:
788
bugs_.Infest(Bugs::BROKEN_NAN_IN_CONDITIONAL);
789
break;
790
case Draw::GPUVendor::VENDOR_NVIDIA:
791
// Older NVIDIAs don't seem to like NaNs in their DX9 vertex shaders.
792
// No idea if KEPLER is the right cutoff, but let's go with it.
793
if (NVIDIAGetDeviceGeneration(caps_.deviceID) < NV_KEPLER) {
794
bugs_.Infest(Bugs::BROKEN_NAN_IN_CONDITIONAL);
795
}
796
break;
797
}
798
799
if (d3d) {
800
D3DDISPLAYMODE displayMode;
801
d3d->GetAdapterDisplayMode(D3DADAPTER_DEFAULT, &displayMode);
802
803
// To be safe, make sure both the display format and the FBO format support INTZ.
804
HRESULT displayINTZ = d3d->CheckDeviceFormat(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, displayMode.Format, D3DUSAGE_DEPTHSTENCIL, D3DRTYPE_TEXTURE, FOURCC_INTZ);
805
HRESULT displayINTY = d3d->CheckDeviceFormat(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, displayMode.Format, D3DUSAGE_DEPTHSTENCIL, D3DRTYPE_TEXTURE, ((D3DFORMAT)(MAKEFOURCC('I', 'N', 'T', 'Y'))));
806
// Try to prevent INTZ on older Intel drivers that claim support.
807
supportsINTZ = SUCCEEDED(displayINTZ) && !SUCCEEDED(displayINTY) && IsWin7OrHigher();
808
}
809
caps_.textureDepthSupported = supportsINTZ;
810
811
shaderLanguageDesc_.Init(HLSL_D3D9);
812
813
dxstate.Restore();
814
}
815
816
D3D9Context::~D3D9Context() {
817
DestroyPresets();
818
}
819
820
ShaderModule *D3D9Context::CreateShaderModule(ShaderStage stage, ShaderLanguage language, const uint8_t *data, size_t size, const char *tag) {
821
D3D9ShaderModule *shader = new D3D9ShaderModule(stage, tag);
822
if (shader->Compile(device_, data, size)) {
823
return shader;
824
} else {
825
delete shader;
826
return NULL;
827
}
828
}
829
830
Pipeline *D3D9Context::CreateGraphicsPipeline(const PipelineDesc &desc, const char *tag) {
831
if (!desc.shaders.size()) {
832
ERROR_LOG(Log::G3D, "Pipeline %s requires at least one shader", tag);
833
return NULL;
834
}
835
D3D9Pipeline *pipeline = new D3D9Pipeline();
836
for (auto iter : desc.shaders) {
837
if (!iter) {
838
ERROR_LOG(Log::G3D, "NULL shader passed to CreateGraphicsPipeline(%s)", tag);
839
delete pipeline;
840
return NULL;
841
}
842
if (iter->GetStage() == ShaderStage::Fragment) {
843
pipeline->pshader = static_cast<D3D9ShaderModule *>(iter);
844
pipeline->pshader->AddRef();
845
}
846
else if (iter->GetStage() == ShaderStage::Vertex) {
847
pipeline->vshader = static_cast<D3D9ShaderModule *>(iter);
848
pipeline->vshader->AddRef();
849
}
850
}
851
pipeline->prim = primToD3D9[(int)desc.prim];
852
pipeline->depthStencil = (D3D9DepthStencilState *)desc.depthStencil;
853
pipeline->blend = (D3D9BlendState *)desc.blend;
854
pipeline->raster = (D3D9RasterState *)desc.raster;
855
pipeline->inputLayout = (D3D9InputLayout *)desc.inputLayout;
856
if (desc.uniformDesc)
857
pipeline->dynamicUniforms = *desc.uniformDesc;
858
return pipeline;
859
}
860
861
DepthStencilState *D3D9Context::CreateDepthStencilState(const DepthStencilStateDesc &desc) {
862
D3D9DepthStencilState *ds = new D3D9DepthStencilState();
863
ds->depthTestEnabled = desc.depthTestEnabled;
864
ds->depthWriteEnabled = desc.depthWriteEnabled;
865
ds->depthCompare = compareToD3D9[(int)desc.depthCompare];
866
ds->stencilEnabled = desc.stencilEnabled;
867
ds->stencilCompareOp = compareToD3D9[(int)desc.stencil.compareOp];
868
ds->stencilPass = stencilOpToD3D9[(int)desc.stencil.passOp];
869
ds->stencilFail = stencilOpToD3D9[(int)desc.stencil.failOp];
870
ds->stencilZFail = stencilOpToD3D9[(int)desc.stencil.depthFailOp];
871
return ds;
872
}
873
874
InputLayout *D3D9Context::CreateInputLayout(const InputLayoutDesc &desc) {
875
D3D9InputLayout *fmt = new D3D9InputLayout(device_, desc);
876
return fmt;
877
}
878
879
BlendState *D3D9Context::CreateBlendState(const BlendStateDesc &desc) {
880
D3D9BlendState *bs = new D3D9BlendState();
881
bs->enabled = desc.enabled;
882
bs->eqCol = blendEqToD3D9[(int)desc.eqCol];
883
bs->srcCol = blendFactorToD3D9[(int)desc.srcCol];
884
bs->dstCol = blendFactorToD3D9[(int)desc.dstCol];
885
bs->eqAlpha = blendEqToD3D9[(int)desc.eqAlpha];
886
bs->srcAlpha = blendFactorToD3D9[(int)desc.srcAlpha];
887
bs->dstAlpha = blendFactorToD3D9[(int)desc.dstAlpha];
888
bs->colorMask = desc.colorMask;
889
// Ignore logic ops, we don't support them in D3D9
890
return bs;
891
}
892
893
SamplerState *D3D9Context::CreateSamplerState(const SamplerStateDesc &desc) {
894
D3D9SamplerState *samps = new D3D9SamplerState();
895
samps->wrapS = texWrapToD3D9[(int)desc.wrapU];
896
samps->wrapT = texWrapToD3D9[(int)desc.wrapV];
897
samps->magFilt = texFilterToD3D9[(int)desc.magFilter];
898
samps->minFilt = texFilterToD3D9[(int)desc.minFilter];
899
samps->mipFilt = texFilterToD3D9[(int)desc.mipFilter];
900
return samps;
901
}
902
903
RasterState *D3D9Context::CreateRasterState(const RasterStateDesc &desc) {
904
D3D9RasterState *rs = new D3D9RasterState();
905
rs->cullMode = D3DCULL_NONE;
906
if (desc.cull == CullMode::NONE) {
907
return rs;
908
}
909
switch (desc.frontFace) {
910
case Facing::CW:
911
switch (desc.cull) {
912
case CullMode::FRONT: rs->cullMode = D3DCULL_CCW; break;
913
case CullMode::BACK: rs->cullMode = D3DCULL_CW; break;
914
}
915
case Facing::CCW:
916
switch (desc.cull) {
917
case CullMode::FRONT: rs->cullMode = D3DCULL_CW; break;
918
case CullMode::BACK: rs->cullMode = D3DCULL_CCW; break;
919
}
920
}
921
return rs;
922
}
923
924
Texture *D3D9Context::CreateTexture(const TextureDesc &desc) {
925
D3D9Texture *tex = new D3D9Texture(device_, deviceEx_, desc);
926
return tex;
927
}
928
929
void D3D9Context::UpdateTextureLevels(Texture *texture, const uint8_t **data, TextureCallback initDataCallback, int numLevels) {
930
D3D9Texture *tex = (D3D9Texture *)texture;
931
tex->UpdateTextureLevels(data, numLevels, initDataCallback);
932
}
933
934
935
void D3D9Context::BindTextures(int start, int count, Texture **textures, TextureBindFlags flags) {
936
_assert_(start + count <= MAX_BOUND_TEXTURES);
937
for (int i = start; i < start + count; i++) {
938
D3D9Texture *tex = static_cast<D3D9Texture *>(textures[i - start]);
939
if (tex) {
940
tex->SetToSampler(device_, i);
941
} else {
942
device_->SetTexture(i, nullptr);
943
}
944
}
945
}
946
947
void D3D9Context::BindNativeTexture(int index, void *nativeTexture) {
948
LPDIRECT3DTEXTURE9 texture = (LPDIRECT3DTEXTURE9)nativeTexture;
949
device_->SetTexture(index, texture);
950
}
951
952
void D3D9Context::BeginFrame(Draw::DebugFlags debugFlags) {
953
FrameTimeData frameTimeData = frameTimeHistory_.Add(frameCount_);
954
frameTimeData.frameBegin = time_now_d();
955
frameTimeData.afterFenceWait = frameTimeData.frameBegin; // no fence wait
956
}
957
958
void D3D9Context::EndFrame() {
959
frameTimeHistory_[frameCount_].firstSubmit = time_now_d();
960
curPipeline_ = nullptr;
961
}
962
963
void D3D9Context::Present(PresentMode presentMode, int vblanks) {
964
frameTimeHistory_[frameCount_].queuePresent = time_now_d();
965
if (deviceEx_) {
966
deviceEx_->EndScene();
967
deviceEx_->PresentEx(NULL, NULL, NULL, NULL, 0);
968
deviceEx_->BeginScene();
969
} else {
970
device_->EndScene();
971
device_->Present(NULL, NULL, NULL, NULL);
972
device_->BeginScene();
973
}
974
frameCount_++;
975
}
976
977
static void SemanticToD3D9UsageAndIndex(int semantic, BYTE *usage, BYTE *index) {
978
*index = 0;
979
switch (semantic) {
980
case SEM_POSITION:
981
*usage = D3DDECLUSAGE_POSITION;
982
break;
983
case SEM_NORMAL:
984
*usage = D3DDECLUSAGE_NORMAL;
985
break;
986
case SEM_TANGENT:
987
*usage = D3DDECLUSAGE_TANGENT;
988
break;
989
case SEM_BINORMAL:
990
*usage = D3DDECLUSAGE_BINORMAL;
991
break;
992
case SEM_COLOR0:
993
*usage = D3DDECLUSAGE_COLOR;
994
break;
995
case SEM_COLOR1:
996
*usage = D3DDECLUSAGE_COLOR;
997
*index = 1;
998
break;
999
case SEM_TEXCOORD0:
1000
*usage = D3DDECLUSAGE_TEXCOORD;
1001
break;
1002
case SEM_TEXCOORD1:
1003
*usage = D3DDECLUSAGE_TEXCOORD;
1004
*index = 1;
1005
break;
1006
}
1007
}
1008
1009
D3D9InputLayout::D3D9InputLayout(LPDIRECT3DDEVICE9 device, const InputLayoutDesc &desc) : decl_(NULL) {
1010
D3DVERTEXELEMENT9 *elements = new D3DVERTEXELEMENT9[desc.attributes.size() + 1];
1011
size_t i;
1012
for (i = 0; i < desc.attributes.size(); i++) {
1013
elements[i].Stream = 0;
1014
elements[i].Offset = desc.attributes[i].offset;
1015
elements[i].Method = D3DDECLMETHOD_DEFAULT;
1016
SemanticToD3D9UsageAndIndex(desc.attributes[i].location, &elements[i].Usage, &elements[i].UsageIndex);
1017
elements[i].Type = FormatToD3DDeclType(desc.attributes[i].format);
1018
}
1019
D3DVERTEXELEMENT9 end = D3DDECL_END();
1020
// Zero the last one.
1021
memcpy(&elements[i], &end, sizeof(elements[i]));
1022
1023
stride_ = desc.stride;
1024
1025
HRESULT hr = device->CreateVertexDeclaration(elements, &decl_);
1026
if (FAILED(hr)) {
1027
ERROR_LOG(Log::G3D, "Error creating vertex decl");
1028
}
1029
delete[] elements;
1030
}
1031
1032
// Simulate a simple buffer type like the other backends have, use the usage flags to create the right internal type.
1033
class D3D9Buffer : public Buffer {
1034
public:
1035
D3D9Buffer(LPDIRECT3DDEVICE9 device, size_t size, uint32_t flags) : vbuffer_(nullptr), ibuffer_(nullptr), maxSize_(size) {
1036
if (flags & BufferUsageFlag::INDEXDATA) {
1037
DWORD usage = D3DUSAGE_DYNAMIC;
1038
device->CreateIndexBuffer((UINT)size, usage, D3DFMT_INDEX16, D3DPOOL_DEFAULT, &ibuffer_, NULL);
1039
} else {
1040
DWORD usage = D3DUSAGE_DYNAMIC;
1041
device->CreateVertexBuffer((UINT)size, usage, 0, D3DPOOL_DEFAULT, &vbuffer_, NULL);
1042
}
1043
}
1044
~D3D9Buffer() {
1045
}
1046
1047
ComPtr<IDirect3DVertexBuffer9> vbuffer_;
1048
ComPtr<IDirect3DIndexBuffer9> ibuffer_;
1049
size_t maxSize_;
1050
};
1051
1052
Buffer *D3D9Context::CreateBuffer(size_t size, uint32_t usageFlags) {
1053
return new D3D9Buffer(device_, size, usageFlags);
1054
}
1055
1056
inline void Transpose4x4(float out[16], const float in[16]) {
1057
for (int i = 0; i < 4; i++) {
1058
for (int j = 0; j < 4; j++) {
1059
out[i * 4 + j] = in[j * 4 + i];
1060
}
1061
}
1062
}
1063
1064
void D3D9Context::UpdateDynamicUniformBuffer(const void *ub, size_t size) {
1065
_assert_(size == curPipeline_->dynamicUniforms.uniformBufferSize);
1066
for (auto &uniform : curPipeline_->dynamicUniforms.uniforms) {
1067
int count = 0;
1068
switch (uniform.type) {
1069
case UniformType::FLOAT1:
1070
case UniformType::FLOAT2:
1071
case UniformType::FLOAT3:
1072
case UniformType::FLOAT4:
1073
count = 1;
1074
break;
1075
case UniformType::MATRIX4X4:
1076
count = 4;
1077
break;
1078
}
1079
const float *srcPtr = (const float *)((const uint8_t *)ub + uniform.offset);
1080
if (uniform.vertexReg != -1) {
1081
float transp[16];
1082
if (count == 4) {
1083
Transpose4x4(transp, srcPtr);
1084
srcPtr = transp;
1085
}
1086
device_->SetVertexShaderConstantF(uniform.vertexReg, srcPtr, count);
1087
}
1088
if (uniform.fragmentReg != -1) {
1089
device_->SetPixelShaderConstantF(uniform.fragmentReg, srcPtr, count);
1090
}
1091
}
1092
}
1093
1094
void D3D9Context::UpdateBuffer(Buffer *buffer, const uint8_t *data, size_t offset, size_t size, UpdateBufferFlags flags) {
1095
D3D9Buffer *buf = (D3D9Buffer *)buffer;
1096
if (!size)
1097
return;
1098
if (offset + size > buf->maxSize_) {
1099
ERROR_LOG(Log::G3D, "Can't SubData with bigger size than buffer was created with");
1100
return;
1101
}
1102
if (buf->vbuffer_) {
1103
void *ptr = nullptr;
1104
HRESULT res = buf->vbuffer_->Lock((UINT)offset, (UINT)size, &ptr, (flags & UPDATE_DISCARD) ? D3DLOCK_DISCARD : 0);
1105
if (!FAILED(res) && ptr) {
1106
memcpy(ptr, data, size);
1107
buf->vbuffer_->Unlock();
1108
}
1109
} else if (buf->ibuffer_) {
1110
void *ptr = nullptr;
1111
HRESULT res = buf->ibuffer_->Lock((UINT)offset, (UINT)size, &ptr, (flags & UPDATE_DISCARD) ? D3DLOCK_DISCARD : 0);
1112
if (!FAILED(res) && ptr) {
1113
memcpy(ptr, data, size);
1114
buf->ibuffer_->Unlock();
1115
}
1116
}
1117
}
1118
1119
void D3D9Pipeline::Apply(LPDIRECT3DDEVICE9 device, uint8_t stencilRef, uint8_t stencilWriteMask, uint8_t stencilCompareMask) {
1120
vshader->Apply(device);
1121
pshader->Apply(device);
1122
blend->Apply(device);
1123
depthStencil->Apply(device, stencilRef, stencilWriteMask, stencilCompareMask);
1124
raster->Apply(device);
1125
}
1126
1127
void D3D9Context::ApplyDynamicState() {
1128
// Apply dynamic state.
1129
if (curPipeline_->depthStencil->stencilEnabled) {
1130
device_->SetRenderState(D3DRS_STENCILREF, (DWORD)stencilRefValue_);
1131
device_->SetRenderState(D3DRS_STENCILWRITEMASK, (DWORD)stencilWriteMask_);
1132
device_->SetRenderState(D3DRS_STENCILMASK, (DWORD)stencilCompareMask_);
1133
}
1134
}
1135
1136
static const int D3DPRIMITIVEVERTEXCOUNT[8][2] = {
1137
{0, 0}, // invalid
1138
{1, 0}, // 1 = D3DPT_POINTLIST,
1139
{2, 0}, // 2 = D3DPT_LINELIST,
1140
{2, 1}, // 3 = D3DPT_LINESTRIP,
1141
{3, 0}, // 4 = D3DPT_TRIANGLELIST,
1142
{1, 2}, // 5 = D3DPT_TRIANGLESTRIP,
1143
{1, 2}, // 6 = D3DPT_TRIANGLEFAN,
1144
};
1145
1146
inline int D3DPrimCount(D3DPRIMITIVETYPE prim, int size) {
1147
return (size / D3DPRIMITIVEVERTEXCOUNT[prim][0]) - D3DPRIMITIVEVERTEXCOUNT[prim][1];
1148
}
1149
1150
void D3D9Context::Draw(int vertexCount, int offset) {
1151
device_->SetStreamSource(0, curVBuffer_->vbuffer_.Get(), curVBufferOffset_, curPipeline_->inputLayout->GetStride());
1152
curPipeline_->inputLayout->Apply(device_);
1153
curPipeline_->Apply(device_, stencilRef_, stencilWriteMask_, stencilCompareMask_);
1154
ApplyDynamicState();
1155
device_->DrawPrimitive(curPipeline_->prim, offset, D3DPrimCount(curPipeline_->prim, vertexCount));
1156
}
1157
1158
void D3D9Context::DrawIndexed(int vertexCount, int offset) {
1159
curPipeline_->inputLayout->Apply(device_);
1160
curPipeline_->Apply(device_, stencilRef_, stencilWriteMask_, stencilCompareMask_);
1161
ApplyDynamicState();
1162
device_->SetStreamSource(0, curVBuffer_->vbuffer_.Get(), curVBufferOffset_, curPipeline_->inputLayout->GetStride());
1163
device_->SetIndices(curIBuffer_->ibuffer_.Get());
1164
device_->DrawIndexedPrimitive(curPipeline_->prim, 0, 0, vertexCount, offset, D3DPrimCount(curPipeline_->prim, vertexCount));
1165
}
1166
1167
void D3D9Context::DrawUP(const void *vdata, int vertexCount) {
1168
curPipeline_->inputLayout->Apply(device_);
1169
curPipeline_->Apply(device_, stencilRef_, stencilWriteMask_, stencilCompareMask_);
1170
ApplyDynamicState();
1171
1172
device_->DrawPrimitiveUP(curPipeline_->prim, D3DPrimCount(curPipeline_->prim, vertexCount), vdata, curPipeline_->inputLayout->GetStride());
1173
}
1174
1175
static uint32_t SwapRB(uint32_t c) {
1176
return (c & 0xFF00FF00) | ((c >> 16) & 0xFF) | ((c << 16) & 0xFF0000);
1177
}
1178
1179
void D3D9Context::Clear(int mask, uint32_t colorval, float depthVal, int stencilVal) {
1180
UINT d3dMask = 0;
1181
if (mask & FBChannel::FB_COLOR_BIT) d3dMask |= D3DCLEAR_TARGET;
1182
if (mask & FBChannel::FB_DEPTH_BIT) d3dMask |= D3DCLEAR_ZBUFFER;
1183
if (mask & FBChannel::FB_STENCIL_BIT) d3dMask |= D3DCLEAR_STENCIL;
1184
if (d3dMask) {
1185
device_->Clear(0, NULL, d3dMask, (D3DCOLOR)SwapRB(colorval), depthVal, stencilVal);
1186
}
1187
}
1188
1189
void D3D9Context::SetScissorRect(int left, int top, int width, int height) {
1190
dxstate.scissorRect.set(left, top, left + width, top + height);
1191
dxstate.scissorTest.set(true);
1192
}
1193
1194
void D3D9Context::SetViewport(const Viewport &viewport) {
1195
int x = (int)viewport.TopLeftX;
1196
int y = (int)viewport.TopLeftY;
1197
int w = (int)viewport.Width;
1198
int h = (int)viewport.Height;
1199
dxstate.viewport.set(x, y, w, h, viewport.MinDepth, viewport.MaxDepth);
1200
}
1201
1202
void D3D9Context::SetBlendFactor(float color[4]) {
1203
uint32_t r = (uint32_t)(color[0] * 255.0f);
1204
uint32_t g = (uint32_t)(color[1] * 255.0f);
1205
uint32_t b = (uint32_t)(color[2] * 255.0f);
1206
uint32_t a = (uint32_t)(color[3] * 255.0f);
1207
dxstate.blendColor.set(color);
1208
}
1209
1210
void D3D9Context::SetStencilParams(uint8_t refValue, uint8_t writeMask, uint8_t compareMask) {
1211
stencilRefValue_ = refValue;
1212
stencilWriteMask_ = writeMask;
1213
stencilCompareMask_ = compareMask;
1214
}
1215
1216
bool D3D9ShaderModule::Compile(LPDIRECT3DDEVICE9 device, const uint8_t *data, size_t size) {
1217
LPD3D_SHADER_MACRO defines = nullptr;
1218
LPD3DINCLUDE includes = nullptr;
1219
ComPtr<ID3DBlob> codeBuffer;
1220
ComPtr<ID3DBlob> errorBuffer;
1221
const char *source = (const char *)data;
1222
auto compile = [&](const char *profile) -> HRESULT {
1223
return dyn_D3DCompile(source, (UINT)strlen(source), nullptr, defines, includes, "main", profile, 0, 0, &codeBuffer, &errorBuffer);
1224
};
1225
HRESULT hr = compile(stage_ == ShaderStage::Fragment ? "ps_3_0" : "vs_3_0");
1226
if (FAILED(hr)) {
1227
const char *error = errorBuffer ? (const char *)errorBuffer->GetBufferPointer() : "(no errorbuffer returned)";
1228
if (hr == ERROR_MOD_NOT_FOUND) {
1229
// No D3D9-compatible shader compiler installed.
1230
error = "D3D9 shader compiler not installed";
1231
}
1232
1233
ERROR_LOG(Log::G3D, "Compile error: %s", error);
1234
ERROR_LOG(Log::G3D, "%s", LineNumberString(std::string((const char *)data)).c_str());
1235
1236
OutputDebugStringA(source);
1237
OutputDebugStringA(error);
1238
return false;
1239
}
1240
1241
bool success = false;
1242
if (stage_ == ShaderStage::Fragment) {
1243
HRESULT result = device->CreatePixelShader((DWORD *)codeBuffer->GetBufferPointer(), &pshader_);
1244
success = SUCCEEDED(result);
1245
} else {
1246
HRESULT result = device->CreateVertexShader((DWORD *)codeBuffer->GetBufferPointer(), &vshader_);
1247
success = SUCCEEDED(result);
1248
}
1249
1250
return true;
1251
}
1252
1253
class D3D9Framebuffer : public Framebuffer {
1254
public:
1255
D3D9Framebuffer(int width, int height) {
1256
width_ = width;
1257
height_ = height;
1258
}
1259
~D3D9Framebuffer();
1260
1261
uint32_t id = 0;
1262
ComPtr<IDirect3DSurface9> surf;
1263
ComPtr<IDirect3DSurface9> depthstencil;
1264
ComPtr<IDirect3DTexture9> tex;
1265
ComPtr<IDirect3DTexture9> depthstenciltex;
1266
};
1267
1268
Framebuffer *D3D9Context::CreateFramebuffer(const FramebufferDesc &desc) {
1269
// Don't think D3D9 does array layers.
1270
_dbg_assert_(desc.numLayers == 1);
1271
1272
static uint32_t id = 0;
1273
1274
D3D9Framebuffer *fbo = new D3D9Framebuffer(desc.width, desc.height);
1275
fbo->depthstenciltex = nullptr;
1276
1277
HRESULT rtResult = device_->CreateTexture(desc.width, desc.height, 1, D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &fbo->tex, nullptr);
1278
if (FAILED(rtResult)) {
1279
ERROR_LOG(Log::G3D, "Failed to create render target");
1280
fbo->Release();
1281
return NULL;
1282
}
1283
fbo->tex->GetSurfaceLevel(0, &fbo->surf);
1284
1285
HRESULT dsResult;
1286
if (supportsINTZ) {
1287
dsResult = device_->CreateTexture(desc.width, desc.height, 1, D3DUSAGE_DEPTHSTENCIL, FOURCC_INTZ, D3DPOOL_DEFAULT, &fbo->depthstenciltex, NULL);
1288
if (SUCCEEDED(dsResult)) {
1289
dsResult = fbo->depthstenciltex->GetSurfaceLevel(0, &fbo->depthstencil);
1290
}
1291
} else {
1292
dsResult = device_->CreateDepthStencilSurface(desc.width, desc.height, D3DFMT_D24S8, D3DMULTISAMPLE_NONE, 0, FALSE, &fbo->depthstencil, NULL);
1293
}
1294
if (FAILED(dsResult)) {
1295
ERROR_LOG(Log::G3D, "Failed to create depth buffer");
1296
fbo->surf = nullptr;
1297
fbo->tex = nullptr;
1298
fbo->depthstenciltex = nullptr;
1299
delete fbo;
1300
return NULL;
1301
}
1302
fbo->id = id++;
1303
return fbo;
1304
}
1305
1306
D3D9Framebuffer::~D3D9Framebuffer() {
1307
}
1308
1309
void D3D9Context::BindFramebufferAsRenderTarget(Framebuffer *fbo, const RenderPassInfo &rp, const char *tag) {
1310
if (fbo) {
1311
D3D9Framebuffer *fb = (D3D9Framebuffer *)fbo;
1312
device_->SetRenderTarget(0, fb->surf.Get());
1313
device_->SetDepthStencilSurface(fb->depthstencil.Get());
1314
curRenderTarget_ = fb;
1315
} else {
1316
device_->SetRenderTarget(0, deviceRTsurf.Get());
1317
device_->SetDepthStencilSurface(deviceDSsurf.Get());
1318
curRenderTarget_ = nullptr;
1319
}
1320
1321
int clearFlags = 0;
1322
if (rp.color == RPAction::CLEAR) {
1323
clearFlags |= D3DCLEAR_TARGET;
1324
}
1325
if (rp.depth == RPAction::CLEAR) {
1326
clearFlags |= D3DCLEAR_ZBUFFER;
1327
}
1328
if (rp.stencil == RPAction::CLEAR) {
1329
clearFlags |= D3DCLEAR_STENCIL;
1330
}
1331
if (clearFlags) {
1332
dxstate.scissorTest.force(false);
1333
device_->Clear(0, nullptr, clearFlags, (D3DCOLOR)SwapRB(rp.clearColor), rp.clearDepth, rp.clearStencil);
1334
dxstate.scissorRect.restore();
1335
}
1336
1337
dxstate.scissorRect.restore();
1338
dxstate.scissorTest.restore();
1339
dxstate.viewport.restore();
1340
1341
if (invalidationCallback_) {
1342
invalidationCallback_(InvalidationCallbackFlags::RENDER_PASS_STATE);
1343
}
1344
}
1345
1346
uintptr_t D3D9Context::GetFramebufferAPITexture(Framebuffer *fbo, int channelBits, int attachment) {
1347
D3D9Framebuffer *fb = (D3D9Framebuffer *)fbo;
1348
if (channelBits & FB_SURFACE_BIT) {
1349
switch (channelBits & 7) {
1350
case FB_DEPTH_BIT:
1351
return (uintptr_t)fb->depthstencil.Get();
1352
case FB_STENCIL_BIT:
1353
return (uintptr_t)fb->depthstencil.Get();
1354
case FB_COLOR_BIT:
1355
default:
1356
return (uintptr_t)fb->surf.Get();
1357
}
1358
} else {
1359
switch (channelBits & 7) {
1360
case FB_DEPTH_BIT:
1361
return (uintptr_t)fb->depthstenciltex.Get();
1362
case FB_STENCIL_BIT:
1363
return 0; // Can't texture from stencil
1364
case FB_COLOR_BIT:
1365
default:
1366
return (uintptr_t)fb->tex.Get();
1367
}
1368
}
1369
}
1370
1371
void D3D9Context::BindFramebufferAsTexture(Framebuffer *fbo, int binding, FBChannel channelBit, int layer) {
1372
_dbg_assert_(binding < MAX_BOUND_TEXTURES);
1373
_dbg_assert_(layer == ALL_LAYERS || layer == 0); // No stereo support
1374
D3D9Framebuffer *fb = (D3D9Framebuffer *)fbo;
1375
switch (channelBit) {
1376
case FB_DEPTH_BIT:
1377
if (fb->depthstenciltex) {
1378
device_->SetTexture(binding, fb->depthstenciltex.Get());
1379
}
1380
break;
1381
case FB_COLOR_BIT:
1382
default:
1383
if (fb->tex) {
1384
device_->SetTexture(binding, fb->tex.Get());
1385
}
1386
break;
1387
}
1388
}
1389
1390
void D3D9Context::GetFramebufferDimensions(Framebuffer *fbo, int *w, int *h) {
1391
D3D9Framebuffer *fb = (D3D9Framebuffer *)fbo;
1392
if (fb) {
1393
*w = fb->Width();
1394
*h = fb->Height();
1395
} else {
1396
*w = targetWidth_;
1397
*h = targetHeight_;
1398
}
1399
}
1400
1401
bool D3D9Context::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) {
1402
D3D9Framebuffer *src = (D3D9Framebuffer *)srcfb;
1403
D3D9Framebuffer *dst = (D3D9Framebuffer *)dstfb;
1404
1405
ComPtr<IDirect3DSurface9> srcSurf;
1406
ComPtr<IDirect3DSurface9> dstSurf;
1407
RECT srcRect{ (LONG)srcX1, (LONG)srcY1, (LONG)srcX2, (LONG)srcY2 };
1408
RECT dstRect{ (LONG)dstX1, (LONG)dstY1, (LONG)dstX2, (LONG)dstY2 };
1409
if (channelBits == FB_COLOR_BIT) {
1410
srcSurf = src ? src->surf : deviceRTsurf;
1411
dstSurf = dst ? dst->surf : deviceRTsurf;
1412
} else if (channelBits & FB_DEPTH_BIT) {
1413
if (!src || !dst) {
1414
// Might have implications for non-buffered rendering.
1415
return false;
1416
}
1417
srcSurf = src->depthstencil;
1418
dstSurf = dst->depthstencil;
1419
} else {
1420
return false;
1421
}
1422
return SUCCEEDED(device_->StretchRect(srcSurf.Get(), &srcRect, dstSurf.Get(), &dstRect, (filter == FB_BLIT_LINEAR && channelBits == FB_COLOR_BIT) ? D3DTEXF_LINEAR : D3DTEXF_POINT));
1423
}
1424
1425
bool D3D9Context::CopyFramebufferToMemory(Framebuffer *src, int channelBits, int bx, int by, int bw, int bh, Draw::DataFormat destFormat, void *pixels, int pixelStride, ReadbackMode mode, const char *tag) {
1426
D3D9Framebuffer *fb = (D3D9Framebuffer *)src;
1427
1428
if (fb) {
1429
if (bx + bw > fb->Width()) {
1430
bw -= (bx + bw) - fb->Width();
1431
}
1432
if (by + bh > fb->Height()) {
1433
bh -= (by + bh) - fb->Height();
1434
}
1435
}
1436
1437
if (bh <= 0 || bw <= 0)
1438
return true;
1439
1440
DataFormat srcFormat = Draw::DataFormat::R8G8B8A8_UNORM;
1441
if (channelBits != FB_COLOR_BIT) {
1442
srcFormat = Draw::DataFormat::D24_S8;
1443
if (!supportsINTZ)
1444
return false;
1445
}
1446
1447
D3DSURFACE_DESC desc;
1448
D3DLOCKED_RECT locked;
1449
RECT rect = { (LONG)bx, (LONG)by, (LONG)bw, (LONG)bh };
1450
1451
ComPtr<IDirect3DSurface9> offscreen;
1452
HRESULT hr = E_UNEXPECTED;
1453
if (channelBits == FB_COLOR_BIT) {
1454
if (fb)
1455
fb->tex->GetLevelDesc(0, &desc);
1456
else
1457
deviceRTsurf->GetDesc(&desc);
1458
1459
hr = device_->CreateOffscreenPlainSurface(desc.Width, desc.Height, desc.Format, D3DPOOL_SYSTEMMEM, &offscreen, nullptr);
1460
if (SUCCEEDED(hr)) {
1461
hr = device_->GetRenderTargetData(fb ? fb->surf.Get() : deviceRTsurf.Get(), offscreen.Get());
1462
if (SUCCEEDED(hr)) {
1463
hr = offscreen->LockRect(&locked, &rect, D3DLOCK_READONLY);
1464
}
1465
}
1466
} else {
1467
_assert_(fb->depthstenciltex != nullptr);
1468
fb->depthstenciltex->GetLevelDesc(0, &desc);
1469
hr = fb->depthstenciltex->LockRect(0, &locked, &rect, D3DLOCK_READONLY);
1470
}
1471
1472
if (SUCCEEDED(hr)) {
1473
switch (channelBits) {
1474
case FB_COLOR_BIT:
1475
// Pixel size always 4 here because we always request BGRA8888.
1476
ConvertFromBGRA8888((uint8_t *)pixels, (const uint8_t *)locked.pBits, pixelStride, locked.Pitch / sizeof(uint32_t), bw, bh, destFormat);
1477
break;
1478
case FB_DEPTH_BIT:
1479
if (srcFormat == destFormat) {
1480
// Can just memcpy when it matches no matter the format!
1481
uint8_t *dst = (uint8_t *)pixels;
1482
const uint8_t *src = (const uint8_t *)locked.pBits;
1483
for (int y = 0; y < bh; ++y) {
1484
memcpy(dst, src, bw * DataFormatSizeInBytes(srcFormat));
1485
dst += pixelStride * DataFormatSizeInBytes(srcFormat);
1486
src += locked.Pitch;
1487
}
1488
} else if (destFormat == DataFormat::D32F) {
1489
ConvertToD32F((uint8_t *)pixels, (const uint8_t *)locked.pBits, pixelStride, locked.Pitch / sizeof(uint32_t), bw, bh, srcFormat);
1490
} else if (destFormat == DataFormat::D16) {
1491
ConvertToD16((uint8_t *)pixels, (const uint8_t *)locked.pBits, pixelStride, locked.Pitch / sizeof(uint32_t), bw, bh, srcFormat);
1492
} else {
1493
_assert_(false);
1494
}
1495
break;
1496
case FB_STENCIL_BIT:
1497
if (srcFormat == destFormat) {
1498
uint8_t *dst = (uint8_t *)pixels;
1499
const uint8_t *src = (const uint8_t *)locked.pBits;
1500
for (int y = 0; y < bh; ++y) {
1501
memcpy(dst, src, bw * DataFormatSizeInBytes(srcFormat));
1502
dst += pixelStride * DataFormatSizeInBytes(srcFormat);
1503
src += locked.Pitch;
1504
}
1505
} else if (destFormat == DataFormat::S8) {
1506
for (int y = 0; y < bh; y++) {
1507
uint8_t *destStencil = (uint8_t *)pixels + y * pixelStride;
1508
const uint32_t *src = (const uint32_t *)((const uint8_t *)locked.pBits + locked.Pitch * y);
1509
for (int x = 0; x < bw; x++) {
1510
destStencil[x] = src[x] >> 24;
1511
}
1512
}
1513
} else {
1514
_assert_(false);
1515
}
1516
break;
1517
}
1518
}
1519
1520
if (channelBits != FB_COLOR_BIT) {
1521
fb->depthstenciltex->UnlockRect(0);
1522
}
1523
1524
return SUCCEEDED(hr);
1525
}
1526
1527
void D3D9Context::HandleEvent(Event ev, int width, int height, void *param1, void *param2) {
1528
switch (ev) {
1529
case Event::LOST_BACKBUFFER:
1530
deviceRTsurf = nullptr;
1531
deviceDSsurf = nullptr;
1532
break;
1533
case Event::GOT_BACKBUFFER:
1534
device_->GetRenderTarget(0, &deviceRTsurf);
1535
device_->GetDepthStencilSurface(&deviceDSsurf);
1536
break;
1537
case Event::PRESENTED:
1538
break;
1539
}
1540
}
1541
1542
DrawContext *T3DCreateDX9Context(IDirect3D9 *d3d, IDirect3D9Ex *d3dEx, int adapterId, IDirect3DDevice9 *device, IDirect3DDevice9Ex *deviceEx) {
1543
bool result = LoadD3DCompilerDynamic();
1544
if (!result) {
1545
ERROR_LOG(Log::G3D, "Failed to load D3DCompiler!");
1546
return nullptr;
1547
}
1548
return new D3D9Context(d3d, d3dEx, adapterId, device, deviceEx);
1549
}
1550
1551
// Only partial implementation!
1552
uint32_t D3D9Context::GetDataFormatSupport(DataFormat fmt) const {
1553
switch (fmt) {
1554
case DataFormat::B8G8R8A8_UNORM:
1555
return FMT_RENDERTARGET | FMT_TEXTURE | FMT_AUTOGEN_MIPS;
1556
1557
case DataFormat::R4G4B4A4_UNORM_PACK16:
1558
return 0;
1559
case DataFormat::B4G4R4A4_UNORM_PACK16:
1560
return FMT_TEXTURE; // emulated support
1561
case DataFormat::R5G6B5_UNORM_PACK16:
1562
case DataFormat::A1R5G5B5_UNORM_PACK16:
1563
case DataFormat::A4R4G4B4_UNORM_PACK16:
1564
return FMT_RENDERTARGET | FMT_TEXTURE | FMT_AUTOGEN_MIPS; // native support
1565
1566
case DataFormat::R8G8B8A8_UNORM:
1567
return FMT_RENDERTARGET | FMT_TEXTURE | FMT_INPUTLAYOUT | FMT_AUTOGEN_MIPS;
1568
1569
case DataFormat::R32_FLOAT:
1570
case DataFormat::R32G32_FLOAT:
1571
case DataFormat::R32G32B32_FLOAT:
1572
case DataFormat::R32G32B32A32_FLOAT:
1573
return FMT_INPUTLAYOUT;
1574
1575
case DataFormat::R8_UNORM:
1576
return 0;
1577
case DataFormat::BC1_RGBA_UNORM_BLOCK:
1578
case DataFormat::BC2_UNORM_BLOCK:
1579
case DataFormat::BC3_UNORM_BLOCK:
1580
// DXT1, DXT3, DXT5.
1581
return FMT_TEXTURE;
1582
default:
1583
return 0;
1584
}
1585
}
1586
1587
1588
} // namespace Draw
1589
1590