Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
hrydgard
GitHub Repository: hrydgard/ppsspp
Path: blob/master/GPU/D3D11/TextureCacheD3D11.cpp
5656 views
1
// Copyright (c) 2012- PPSSPP Project.
2
3
// This program is free software: you can redistribute it and/or modify
4
// it under the terms of the GNU General Public License as published by
5
// the Free Software Foundation, version 2.0 or later versions.
6
7
// This program is distributed in the hope that it will be useful,
8
// but WITHOUT ANY WARRANTY; without even the implied warranty of
9
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10
// GNU General Public License 2.0 for more details.
11
12
// A copy of the GPL 2.0 should have been included with the program.
13
// If not, see http://www.gnu.org/licenses/
14
15
// Official git repository and contact information can be found at
16
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
17
18
#include <algorithm>
19
#include <cstring>
20
#include <cfloat>
21
22
#include <d3d11.h>
23
#include <wrl/client.h>
24
25
#include "GPU/ge_constants.h"
26
#include "GPU/GPUState.h"
27
#include "GPU/GPUDefinitions.h"
28
#include "GPU/Common/GPUStateUtils.h"
29
#include "GPU/Common/DrawEngineCommon.h"
30
#include "GPU/D3D11/TextureCacheD3D11.h"
31
#include "GPU/D3D11/FramebufferManagerD3D11.h"
32
#include "GPU/D3D11/D3D11Util.h"
33
#include "Core/Config.h"
34
35
#include "ext/xxhash.h"
36
37
using namespace Microsoft::WRL;
38
39
// For depth depal
40
struct DepthPushConstants {
41
float z_scale;
42
float z_offset;
43
float pad[2];
44
};
45
46
static const D3D11_INPUT_ELEMENT_DESC g_QuadVertexElements[] = {
47
{ "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, },
48
{ "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 12,},
49
};
50
51
// NOTE: In the D3D backends, we flip R and B in the shaders, so while these look wrong, they're OK.
52
53
static Draw::DataFormat FromD3D11Format(u32 fmt) {
54
switch (fmt) {
55
case DXGI_FORMAT_B4G4R4A4_UNORM: return Draw::DataFormat::A4R4G4B4_UNORM_PACK16;
56
case DXGI_FORMAT_B5G5R5A1_UNORM: return Draw::DataFormat::A1R5G5B5_UNORM_PACK16;
57
case DXGI_FORMAT_B5G6R5_UNORM: return Draw::DataFormat::R5G6B5_UNORM_PACK16;
58
case DXGI_FORMAT_R8_UNORM: return Draw::DataFormat::R8_UNORM;
59
case DXGI_FORMAT_B8G8R8A8_UNORM: default: return Draw::DataFormat::R8G8B8A8_UNORM;
60
}
61
}
62
63
static DXGI_FORMAT ToDXGIFormat(Draw::DataFormat fmt) {
64
switch (fmt) {
65
case Draw::DataFormat::BC1_RGBA_UNORM_BLOCK: return DXGI_FORMAT_BC1_UNORM;
66
case Draw::DataFormat::BC2_UNORM_BLOCK: return DXGI_FORMAT_BC2_UNORM;
67
case Draw::DataFormat::BC3_UNORM_BLOCK: return DXGI_FORMAT_BC3_UNORM;
68
case Draw::DataFormat::BC4_UNORM_BLOCK: return DXGI_FORMAT_BC4_UNORM;
69
case Draw::DataFormat::BC5_UNORM_BLOCK: return DXGI_FORMAT_BC5_UNORM;
70
case Draw::DataFormat::BC7_UNORM_BLOCK: return DXGI_FORMAT_BC7_UNORM;
71
case Draw::DataFormat::R8G8B8A8_UNORM: return DXGI_FORMAT_B8G8R8A8_UNORM;
72
default: _dbg_assert_(false); return DXGI_FORMAT_UNKNOWN;
73
}
74
}
75
76
SamplerCacheD3D11::~SamplerCacheD3D11() {
77
}
78
79
HRESULT SamplerCacheD3D11::GetOrCreateSampler(ID3D11Device *device, const SamplerCacheKey &key, ID3D11SamplerState **ppSamplerState) {
80
auto iter = cache_.find(key);
81
if (iter != cache_.end()) {
82
iter->second->AddRef();
83
*ppSamplerState = iter->second.Get();
84
return S_OK;
85
}
86
87
D3D11_SAMPLER_DESC samp{};
88
samp.AddressU = key.sClamp ? D3D11_TEXTURE_ADDRESS_CLAMP : D3D11_TEXTURE_ADDRESS_WRAP;
89
samp.AddressV = key.tClamp ? D3D11_TEXTURE_ADDRESS_CLAMP : D3D11_TEXTURE_ADDRESS_WRAP;
90
samp.AddressW = samp.AddressU; // Mali benefits from all clamps being the same, and this one is irrelevant.
91
if (key.aniso) {
92
samp.MaxAnisotropy = (float)(1 << g_Config.iAnisotropyLevel);
93
} else {
94
samp.MaxAnisotropy = 1.0f;
95
}
96
int filterKey = ((int)key.minFilt << 2) | ((int)key.magFilt << 1) | ((int)key.mipFilt);
97
static const D3D11_FILTER filters[8] = {
98
D3D11_FILTER_MIN_MAG_MIP_POINT,
99
D3D11_FILTER_MIN_MAG_POINT_MIP_LINEAR,
100
D3D11_FILTER_MIN_POINT_MAG_LINEAR_MIP_POINT,
101
D3D11_FILTER_MIN_POINT_MAG_MIP_LINEAR,
102
D3D11_FILTER_MIN_LINEAR_MAG_MIP_POINT,
103
D3D11_FILTER_MIN_LINEAR_MAG_POINT_MIP_LINEAR,
104
D3D11_FILTER_MIN_MAG_LINEAR_MIP_POINT,
105
D3D11_FILTER_MIN_MAG_MIP_LINEAR,
106
};
107
// Only switch to aniso if linear min and mag are set.
108
if (key.aniso && key.magFilt != 0 && key.minFilt != 0)
109
samp.Filter = D3D11_FILTER_ANISOTROPIC;
110
else
111
samp.Filter = filters[filterKey];
112
// Can't set MaxLOD on Feature Level <= 9_3.
113
if (device->GetFeatureLevel() <= D3D_FEATURE_LEVEL_9_3) {
114
samp.MaxLOD = FLT_MAX;
115
samp.MinLOD = -FLT_MAX;
116
samp.MipLODBias = 0.0f;
117
} else {
118
samp.MaxLOD = key.maxLevel / 256.0f;
119
samp.MinLOD = key.minLevel / 256.0f;
120
samp.MipLODBias = key.lodBias / 256.0f;
121
}
122
samp.ComparisonFunc = D3D11_COMPARISON_NEVER;
123
for (int i = 0; i < 4; i++) {
124
samp.BorderColor[i] = 1.0f;
125
}
126
127
ASSERT_SUCCESS(device->CreateSamplerState(&samp, ppSamplerState));
128
cache_[key] = *ppSamplerState;
129
return S_OK;
130
}
131
132
TextureCacheD3D11::TextureCacheD3D11(Draw::DrawContext *draw, Draw2D *draw2D)
133
: TextureCacheCommon(draw, draw2D) {
134
device_ = (ID3D11Device *)draw->GetNativeObject(Draw::NativeObject::DEVICE);
135
context_ = (ID3D11DeviceContext *)draw->GetNativeObject(Draw::NativeObject::CONTEXT);
136
137
lastBoundTexture_ = D3D11_INVALID_TEX;
138
139
InitDeviceObjects();
140
}
141
142
TextureCacheD3D11::~TextureCacheD3D11() {
143
Clear(true);
144
DestroyDeviceObjects();
145
}
146
147
void TextureCacheD3D11::InitDeviceObjects() {
148
D3D11_BUFFER_DESC desc{ sizeof(DepthPushConstants), D3D11_USAGE_DYNAMIC, D3D11_BIND_CONSTANT_BUFFER, D3D11_CPU_ACCESS_WRITE };
149
HRESULT hr = device_->CreateBuffer(&desc, nullptr, &depalConstants_);
150
_dbg_assert_(SUCCEEDED(hr));
151
D3D11_SAMPLER_DESC sampler_desc{};
152
sampler_desc.Filter = D3D11_FILTER_MIN_MAG_MIP_POINT;
153
sampler_desc.ComparisonFunc = D3D11_COMPARISON_NEVER;
154
for (int i = 0; i < 4; i++)
155
sampler_desc.BorderColor[i] = 1.0f;
156
sampler_desc.MinLOD = -FLT_MAX;
157
sampler_desc.MaxLOD = FLT_MAX;
158
sampler_desc.MipLODBias = 0.0f;
159
sampler_desc.MaxAnisotropy = 1;
160
sampler_desc.AddressU = D3D11_TEXTURE_ADDRESS_CLAMP;
161
sampler_desc.AddressV = D3D11_TEXTURE_ADDRESS_CLAMP;
162
sampler_desc.AddressW = D3D11_TEXTURE_ADDRESS_CLAMP;
163
ASSERT_SUCCESS(device_->CreateSamplerState(&sampler_desc, &samplerPoint2DClamp_));
164
sampler_desc.Filter = D3D11_FILTER_MIN_MAG_LINEAR_MIP_POINT;
165
ASSERT_SUCCESS(device_->CreateSamplerState(&sampler_desc, &samplerLinear2DClamp_));
166
}
167
168
void TextureCacheD3D11::DestroyDeviceObjects() {
169
depalConstants_.Reset();
170
samplerPoint2DClamp_.Reset();
171
samplerLinear2DClamp_.Reset();
172
lastBoundTexture_ = D3D11_INVALID_TEX;
173
samplerCache_.Destroy();
174
}
175
176
void TextureCacheD3D11::DeviceLost() {
177
Clear(false);
178
DestroyDeviceObjects();
179
draw_ = nullptr;
180
}
181
182
void TextureCacheD3D11::DeviceRestore(Draw::DrawContext *draw) {
183
draw_ = draw;
184
InitDeviceObjects();
185
}
186
187
void TextureCacheD3D11::SetFramebufferManager(FramebufferManagerD3D11 *fbManager) {
188
framebufferManager_ = fbManager;
189
}
190
191
void TextureCacheD3D11::ReleaseTexture(TexCacheEntry *entry, bool delete_them) {
192
ID3D11Texture2D *texture = (ID3D11Texture2D *)entry->texturePtr;
193
ID3D11ShaderResourceView *view = (ID3D11ShaderResourceView *)entry->textureView;
194
if (texture) {
195
texture->Release();
196
entry->texturePtr = nullptr;
197
}
198
if (view) {
199
view->Release();
200
entry->textureView = nullptr;
201
}
202
}
203
204
void TextureCacheD3D11::ForgetLastTexture() {
205
lastBoundTexture_ = D3D11_INVALID_TEX;
206
207
ID3D11ShaderResourceView *nullTex[4]{};
208
context_->PSSetShaderResources(0, 4, nullTex);
209
}
210
211
void TextureCacheD3D11::UpdateCurrentClut(GEPaletteFormat clutFormat, u32 clutBase, bool clutIndexIsSimple) {
212
const u32 clutBaseBytes = clutBase * (clutFormat == GE_CMODE_32BIT_ABGR8888 ? sizeof(u32) : sizeof(u16));
213
// Technically, these extra bytes weren't loaded, but hopefully it was loaded earlier.
214
// If not, we're going to hash random data, which hopefully doesn't cause a performance issue.
215
//
216
// TODO: Actually, this seems like a hack. The game can upload part of a CLUT and reference other data.
217
// clutTotalBytes_ is the last amount uploaded. We should hash clutMaxBytes_, but this will often hash
218
// unrelated old entries for small palettes.
219
// Adding clutBaseBytes may just be mitigating this for some usage patterns.
220
const u32 clutExtendedBytes = std::min(clutTotalBytes_ + clutBaseBytes, clutMaxBytes_);
221
222
if (replacer_.Enabled())
223
clutHash_ = XXH32((const char *)clutBufRaw_, clutExtendedBytes, 0xC0108888);
224
else
225
clutHash_ = XXH3_64bits((const char *)clutBufRaw_, clutExtendedBytes) & 0xFFFFFFFF;
226
clutBuf_ = clutBufRaw_;
227
228
// Special optimization: fonts typically draw clut4 with just alpha values in a single color.
229
clutAlphaLinear_ = false;
230
clutAlphaLinearColor_ = 0;
231
if (clutFormat == GE_CMODE_16BIT_ABGR4444 && clutIndexIsSimple) {
232
const u16_le *clut = GetCurrentClut<u16_le>();
233
clutAlphaLinear_ = true;
234
clutAlphaLinearColor_ = clut[15] & 0x0FFF;
235
for (int i = 0; i < 16; ++i) {
236
u16 step = clutAlphaLinearColor_ | (i << 12);
237
if (clut[i] != step) {
238
clutAlphaLinear_ = false;
239
break;
240
}
241
}
242
}
243
244
clutLastFormat_ = gstate.clutformat;
245
}
246
247
void TextureCacheD3D11::BindTexture(TexCacheEntry *entry) {
248
if (!entry) {
249
ID3D11ShaderResourceView *textureView = nullptr;
250
context_->PSSetShaderResources(0, 1, &textureView);
251
return;
252
}
253
ID3D11ShaderResourceView *textureView = DxView(entry);
254
if (textureView != lastBoundTexture_) {
255
context_->PSSetShaderResources(0, 1, &textureView);
256
lastBoundTexture_ = textureView;
257
}
258
int maxLevel = (entry->status & TexCacheEntry::STATUS_NO_MIPS) ? 0 : entry->maxLevel;
259
SamplerCacheKey samplerKey = GetSamplingParams(maxLevel, entry);
260
ComPtr<ID3D11SamplerState> state;
261
samplerCache_.GetOrCreateSampler(device_, samplerKey, &state);
262
context_->PSSetSamplers(0, 1, state.GetAddressOf());
263
gstate_c.SetUseShaderDepal(ShaderDepalMode::OFF);
264
}
265
266
void TextureCacheD3D11::ApplySamplingParams(const SamplerCacheKey &key) {
267
ComPtr<ID3D11SamplerState> state;
268
samplerCache_.GetOrCreateSampler(device_, key, &state);
269
context_->PSSetSamplers(0, 1, state.GetAddressOf());
270
}
271
272
void TextureCacheD3D11::Unbind() {
273
ForgetLastTexture();
274
}
275
276
void TextureCacheD3D11::BindAsClutTexture(Draw::Texture *tex, bool smooth) {
277
ID3D11ShaderResourceView *clutTexture = (ID3D11ShaderResourceView *)draw_->GetNativeObject(Draw::NativeObject::TEXTURE_VIEW, tex);
278
context_->PSSetShaderResources(TEX_SLOT_CLUT, 1, &clutTexture);
279
context_->PSSetSamplers(3, 1, smooth ? samplerLinear2DClamp_.GetAddressOf() : samplerPoint2DClamp_.GetAddressOf());
280
}
281
282
void TextureCacheD3D11::BuildTexture(TexCacheEntry *const entry) {
283
BuildTexturePlan plan;
284
if (!PrepareBuildTexture(plan, entry)) {
285
// We're screwed?
286
return;
287
}
288
289
DXGI_FORMAT dstFmt = GetDestFormat(GETextureFormat(entry->format), gstate.getClutPaletteFormat());
290
if (plan.doReplace) {
291
dstFmt = ToDXGIFormat(plan.replaced->Format());
292
} else if (plan.scaleFactor > 1 || plan.saveTexture) {
293
dstFmt = DXGI_FORMAT_B8G8R8A8_UNORM;
294
} else if (plan.decodeToClut8) {
295
dstFmt = DXGI_FORMAT_R8_UNORM;
296
}
297
298
int levels;
299
300
ID3D11ShaderResourceView *view;
301
ID3D11Resource *texture = DxTex(entry);
302
_assert_(texture == nullptr);
303
304
// The PSP only supports 8 mip levels, but we support more in the texture replacer. 20 will never run out.
305
D3D11_SUBRESOURCE_DATA subresData[20]{};
306
307
if (plan.depth == 1) {
308
// We don't yet have mip generation, so clamp the number of levels to the ones we can load directly.
309
levels = std::min(plan.levelsToCreate, plan.levelsToLoad);
310
} else {
311
levels = plan.depth;
312
}
313
314
Draw::DataFormat texFmt = FromD3D11Format(dstFmt);
315
316
for (int i = 0; i < levels; i++) {
317
int srcLevel = (i == 0) ? plan.baseLevelSrc : i;
318
319
int mipWidth;
320
int mipHeight;
321
plan.GetMipSize(i, &mipWidth, &mipHeight);
322
323
u8 *data = nullptr;
324
int stride = 0;
325
326
int dataSize;
327
if (plan.doReplace) {
328
int blockSize = 0;
329
if (Draw::DataFormatIsBlockCompressed(plan.replaced->Format(), &blockSize)) {
330
stride = ((mipWidth + 3) & ~3) * blockSize / 4; // Number of blocks * 4 * Size of a block / 4
331
dataSize = plan.replaced->GetLevelDataSizeAfterCopy(i);
332
} else {
333
int bpp = (int)Draw::DataFormatSizeInBytes(plan.replaced->Format());
334
stride = std::max(mipWidth * bpp, 16);
335
dataSize = stride * mipHeight;
336
}
337
} else {
338
int bpp = 0;
339
if (plan.scaleFactor > 1) {
340
bpp = 4;
341
} else {
342
bpp = dstFmt == DXGI_FORMAT_B8G8R8A8_UNORM ? 4 : 2;
343
}
344
stride = std::max(mipWidth * bpp, 16);
345
dataSize = stride * mipHeight;
346
}
347
348
if (plan.depth == 1) {
349
data = (u8 *)AllocateAlignedMemory(dataSize, 16);
350
subresData[i].pSysMem = data;
351
subresData[i].SysMemPitch = stride;
352
subresData[i].SysMemSlicePitch = 0;
353
} else {
354
if (i == 0) {
355
subresData[0].pSysMem = AllocateAlignedMemory(stride * mipHeight * plan.depth, 16);
356
subresData[0].SysMemPitch = stride;
357
subresData[0].SysMemSlicePitch = stride * mipHeight;
358
}
359
data = (uint8_t *)subresData[0].pSysMem + stride * mipHeight * i;
360
}
361
362
if (!data) {
363
ERROR_LOG(Log::G3D, "Ran out of RAM trying to allocate a temporary texture upload buffer (%dx%d)", mipWidth, mipHeight);
364
return;
365
}
366
367
LoadTextureLevel(*entry, data, 0, stride, plan, srcLevel, texFmt, TexDecodeFlags{});
368
}
369
370
int tw;
371
int th;
372
plan.GetMipSize(0, &tw, &th);
373
if (tw > 16384)
374
tw = 16384;
375
if (th > 16384)
376
th = 16384;
377
378
// NOTE: For block-compressed textures, we'll force the size up to the closest 4x4. This is due to an
379
// unfortunate restriction in D3D11 (and early D3D12). We'll warn about it in the log to give texture pack
380
// authors notice to fix it.
381
if (plan.doReplace && Draw::DataFormatIsBlockCompressed(plan.replaced->Format(), nullptr)) {
382
tw = (tw + 3) & ~3;
383
th = (th + 3) & ~3;
384
}
385
386
if (plan.depth == 1) {
387
// We don't yet have mip generation, so clamp the number of levels to the ones we can load directly.
388
levels = std::min(plan.levelsToCreate, plan.levelsToLoad);
389
390
ID3D11Texture2D *tex = nullptr;
391
D3D11_TEXTURE2D_DESC desc{};
392
desc.CPUAccessFlags = 0;
393
desc.Usage = D3D11_USAGE_DEFAULT;
394
desc.ArraySize = 1;
395
desc.SampleDesc.Count = 1;
396
desc.Width = tw;
397
desc.Height = th;
398
desc.Format = dstFmt;
399
desc.MipLevels = levels;
400
desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
401
ASSERT_SUCCESS(device_->CreateTexture2D(&desc, subresData, &tex));
402
texture = tex;
403
} else {
404
ID3D11Texture3D *tex = nullptr;
405
D3D11_TEXTURE3D_DESC desc{};
406
desc.CPUAccessFlags = 0;
407
desc.Usage = D3D11_USAGE_DEFAULT;
408
desc.Width = tw;
409
desc.Height = th;
410
desc.Depth = plan.depth;
411
desc.Format = dstFmt;
412
desc.MipLevels = 1;
413
desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
414
ASSERT_SUCCESS(device_->CreateTexture3D(&desc, subresData, &tex));
415
texture = tex;
416
417
levels = plan.depth;
418
}
419
420
ASSERT_SUCCESS(device_->CreateShaderResourceView(texture, nullptr, &view));
421
entry->texturePtr = texture;
422
entry->textureView = view;
423
424
for (int i = 0; i < 12; i++) {
425
if (subresData[i].pSysMem) {
426
FreeAlignedMemory((void *)subresData[i].pSysMem);
427
}
428
}
429
430
// Signal that we support depth textures so use it as one.
431
if (plan.depth > 1) {
432
entry->status |= TexCacheEntry::STATUS_3D;
433
}
434
435
if (levels == 1) {
436
entry->status |= TexCacheEntry::STATUS_NO_MIPS;
437
} else {
438
entry->status &= ~TexCacheEntry::STATUS_NO_MIPS;
439
}
440
441
if (plan.doReplace) {
442
entry->SetAlphaStatus(TexCacheEntry::TexStatus(plan.replaced->AlphaStatus()));
443
444
if (!Draw::DataFormatIsBlockCompressed(plan.replaced->Format(), nullptr)) {
445
entry->status |= TexCacheEntry::STATUS_BGRA;
446
}
447
} else {
448
entry->status |= TexCacheEntry::STATUS_BGRA;
449
}
450
}
451
452
DXGI_FORMAT GetClutDestFormatD3D11(GEPaletteFormat format) {
453
switch (format) {
454
case GE_CMODE_16BIT_ABGR4444:
455
return DXGI_FORMAT_B4G4R4A4_UNORM;
456
case GE_CMODE_16BIT_ABGR5551:
457
return DXGI_FORMAT_B5G5R5A1_UNORM;
458
case GE_CMODE_16BIT_BGR5650:
459
return DXGI_FORMAT_B5G6R5_UNORM;
460
case GE_CMODE_32BIT_ABGR8888:
461
return DXGI_FORMAT_B8G8R8A8_UNORM;
462
}
463
// Should never be here !
464
return DXGI_FORMAT_B8G8R8A8_UNORM;
465
}
466
467
DXGI_FORMAT TextureCacheD3D11::GetDestFormat(GETextureFormat format, GEPaletteFormat clutFormat) const {
468
if (!gstate_c.Use(GPU_USE_16BIT_FORMATS)) {
469
return DXGI_FORMAT_B8G8R8A8_UNORM;
470
}
471
472
switch (format) {
473
case GE_TFMT_CLUT4:
474
case GE_TFMT_CLUT8:
475
case GE_TFMT_CLUT16:
476
case GE_TFMT_CLUT32:
477
return GetClutDestFormatD3D11(clutFormat);
478
case GE_TFMT_4444:
479
return DXGI_FORMAT_B4G4R4A4_UNORM;
480
case GE_TFMT_5551:
481
return DXGI_FORMAT_B5G5R5A1_UNORM;
482
case GE_TFMT_5650:
483
return DXGI_FORMAT_B5G6R5_UNORM;
484
case GE_TFMT_8888:
485
case GE_TFMT_DXT1:
486
case GE_TFMT_DXT3:
487
case GE_TFMT_DXT5:
488
default:
489
return DXGI_FORMAT_B8G8R8A8_UNORM;
490
}
491
}
492
493
bool TextureCacheD3D11::GetCurrentTextureDebug(GPUDebugBuffer &buffer, int level, bool *isFramebuffer) {
494
SetTexture();
495
if (!nextTexture_) {
496
return GetCurrentFramebufferTextureDebug(buffer, isFramebuffer);
497
}
498
499
// Apply texture may need to rebuild the texture if we're about to render, or bind a framebuffer.
500
TexCacheEntry *entry = nextTexture_;
501
ApplyTexture();
502
503
ID3D11Texture2D *texture = (ID3D11Texture2D *)entry->texturePtr;
504
if (!texture)
505
return false;
506
507
D3D11_TEXTURE2D_DESC desc;
508
texture->GetDesc(&desc);
509
510
int width = desc.Width >> level;
511
int height = desc.Height >> level;
512
513
switch (desc.Format) {
514
case DXGI_FORMAT_B8G8R8A8_UNORM:
515
buffer.Allocate(width, height, GPU_DBG_FORMAT_8888);
516
break;
517
518
case DXGI_FORMAT_B5G6R5_UNORM:
519
buffer.Allocate(width, height, GPU_DBG_FORMAT_565);
520
break;
521
522
case DXGI_FORMAT_B4G4R4A4_UNORM:
523
buffer.Allocate(width, height, GPU_DBG_FORMAT_4444);
524
break;
525
526
case DXGI_FORMAT_B5G5R5A1_UNORM:
527
buffer.Allocate(width, height, GPU_DBG_FORMAT_5551);
528
break;
529
530
case DXGI_FORMAT_R8_UNORM:
531
buffer.Allocate(width, height, GPU_DBG_FORMAT_8BIT);
532
break;
533
534
default:
535
return false;
536
}
537
538
desc.BindFlags = 0;
539
desc.Usage = D3D11_USAGE_STAGING;
540
desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
541
542
ComPtr<ID3D11Texture2D> stagingCopy;
543
device_->CreateTexture2D(&desc, nullptr, &stagingCopy);
544
if (!stagingCopy)
545
return false;
546
context_->CopyResource(stagingCopy.Get(), texture);
547
548
D3D11_MAPPED_SUBRESOURCE map;
549
if (FAILED(context_->Map(stagingCopy.Get(), level, D3D11_MAP_READ, 0, &map))) {
550
return false;
551
}
552
553
int bufferRowSize = buffer.PixelSize() * width;
554
for (int y = 0; y < height; y++) {
555
memcpy(buffer.GetData() + bufferRowSize * y, (const uint8_t *)map.pData + map.RowPitch * y, bufferRowSize);
556
}
557
558
context_->Unmap(stagingCopy.Get(), level);
559
*isFramebuffer = false;
560
return true;
561
}
562
563
void *TextureCacheD3D11::GetNativeTextureView(const TexCacheEntry *entry, bool flat) const {
564
ID3D11ShaderResourceView *textureView = DxView(entry);
565
return (void *)textureView;
566
}
567
568