mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-11-13 01:29:41 +01:00
Display: Don't read past memory presenting a framebuffer from RAM
The PSP accepts display strides that run past the end of VRAM, and negative ones (setframebuf.expected has -64 and 2048), and presenting straight from memory read all 272 rows of whatever stride was set. Without a matching framebuffer, that's a read far outside PSP memory. Now the whole image has to be in memory, or the display shows black, on the hardware backends and the software renderer. A savestate's display framebuffer with an address outside RAM and VRAM, or an invalid format, turns the display off instead. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
ef8961e17a
commit
fa3eff96fb
3 files changed
+30
-3
No files matched your search
@@ -1479,6 +1479,16 @@ void FramebufferManagerCommon::CopyFramebufferForColorTexture(VirtualFramebuffer
|
||||
}
|
||||
}
|
||||
|
||||
// Whether the 480x272 the display shows from addr is all in memory. The PSP takes strides that
|
||||
// aren't: negative ones (rows going up, which this doesn't handle), and larger than VRAM has room for.
|
||||
static bool IsValidDisplayRange(u32 addr, int stride, GEBufferFormat format) {
|
||||
if (stride <= 0) {
|
||||
return false;
|
||||
}
|
||||
const u32 bpp = BufferFormatBytesPerPixel(format);
|
||||
return Memory::IsValidRange(addr, ((272 - 1) * (u32)stride + 480) * bpp);
|
||||
}
|
||||
|
||||
Draw::Texture *FramebufferManagerCommon::MakePixelTexture(const u8 *srcPixels, GEBufferFormat srcPixelFormat, int srcStride, int width, int height) {
|
||||
Draw::DataFormat depthFormat = Draw::DataFormat::UNDEFINED;
|
||||
|
||||
@@ -1787,7 +1797,7 @@ void FramebufferManagerCommon::PrepareCopyDisplayToOutput(const DisplayLayoutCon
|
||||
VirtualFramebuffer *vfb = FindDisplayVFB(fbaddr, &offsetX, &offsetY);
|
||||
|
||||
if (!vfb) {
|
||||
if (Memory::IsValidAddress(fbaddr)) {
|
||||
if (IsValidDisplayRange(fbaddr, displayStride_, displayFormat_)) {
|
||||
// The game is displaying something directly from RAM. In GTA, it's decoded video.
|
||||
// If successful, this effectively calls presentation_->NotifyPresent();
|
||||
if (!DrawFramebufferToOutput(config, Memory::GetPointerUnchecked(fbaddr), displayStride_, displayFormat_)) {
|
||||
@@ -3018,7 +3028,7 @@ void FramebufferManagerCommon::NotifyBlockTransferAfter(u32 dstBasePtr, int dstS
|
||||
if (!useBufferedRendering_ && dstStride >= 480 && width >= 480 && height == 272) {
|
||||
bool isPrevDisplayBuffer = PrevDisplayFramebufAddr() == dstBasePtr;
|
||||
bool isDisplayBuffer = CurrentDisplayFramebufAddr() == dstBasePtr;
|
||||
if (isPrevDisplayBuffer || isDisplayBuffer) {
|
||||
if ((isPrevDisplayBuffer || isDisplayBuffer) && IsValidDisplayRange(dstBasePtr, dstStride, displayFormat_)) {
|
||||
FlushBeforeCopy();
|
||||
// HACK
|
||||
DrawFramebufferToOutput(displayLayoutConfigCopy_, Memory::GetPointerUnchecked(dstBasePtr), dstStride, displayFormat_);
|
||||
|
||||
Reference in new issue
Block a user