mirror of
https://github.com/hrydgard/ppsspp.git
synced 2024-11-27 07:20:49 +00:00
Reinterpret the data when binding a framebuffer with a different 16-bit format.
Car reflections in Outrun are better (see #11358) but have some blue/yellow color garbage that will need a different fix.
This commit is contained in:
parent
1ccc8c129c
commit
981d0a2abe
@ -584,7 +584,7 @@ void FramebufferManagerCommon::ReformatFramebufferFrom(VirtualFramebuffer *vfb,
|
||||
}
|
||||
|
||||
// Copy to a temp framebuffer.
|
||||
Draw::Framebuffer *temp = GetTempFBO(TempFBO::COPY, vfb->renderWidth, vfb->renderHeight);
|
||||
Draw::Framebuffer *temp = GetTempFBO(TempFBO::REINTERPRET, vfb->renderWidth, vfb->renderHeight);
|
||||
|
||||
draw_->CopyFramebufferImage(vfb->fbo, 0, 0, 0, 0, temp, 0, 0, 0, 0, vfb->renderWidth, vfb->renderHeight, 1, Draw::FBChannel::FB_COLOR_BIT, "reinterpret_prep");
|
||||
draw_->BindFramebufferAsRenderTarget(vfb->fbo, { Draw::RPAction::DONT_CARE, Draw::RPAction::DONT_CARE, Draw::RPAction::DONT_CARE }, "reinterpret");
|
||||
|
@ -158,6 +158,8 @@ enum class TempFBO {
|
||||
BLIT,
|
||||
// For copies of framebuffers (e.g. shader blending.)
|
||||
COPY,
|
||||
// For another type of framebuffers that can happen together with COPY (see Outrun)
|
||||
REINTERPRET,
|
||||
// Used to copy stencil data, means we need a stencil backing.
|
||||
STENCIL,
|
||||
};
|
||||
@ -320,6 +322,7 @@ public:
|
||||
const std::vector<VirtualFramebuffer *> &Framebuffers() {
|
||||
return vfbs_;
|
||||
}
|
||||
void ReformatFramebufferFrom(VirtualFramebuffer *vfb, GEBufferFormat old);
|
||||
|
||||
protected:
|
||||
virtual void PackFramebufferSync_(VirtualFramebuffer *vfb, int x, int y, int w, int h);
|
||||
@ -344,7 +347,6 @@ protected:
|
||||
void NotifyRenderFramebufferUpdated(VirtualFramebuffer *vfb, bool vfbFormatChanged);
|
||||
void NotifyRenderFramebufferSwitched(VirtualFramebuffer *prevVfb, VirtualFramebuffer *vfb, bool isClearingDepth);
|
||||
|
||||
void ReformatFramebufferFrom(VirtualFramebuffer *vfb, GEBufferFormat old);
|
||||
void BlitFramebufferDepth(VirtualFramebuffer *src, VirtualFramebuffer *dst);
|
||||
|
||||
void ResizeFramebufFBO(VirtualFramebuffer *vfb, int w, int h, bool force = false, bool skipCopy = false);
|
||||
|
@ -486,9 +486,10 @@ TexCacheEntry *TextureCacheCommon::SetTexture() {
|
||||
DeleteTexture(entryIter);
|
||||
}
|
||||
|
||||
const AttachCandidate &candidate = candidates[index];
|
||||
nextTexture_ = nullptr;
|
||||
nextNeedsRebuild_ = false;
|
||||
SetTextureFramebuffer(candidates[index]);
|
||||
SetTextureFramebuffer(candidate);
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
@ -849,11 +850,19 @@ FramebufferMatchInfo TextureCacheCommon::MatchFramebuffer(
|
||||
WARN_LOG_ONCE(diffStrides1, G3D, "Texturing from framebuffer with different strides %d != %d", entry.bufw, framebuffer->fb_stride);
|
||||
}
|
||||
// NOTE: This check is okay because the first texture formats are the same as the buffer formats.
|
||||
if (entry.format != (GETextureFormat)framebuffer->format) {
|
||||
WARN_LOG_ONCE(diffFormat1, G3D, "Texturing from framebuffer with different formats %s != %s", GeTextureFormatToString(entry.format), GeBufferFormatToString(framebuffer->format));
|
||||
return FramebufferMatchInfo{ FramebufferMatch::NO_MATCH };
|
||||
} else {
|
||||
if (IsTextureFormatBufferCompatible(entry.format)) {
|
||||
if (TextureFormatMatchesBufferFormat(entry.format, framebuffer->format)) {
|
||||
return FramebufferMatchInfo{ FramebufferMatch::VALID };
|
||||
} else if (IsTextureFormat16Bit(entry.format) && IsBufferFormat16Bit(framebuffer->format)) {
|
||||
WARN_LOG_ONCE(diffFormat1, G3D, "Texturing from framebuffer with reinterpretable format: %s != %s", GeTextureFormatToString(entry.format), GeBufferFormatToString(framebuffer->format));
|
||||
return FramebufferMatchInfo{ FramebufferMatch::VALID, 0, 0, true, TextureFormatToBufferFormat(entry.format) };
|
||||
} else {
|
||||
WARN_LOG_ONCE(diffFormat2, G3D, "Texturing from framebuffer with incompatible formats %s != %s", GeTextureFormatToString(entry.format), GeBufferFormatToString(framebuffer->format));
|
||||
return FramebufferMatchInfo{ FramebufferMatch::NO_MATCH };
|
||||
}
|
||||
} else {
|
||||
// Format incompatible, ignoring without comment. (maybe some really gnarly hacks will end up here...)
|
||||
return FramebufferMatchInfo{ FramebufferMatch::NO_MATCH };
|
||||
}
|
||||
} else {
|
||||
// Apply to buffered mode only.
|
||||
@ -944,6 +953,13 @@ void TextureCacheCommon::SetTextureFramebuffer(const AttachCandidate &candidate)
|
||||
VirtualFramebuffer *framebuffer = candidate.fb;
|
||||
FramebufferMatchInfo fbInfo = candidate.match;
|
||||
|
||||
if (candidate.match.reinterpret) {
|
||||
// TODO: Kinda ugly, maybe switch direction of the call?
|
||||
GEBufferFormat oldFormat = candidate.fb->format;
|
||||
candidate.fb->format = candidate.match.reinterpretTo;
|
||||
framebufferManager_->ReformatFramebufferFrom(candidate.fb, oldFormat);
|
||||
}
|
||||
|
||||
_dbg_assert_msg_(framebuffer != nullptr, "Framebuffer must not be null.");
|
||||
|
||||
framebuffer->usageFlags |= FB_USAGE_TEXTURE;
|
||||
|
@ -212,6 +212,8 @@ struct FramebufferMatchInfo {
|
||||
FramebufferMatch match;
|
||||
u32 xOffset;
|
||||
u32 yOffset;
|
||||
bool reinterpret;
|
||||
GEBufferFormat reinterpretTo;
|
||||
};
|
||||
|
||||
struct AttachCandidate {
|
||||
|
@ -419,12 +419,33 @@ enum GETextureFormat
|
||||
GE_TFMT_DXT5 = 10,
|
||||
};
|
||||
|
||||
const char *GeTextureFormatToString(GETextureFormat fmt);
|
||||
inline bool IsClutFormat(GETextureFormat fmt) {
|
||||
return fmt == GE_TFMT_CLUT4 || fmt == GE_TFMT_CLUT8 || fmt == GE_TFMT_CLUT16 || fmt == GE_TFMT_CLUT32;
|
||||
const char *GeTextureFormatToString(GETextureFormat tfmt);
|
||||
inline bool IsClutFormat(GETextureFormat tfmt) {
|
||||
return tfmt == GE_TFMT_CLUT4 || tfmt == GE_TFMT_CLUT8 || tfmt == GE_TFMT_CLUT16 || tfmt == GE_TFMT_CLUT32;
|
||||
}
|
||||
inline bool IsDXTFormat(GETextureFormat fmt) {
|
||||
return fmt == GE_TFMT_DXT1 || fmt == GE_TFMT_DXT3 || fmt == GE_TFMT_DXT5;
|
||||
inline bool IsDXTFormat(GETextureFormat tfmt) {
|
||||
return tfmt == GE_TFMT_DXT1 || tfmt == GE_TFMT_DXT3 || tfmt == GE_TFMT_DXT5;
|
||||
}
|
||||
inline bool IsTextureFormatBufferCompatible(GETextureFormat tfmt) {
|
||||
return (int)tfmt < 4;
|
||||
}
|
||||
inline bool IsBufferFormat16Bit(GEBufferFormat bfmt) {
|
||||
return (int)bfmt < 3;
|
||||
}
|
||||
inline bool IsTextureFormat16Bit(GETextureFormat tfmt) {
|
||||
return (int)tfmt < 3;
|
||||
}
|
||||
inline bool TextureFormatMatchesBufferFormat(GETextureFormat fmt, GEBufferFormat bfmt) {
|
||||
// First four matches perfectly.
|
||||
if ((int)fmt < 4) {
|
||||
return (int)fmt == (int)bfmt;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// only applicable if IsTextureFormatBufferCompatible(fmt)
|
||||
inline GEBufferFormat TextureFormatToBufferFormat(GETextureFormat bfmt) {
|
||||
return (GEBufferFormat)(int)bfmt;
|
||||
}
|
||||
|
||||
enum GETexLevelMode {
|
||||
|
Loading…
Reference in New Issue
Block a user