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