Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Framebuffer-bind sequence numbers #15853

Merged
merged 4 commits into from
Aug 17, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 17 additions & 17 deletions GPU/Common/FramebufferManagerCommon.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -120,8 +120,8 @@ VirtualFramebuffer *FramebufferManagerCommon::GetVFBAt(u32 addr) const {
for (size_t i = 0; i < vfbs_.size(); ++i) {
VirtualFramebuffer *v = vfbs_[i];
if (v->fb_address == addr) {
// Could check w too but whatever
if (match == nullptr || match->last_frame_render < v->last_frame_render) {
// Could check w too but whatever (actually, might very well make sense to do so, depending on context).
if (!match || v->last_frame_render > match->last_frame_render) {
match = v;
}
}
Expand Down Expand Up @@ -275,7 +275,7 @@ VirtualFramebuffer *FramebufferManagerCommon::DoSetRenderFrameBuffer(const Frame
// As there are no clear "framebuffer width" and "framebuffer height" registers,
// we need to infer the size of the current framebuffer somehow.
int drawing_width, drawing_height;
EstimateDrawingSize(params.fb_address, params.fmt, params.viewportWidth, params.viewportHeight, params.regionWidth, params.regionHeight, params.scissorWidth, params.scissorHeight, std::max(params.fb_stride, 4), drawing_width, drawing_height);
EstimateDrawingSize(params.fb_address, params.fmt, params.viewportWidth, params.viewportHeight, params.regionWidth, params.regionHeight, params.scissorWidth, params.scissorHeight, std::max(params.fb_stride, (u16)4), drawing_width, drawing_height);

gstate_c.SetCurRTOffset(0, 0);
bool vfbFormatChanged = false;
Expand Down Expand Up @@ -530,6 +530,9 @@ VirtualFramebuffer *FramebufferManagerCommon::DoSetRenderFrameBuffer(const Frame
NotifyRenderFramebufferUpdated(vfb, vfbFormatChanged);
}

vfb->colorBindSeq = GetBindSeqCount();
vfb->depthBindSeq = GetBindSeqCount();

gstate_c.curRTWidth = vfb->width;
gstate_c.curRTHeight = vfb->height;
gstate_c.curRTRenderWidth = vfb->renderWidth;
Expand Down Expand Up @@ -692,8 +695,7 @@ void FramebufferManagerCommon::NotifyRenderFramebufferUpdated(VirtualFramebuffer
void FramebufferManagerCommon::NotifyRenderFramebufferSwitched(VirtualFramebuffer *prevVfb, VirtualFramebuffer *vfb, bool isClearingDepth) {
if (ShouldDownloadFramebuffer(vfb) && !vfb->memoryUpdated) {
ReadFramebufferToMemory(vfb, 0, 0, vfb->width, vfb->height);
vfb->usageFlags = (vfb->usageFlags | FB_USAGE_DOWNLOAD) & ~FB_USAGE_DOWNLOAD_CLEAR;
vfb->firstFrameSaved = true;
vfb->usageFlags = (vfb->usageFlags | FB_USAGE_DOWNLOAD | FB_USAGE_FIRST_FRAME_SAVED) & ~FB_USAGE_DOWNLOAD_CLEAR;
} else {
DownloadFramebufferOnSwitch(prevVfb);
}
Expand Down Expand Up @@ -1026,14 +1028,13 @@ void FramebufferManagerCommon::DrawFramebufferToOutput(const u8 *srcPixels, GEBu
}

void FramebufferManagerCommon::DownloadFramebufferOnSwitch(VirtualFramebuffer *vfb) {
if (vfb && vfb->safeWidth > 0 && vfb->safeHeight > 0 && !vfb->firstFrameSaved && !vfb->memoryUpdated) {
if (vfb && vfb->safeWidth > 0 && vfb->safeHeight > 0 && !(vfb->usageFlags & FB_USAGE_FIRST_FRAME_SAVED) && !vfb->memoryUpdated) {
// Some games will draw to some memory once, and use it as a render-to-texture later.
// To support this, we save the first frame to memory when we have a safe w/h.
// Saving each frame would be slow.
if (!g_Config.bDisableSlowFramebufEffects && !PSP_CoreParameter().compat.flags().DisableFirstFrameReadback) {
ReadFramebufferToMemory(vfb, 0, 0, vfb->safeWidth, vfb->safeHeight);
vfb->usageFlags = (vfb->usageFlags | FB_USAGE_DOWNLOAD) & ~FB_USAGE_DOWNLOAD_CLEAR;
vfb->firstFrameSaved = true;
vfb->usageFlags = (vfb->usageFlags | FB_USAGE_DOWNLOAD | FB_USAGE_FIRST_FRAME_SAVED) & ~FB_USAGE_DOWNLOAD_CLEAR;
vfb->safeWidth = 0;
vfb->safeHeight = 0;
}
Expand Down Expand Up @@ -1198,8 +1199,7 @@ void FramebufferManagerCommon::DecimateFBOs() {

if (ShouldDownloadFramebuffer(vfb) && age == 0 && !vfb->memoryUpdated) {
ReadFramebufferToMemory(vfb, 0, 0, vfb->width, vfb->height);
vfb->usageFlags = (vfb->usageFlags | FB_USAGE_DOWNLOAD) & ~FB_USAGE_DOWNLOAD_CLEAR;
vfb->firstFrameSaved = true;
vfb->usageFlags = (vfb->usageFlags | FB_USAGE_DOWNLOAD | FB_USAGE_FIRST_FRAME_SAVED) & ~FB_USAGE_DOWNLOAD_CLEAR;
}

// Let's also "decimate" the usageFlags.
Expand Down Expand Up @@ -1286,7 +1286,7 @@ void FramebufferManagerCommon::ResizeFramebufFBO(VirtualFramebuffer *vfb, int w,
}

if (force1x && g_Config.iInternalResolution != 1) {
vfb->renderScaleFactor = 1.0f;
vfb->renderScaleFactor = 1;
vfb->renderWidth = vfb->bufferWidth;
vfb->renderHeight = vfb->bufferHeight;
} else {
Expand Down Expand Up @@ -1654,7 +1654,7 @@ VirtualFramebuffer *FramebufferManagerCommon::FindDownloadTempBuffer(VirtualFram
nvfb->height = vfb->height;
nvfb->renderWidth = vfb->bufferWidth;
nvfb->renderHeight = vfb->bufferHeight;
nvfb->renderScaleFactor = 1.0f; // For readbacks we resize to the original size, of course.
nvfb->renderScaleFactor = 1; // For readbacks we resize to the original size, of course.
nvfb->bufferWidth = vfb->bufferWidth;
nvfb->bufferHeight = vfb->bufferHeight;
nvfb->format = vfb->format;
Expand Down Expand Up @@ -2023,7 +2023,7 @@ void FramebufferManagerCommon::ShowScreenResolution() {
// * Video file recording(would probably be great if it was async.)
// * Screenshots(benefit slightly from async.)
// * Save state screenshots(could probably be async but need to manage the stall.)
bool FramebufferManagerCommon::GetFramebuffer(u32 fb_address, int fb_stride, GEBufferFormat format, GPUDebugBuffer &buffer, int maxRes) {
bool FramebufferManagerCommon::GetFramebuffer(u32 fb_address, int fb_stride, GEBufferFormat format, GPUDebugBuffer &buffer, int maxScaleFactor) {
VirtualFramebuffer *vfb = currentRenderVfb_;
if (!vfb) {
vfb = GetVFBAt(fb_address);
Expand All @@ -2042,9 +2042,9 @@ bool FramebufferManagerCommon::GetFramebuffer(u32 fb_address, int fb_stride, GEB
Draw::Framebuffer *bound = nullptr;

if (vfb->fbo) {
if (maxRes > 0 && vfb->renderWidth > vfb->width * maxRes) {
w = vfb->width * maxRes;
h = vfb->height * maxRes;
if (maxScaleFactor > 0 && vfb->renderWidth > vfb->width * maxScaleFactor) {
w = vfb->width * maxScaleFactor;
h = vfb->height * maxScaleFactor;

Draw::Framebuffer *tempFBO = GetTempFBO(TempFBO::COPY, w, h);
VirtualFramebuffer tempVfb = *vfb;
Expand All @@ -2053,7 +2053,7 @@ bool FramebufferManagerCommon::GetFramebuffer(u32 fb_address, int fb_stride, GEB
tempVfb.bufferHeight = vfb->height;
tempVfb.renderWidth = w;
tempVfb.renderHeight = h;
tempVfb.renderScaleFactor = (float)maxRes;
tempVfb.renderScaleFactor = maxScaleFactor;
BlitFramebuffer(&tempVfb, 0, 0, vfb, 0, 0, vfb->width, vfb->height, 0, "Blit_GetFramebuffer");

bound = tempFBO;
Expand Down
82 changes: 60 additions & 22 deletions GPU/Common/FramebufferManagerCommon.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ enum {
FB_USAGE_DOWNLOAD = 16,
FB_USAGE_DOWNLOAD_CLEAR = 32,
FB_USAGE_BLUE_TO_ALPHA = 64,
FB_USAGE_FIRST_FRAME_SAVED = 128,
};

enum {
Expand All @@ -63,48 +64,79 @@ class ShaderWriter;
// when such a situation is detected. In order to reliably detect this, we separately track depth buffers,
// and they know which color buffer they were used with last.
struct VirtualFramebuffer {
Draw::Framebuffer *fbo;

u32 fb_address;
u32 z_address; // If 0, it's a "RAM" framebuffer.
int fb_stride;
int z_stride;

GEBufferFormat format; // virtual, in reality they are all RGBA8888 for better quality but we can reinterpret that as necessary
u16 fb_stride;
u16 z_stride;

// width/height: The detected size of the current framebuffer, in original PSP pixels.
u16 width;
u16 height;

// bufferWidth/bufferHeight: The pre-scaling size of the buffer itself. May only be bigger than or equal to width/height.
// Actual physical buffer is this size times the render resolution multiplier.
// In original PSP pixels - actual framebuffer is this size times the render resolution multiplier.
// The buffer may be used to render a width or height from 0 to these values without being recreated.
u16 bufferWidth;
u16 bufferHeight;

// renderWidth/renderHeight: The scaled size we render at. May be scaled to render at higher resolutions.
// The physical buffer may be larger than renderWidth/renderHeight.
// These are simply bufferWidth/Height * renderScaleFactor and are thus redundant.
u16 renderWidth;
u16 renderHeight;

float renderScaleFactor;
// Attempt to keep track of a bounding rectangle of what's been actually drawn. Coarse, but might be smaller
// than width/height if framebuffer has been enlarged. In PSP pixels.
u16 drawnWidth;
u16 drawnHeight;

// The dimensions at which we are confident that we can read back this buffer without stomping on irrelevant memory.
u16 safeWidth;
u16 safeHeight;

// The scale factor at which we are rendering (to achieve higher resolution).
u8 renderScaleFactor;

// The original PSP format of the framebuffer.
// In reality they are all RGBA8888 for better quality but this is what the PSP thinks it is. This is necessary
// when we need to interpret the bits directly (depal or buffer aliasing).
GEBufferFormat format;

// The configured buffer format at the time of the latest/current draw. This will change first, then
// if different we'll "reinterpret" the framebuffer to match 'format' as needed.
GEBufferFormat drawnFormat;

u16 usageFlags;

// These are used to track state to try to avoid buffer size shifting back and forth.
// You might think that doesn't happen since we mostly grow framebuffers, but we do resize down,
// if the size has shrunk for a while and the framebuffer is also larger than the stride.
// At this point, the "safe" size is probably a lie, and we have had various issues with readbacks, so this resizes down to avoid them.
// An example would be a game that always uses the address 0x00154000 for temp buffers, and uses it for a full-screen effect for 3 frames, then goes back to using it for character shadows or something much smaller.
u16 newWidth;
u16 newHeight;

// The frame number at which this was last resized.
int lastFrameNewSize;

Draw::Framebuffer *fbo;

u16 drawnWidth;
u16 drawnHeight;
GEBufferFormat drawnFormat;
u16 safeWidth;
u16 safeHeight;
// Tracking for downloads-to-CLUT.
u16 clutUpdatedBytes;
bool memoryUpdated;

// TODO: Fold into usageFlags?
bool dirtyAfterDisplay;
bool reallyDirtyAfterDisplay; // takes frame skipping into account

// Global sequence numbers for the last time these were bound.
// Not based on frames at all. Can be used to determine new-ness of one framebuffer over another,
// can even be within a frame.
int colorBindSeq;
int depthBindSeq;

// These are mainly used for garbage collection purposes and similar.
// Cannot be used to determine new-ness against a similar other buffer, since they are
// only at frame granularity.
int last_frame_used;
int last_frame_attached;
int last_frame_render;
Expand All @@ -113,9 +145,6 @@ struct VirtualFramebuffer {
int last_frame_failed;
int last_frame_depth_updated;
int last_frame_depth_render;
u32 clutUpdatedBytes;
bool memoryUpdated;
bool firstFrameSaved;
};

struct TrackedDepthBuffer {
Expand All @@ -132,9 +161,9 @@ struct TrackedDepthBuffer {

struct FramebufferHeuristicParams {
u32 fb_address;
int fb_stride;
u32 z_address;
int z_stride;
u16 fb_stride;
u16 z_stride;
GEBufferFormat fmt;
bool isClearingDepth;
bool isWritingDepth;
Expand Down Expand Up @@ -308,8 +337,10 @@ class FramebufferManagerCommon {
VirtualFramebuffer *GetCurrentRenderVFB() const {
return currentRenderVfb_;
}
// TODO: Break out into some form of FBO manager

// This only checks for the color channel.
VirtualFramebuffer *GetVFBAt(u32 addr) const;

VirtualFramebuffer *GetDisplayVFB() const {
return GetVFBAt(displayFramebufPtr_);
}
Expand Down Expand Up @@ -412,6 +443,10 @@ class FramebufferManagerCommon {
dstBuffer->reallyDirtyAfterDisplay = true;
}

inline int GetBindSeqCount() {
return fbBindSeqCount_++;
}

PresentationCommon *presentation_ = nullptr;

Draw::DrawContext *draw_ = nullptr;
Expand All @@ -427,6 +462,8 @@ class FramebufferManagerCommon {
GEBufferFormat displayFormat_ = GE_FORMAT_565;
u32 prevDisplayFramebufPtr_ = 0;

int fbBindSeqCount_ = 0;

VirtualFramebuffer *displayFramebuf_ = nullptr;
VirtualFramebuffer *prevDisplayFramebuf_ = nullptr;
VirtualFramebuffer *prevPrevDisplayFramebuf_ = nullptr;
Expand All @@ -451,7 +488,8 @@ class FramebufferManagerCommon {
// Sampled in BeginFrame/UpdateSize for safety.
float renderWidth_ = 0.0f;
float renderHeight_ = 0.0f;
float renderScaleFactor_ = 1.0f;

int renderScaleFactor_ = 1;
int pixelWidth_ = 0;
int pixelHeight_ = 0;
int bloomHack_ = 0;
Expand Down Expand Up @@ -481,7 +519,7 @@ class FramebufferManagerCommon {
Draw::SamplerState *reinterpretSampler_ = nullptr;
Draw::Buffer *reinterpretVBuf_ = nullptr;

// Common implementation of stencil buffer upload. Also not 100% optimal, but not perforamnce
// Common implementation of stencil buffer upload. Also not 100% optimal, but not performance
// critical either.
Draw::Pipeline *stencilUploadPipeline_ = nullptr;
Draw::SamplerState *stencilUploadSampler_ = nullptr;
Expand Down
2 changes: 1 addition & 1 deletion GPU/GLES/DepthBufferGLES.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ void FramebufferManagerGLES::PackDepthbuffer(VirtualFramebuffer *vfb, int x, int
// Pixel size always 4 here because we always request float
const u32 bufSize = vfb->z_stride * (h - y) * 4;
const u32 z_address = vfb->z_address;
const int packWidth = std::min(vfb->z_stride, std::min(x + w, (int)vfb->width));
const int packWidth = std::min((int)vfb->z_stride, std::min(x + w, (int)vfb->width));

if (!convBuf_ || convBufSize_ < bufSize) {
delete[] convBuf_;
Expand Down
5 changes: 3 additions & 2 deletions GPU/ge_constants.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@

#pragma once

#include <cstdint>

enum GECommand {
GE_CMD_NOP = 0,
GE_CMD_VADDR = 0x1,
Expand Down Expand Up @@ -276,8 +278,7 @@ enum GECommand {
GE_CMD_NOP_FF = 0xFF,
};

enum GEBufferFormat
{
enum GEBufferFormat : uint8_t {
GE_FORMAT_565 = 0,
GE_FORMAT_5551 = 1,
GE_FORMAT_4444 = 2,
Expand Down