Skip to content

Commit

Permalink
Share LoadTextureLevel between the two D3D backends.
Browse files Browse the repository at this point in the history
  • Loading branch information
hrydgard committed Jul 30, 2022
1 parent 9ed9692 commit dea9794
Show file tree
Hide file tree
Showing 6 changed files with 89 additions and 145 deletions.
66 changes: 66 additions & 0 deletions GPU/Common/TextureCacheCommon.cpp
Expand Up @@ -2142,3 +2142,69 @@ bool TextureCacheCommon::PrepareBuildTexture(BuildTexturePlan &plan, TexCacheEnt
entry->status &= ~TexCacheEntry::STATUS_ALPHA_MASK;
return true;
}

uint8_t *TextureCacheCommon::LoadTextureLevel(TexCacheEntry &entry, uint8_t *data, int stride, ReplacedTexture &replaced, int srcLevel, int scaleFactor, Draw::DataFormat dstFmt) {
int w = gstate.getTextureWidth(srcLevel);
int h = gstate.getTextureHeight(srcLevel);

if (replaced.GetSize(srcLevel, w, h)) {
double replaceStart = time_now_d();
replaced.Load(srcLevel, data, stride);
replacementTimeThisFrame_ += time_now_d() - replaceStart;
} else {
GETextureFormat tfmt = (GETextureFormat)entry.format;
GEPaletteFormat clutformat = gstate.getClutPaletteFormat();
u32 texaddr = gstate.getTextureAddress(srcLevel);
int bufw = GetTextureBufw(srcLevel, texaddr, tfmt);
u32 *pixelData;
int decPitch;
if (scaleFactor > 1) {
tmpTexBufRearrange_.resize(std::max(bufw, w) * h);
pixelData = tmpTexBufRearrange_.data();
// We want to end up with a neatly packed texture for scaling.
decPitch = w * 4;
} else {
pixelData = (u32 *)data;
decPitch = stride;
}

bool expand32 = !gstate_c.Supports(GPU_SUPPORTS_16BIT_FORMATS) || scaleFactor > 1;

CheckAlphaResult alphaResult = DecodeTextureLevel((u8 *)pixelData, decPitch, tfmt, clutformat, texaddr, srcLevel, bufw, false, expand32);
entry.SetAlphaStatus(alphaResult, srcLevel);

if (scaleFactor > 1) {
// Note that this updates w and h!
scaler_.ScaleAlways((u32 *)data, pixelData, w, h, scaleFactor);
pixelData = (u32 *)data;

decPitch = w * 4;

if (decPitch != stride) {
// Rearrange in place to match the requested pitch.
// (it can only be larger than w * bpp, and a match is likely.)
// Note! This is bad because it reads the mapped memory! TODO: Look into if DX9 does this right.
for (int y = h - 1; y >= 0; --y) {
memcpy((u8 *)data + stride * y, (u8 *)data + decPitch * y, w * 4);
}
decPitch = stride;
}
}

if (replacer_.Enabled()) {
ReplacedTextureDecodeInfo replacedInfo;
replacedInfo.cachekey = entry.CacheKey();
replacedInfo.hash = entry.fullhash;
replacedInfo.addr = entry.addr;
replacedInfo.isVideo = IsVideo(entry.addr);
replacedInfo.isFinal = (entry.status & TexCacheEntry::STATUS_TO_SCALE) == 0;
replacedInfo.scaleFactor = scaleFactor;
replacedInfo.fmt = dstFmt;

// NOTE: Reading the decoded texture here may be very slow, if we just wrote it to write-combined memory.
replacer_.NotifyTextureDecoded(replacedInfo, pixelData, decPitch, srcLevel, w, h);
}
}

return data;
}
3 changes: 3 additions & 0 deletions GPU/Common/TextureCacheCommon.h
Expand Up @@ -329,6 +329,9 @@ class TextureCacheCommon {
CheckAlphaResult ReadIndexedTex(u8 *out, int outPitch, int level, const u8 *texptr, int bytesPerIndex, int bufw, bool reverseColors, bool expandTo32Bit);
ReplacedTexture &FindReplacement(TexCacheEntry *entry, int &w, int &h);

// Return value is mapData normally, but could be another buffer allocated with AllocateAlignedMemory.
uint8_t *LoadTextureLevel(TexCacheEntry &entry, uint8_t *mapData, int mapRowPitch, ReplacedTexture &replaced, int srcLevel, int scaleFactor, Draw::DataFormat dstFmt);

template <typename T>
inline const T *GetCurrentClut() {
return (const T *)clutBuf_;
Expand Down
96 changes: 17 additions & 79 deletions GPU/D3D11/TextureCacheD3D11.cpp
Expand Up @@ -490,42 +490,44 @@ void TextureCacheD3D11::BuildTexture(TexCacheEntry *const entry) {
entry->texturePtr = texture;
entry->textureView = view;

// Mipmapping is only enabled when texture scaling is disabled.
Draw::DataFormat texFmt = FromD3D11Format(dstFmt);

for (int i = 0; i < levels; i++) {
// For UpdateSubresource, we can't decode directly into the texture so we allocate a buffer :(
u8 *mapData = nullptr;
int mapRowPitch = 0;
u8 *data = nullptr;
int stride = 0;
int bpp = dstFmt == DXGI_FORMAT_B8G8R8A8_UNORM ? 4 : 2;

int srcLevel = (i == 0) ? plan.baseLevelSrc : i;

int w = gstate.getTextureWidth(srcLevel);
int h = gstate.getTextureHeight(srcLevel);

// For UpdateSubresource, we can't decode directly into the texture so we allocate a buffer :(
// NOTE: Could reuse it between levels or textures!
if (plan.replaced->GetSize(srcLevel, w, h)) {
mapData = (u8 *)AllocateAlignedMemory(w * h * 4, 16);
mapRowPitch = w * 4;
data = (u8 *)AllocateAlignedMemory(w * h * 4, 16);
stride = w * 4;
} else {
if (plan.scaleFactor > 1) {
mapData = (u8 *)AllocateAlignedMemory(4 * (w * plan.scaleFactor) * (h * plan.scaleFactor), 16);
mapRowPitch = w * plan.scaleFactor * 4;
data = (u8 *)AllocateAlignedMemory(4 * (w * plan.scaleFactor) * (h * plan.scaleFactor), 16);
stride = w * plan.scaleFactor * 4;
} else {
mapRowPitch = std::max(w * bpp, 16);
size_t bufSize = sizeof(u32) * (mapRowPitch / bpp) * h;
mapData = (u8 *)AllocateAlignedMemory(bufSize, 16);
stride = std::max(w * bpp, 16);
size_t bufSize = sizeof(u32) * (stride / bpp) * h;
data = (u8 *)AllocateAlignedMemory(bufSize, 16);
}
}

if (!mapData) {
if (!data) {
ERROR_LOG(G3D, "Ran out of RAM trying to allocate a temporary texture upload buffer (%dx%d)", w, h);
return;
}

LoadTextureLevel(*entry, mapData, mapRowPitch, *plan.replaced, srcLevel, plan.scaleFactor, dstFmt);
data = LoadTextureLevel(*entry, data, stride, *plan.replaced, srcLevel, plan.scaleFactor, texFmt);

ID3D11Texture2D *texture = DxTex(entry);
context_->UpdateSubresource(texture, i, nullptr, mapData, mapRowPitch, 0);
FreeAlignedMemory(mapData);
context_->UpdateSubresource(texture, i, nullptr, data, stride, 0);
FreeAlignedMemory(data);
}

if (levels == 1) {
Expand Down Expand Up @@ -594,70 +596,6 @@ CheckAlphaResult TextureCacheD3D11::CheckAlpha(const u32 *pixelData, u32 dstFmt,
}
}

void TextureCacheD3D11::LoadTextureLevel(TexCacheEntry &entry, uint8_t *mapData, int mapRowPitch, ReplacedTexture &replaced, int srcLevel, int scaleFactor, DXGI_FORMAT dstFmt) {
int w = gstate.getTextureWidth(srcLevel);
int h = gstate.getTextureHeight(srcLevel);

if (replaced.GetSize(srcLevel, w, h)) {
double replaceStart = time_now_d();
replaced.Load(srcLevel, mapData, mapRowPitch);
replacementTimeThisFrame_ += time_now_d() - replaceStart;
} else {
GETextureFormat tfmt = (GETextureFormat)entry.format;
GEPaletteFormat clutformat = gstate.getClutPaletteFormat();
u32 texaddr = gstate.getTextureAddress(srcLevel);
int bufw = GetTextureBufw(srcLevel, texaddr, tfmt);
u32 *pixelData;
int decPitch;
if (scaleFactor > 1) {
tmpTexBufRearrange_.resize(std::max(bufw, w) * h);
pixelData = tmpTexBufRearrange_.data();
// We want to end up with a neatly packed texture for scaling.
decPitch = w * 4;
} else {
pixelData = (u32 *)mapData;
decPitch = mapRowPitch;
}

bool expand32 = !gstate_c.Supports(GPU_SUPPORTS_16BIT_FORMATS) || scaleFactor > 1;

CheckAlphaResult alphaResult = DecodeTextureLevel((u8 *)pixelData, decPitch, tfmt, clutformat, texaddr, srcLevel, bufw, false, expand32);
entry.SetAlphaStatus(alphaResult, srcLevel);

if (scaleFactor > 1) {
// Note that this updates w and h!
scaler_.ScaleAlways((u32 *)mapData, pixelData, w, h, scaleFactor);
pixelData = (u32 *)mapData;

decPitch = w * 4;

if (decPitch != mapRowPitch) {
// Rearrange in place to match the requested pitch.
// (it can only be larger than w * bpp, and a match is likely.)
// Note! This is bad because it reads the mapped memory! TODO: Look into if DX9 does this right.
for (int y = h - 1; y >= 0; --y) {
memcpy((u8 *)mapData + mapRowPitch * y, (u8 *)mapData + decPitch * y, w * 4);
}
decPitch = mapRowPitch;
}
}

if (replacer_.Enabled()) {
ReplacedTextureDecodeInfo replacedInfo;
replacedInfo.cachekey = entry.CacheKey();
replacedInfo.hash = entry.fullhash;
replacedInfo.addr = entry.addr;
replacedInfo.isVideo = IsVideo(entry.addr);
replacedInfo.isFinal = (entry.status & TexCacheEntry::STATUS_TO_SCALE) == 0;
replacedInfo.scaleFactor = scaleFactor;
replacedInfo.fmt = FromD3D11Format(dstFmt);

// NOTE: Reading the decoded texture here may be very slow, if we just wrote it to write-combined memory.
replacer_.NotifyTextureDecoded(replacedInfo, pixelData, decPitch, srcLevel, w, h);
}
}
}

bool TextureCacheD3D11::GetCurrentTextureDebug(GPUDebugBuffer &buffer, int level) {
SetTexture();
if (!nextTexture_) {
Expand Down
1 change: 0 additions & 1 deletion GPU/D3D11/TextureCacheD3D11.h
Expand Up @@ -67,7 +67,6 @@ class TextureCacheD3D11 : public TextureCacheCommon {
void ReleaseTexture(TexCacheEntry *entry, bool delete_them) override;

private:
void LoadTextureLevel(TexCacheEntry &entry, uint8_t *mapData, int mapRowPitch, ReplacedTexture &replaced, int srcLevel, int scaleFactor, DXGI_FORMAT dstFmt);
DXGI_FORMAT GetDestFormat(GETextureFormat format, GEPaletteFormat clutFormat) const;
static CheckAlphaResult CheckAlpha(const u32 *pixelData, u32 dstFmt, int w);
void UpdateCurrentClut(GEPaletteFormat clutFormat, u32 clutBase, bool clutIndexIsSimple) override;
Expand Down
67 changes: 3 additions & 64 deletions GPU/Directx9/TextureCacheDX9.cpp
Expand Up @@ -443,6 +443,8 @@ void TextureCacheDX9::BuildTexture(TexCacheEntry *const entry) {
return;
}

Draw::DataFormat texFmt = FromD3D9Format(dstFmt);

// Mipmapping is only enabled when texture scaling is disabled.
for (int i = 0; i < levels; i++) {
int dstLevel = i;
Expand All @@ -458,7 +460,7 @@ void TextureCacheDX9::BuildTexture(TexCacheEntry *const entry) {
uint8_t *data = (uint8_t *)rect.pBits;
int stride = rect.Pitch;

LoadTextureLevel(*entry, data, stride, *plan.replaced, (i == 0) ? plan.baseLevelSrc : i, plan.scaleFactor, dstFmt);
data = LoadTextureLevel(*entry, data, stride, *plan.replaced, (i == 0) ? plan.baseLevelSrc : i, plan.scaleFactor, texFmt);

texture->UnlockRect(dstLevel);
}
Expand Down Expand Up @@ -504,69 +506,6 @@ CheckAlphaResult TextureCacheDX9::CheckAlpha(const u32 *pixelData, u32 dstFmt, i
}
}

void TextureCacheDX9::LoadTextureLevel(TexCacheEntry &entry, uint8_t *data, int stride, ReplacedTexture &replaced, int level, int scaleFactor, u32 dstFmt) {
int w = gstate.getTextureWidth(level);
int h = gstate.getTextureHeight(level);

if (replaced.GetSize(level, w, h)) {
double replaceStart = time_now_d();
replaced.Load(level, data, stride);
replacementTimeThisFrame_ += time_now_d() - replaceStart;
} else {
GETextureFormat tfmt = (GETextureFormat)entry.format;
GEPaletteFormat clutformat = gstate.getClutPaletteFormat();
u32 texaddr = gstate.getTextureAddress(level);

int bufw = GetTextureBufw(level, texaddr, tfmt);
int bpp = dstFmt == D3DFMT_A8R8G8B8 ? 4 : 2;

u32 *pixelData = (u32 *)data;
int decPitch = stride;

if (scaleFactor > 1) {
tmpTexBufRearrange_.resize(std::max(bufw, w) * h);
pixelData = tmpTexBufRearrange_.data();
// We want to end up with a neatly packed texture for scaling.
decPitch = w * bpp;
}

bool expand32 = scaleFactor > 1;

CheckAlphaResult alphaResult = DecodeTextureLevel((u8 *)pixelData, decPitch, tfmt, clutformat, texaddr, level, bufw, false, expand32);
entry.SetAlphaStatus(alphaResult, level);

if (scaleFactor > 1) {
scaler_.ScaleAlways((u32 *)data, pixelData, w, h, scaleFactor);
pixelData = (u32 *)data;

// We always end up at 8888. Other parts assume this.
_assert_(dstFmt == D3DFMT_A8R8G8B8);
bpp = sizeof(u32);
decPitch = w * bpp;

if (decPitch != stride) {
for (int y = h - 1; y >= 0; --y) {
memcpy(data + stride * y, (u8 *)data + decPitch * y, w * bpp);
}
decPitch = stride;
}
}

if (replacer_.Enabled()) {
ReplacedTextureDecodeInfo replacedInfo;
replacedInfo.cachekey = entry.CacheKey();
replacedInfo.hash = entry.fullhash;
replacedInfo.addr = entry.addr;
replacedInfo.isVideo = IsVideo(entry.addr);
replacedInfo.isFinal = (entry.status & TexCacheEntry::STATUS_TO_SCALE) == 0;
replacedInfo.scaleFactor = scaleFactor;
replacedInfo.fmt = FromD3D9Format(dstFmt);

replacer_.NotifyTextureDecoded(replacedInfo, pixelData, decPitch, level, w, h);
}
}
}

bool TextureCacheDX9::GetCurrentTextureDebug(GPUDebugBuffer &buffer, int level) {
SetTexture();
ApplyTexture();
Expand Down
1 change: 0 additions & 1 deletion GPU/Directx9/TextureCacheDX9.h
Expand Up @@ -61,7 +61,6 @@ class TextureCacheDX9 : public TextureCacheCommon {
private:
void ApplySamplingParams(const SamplerCacheKey &key);

void LoadTextureLevel(TexCacheEntry &entry, uint8_t *data, int stride, ReplacedTexture &replaced, int srcLevel, int scaleFactor, u32 dstFmt);
D3DFORMAT GetDestFormat(GETextureFormat format, GEPaletteFormat clutFormat) const;
static CheckAlphaResult CheckAlpha(const u32 *pixelData, u32 dstFmt, int w);
void UpdateCurrentClut(GEPaletteFormat clutFormat, u32 clutBase, bool clutIndexIsSimple) override;
Expand Down

0 comments on commit dea9794

Please sign in to comment.