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