Merge pull request #21218 from hrydgard/renderpass-refactor

Preparations for a rendering refactor
This commit is contained in:
Henrik Rydgård authored and GitHub committed 2026-02-08 10:04:17 +01:00
commit 37052cc1ae
17 files changed
+163 -137

No files matched your search

+39 -67
View File
@@ -20,7 +20,7 @@ void VFS::Register(std::string_view prefix, VFSBackend *reader) {
void VFS::Clear() {
for (auto &entry : entries_) {
delete entry.reader;
delete entry.backend;
}
entries_.clear();
}
@@ -37,6 +37,21 @@ static bool IsLocalAbsolutePath(std::string_view path) {
return isUnixLocal || isWindowsLocal || isContentURI;
}
bool VFS::MapPath(std::string_view path, VFSBackend **backend, std::string_view *relativePath) {
int fn_len = (int)path.length();
for (const auto &entry : entries_) {
int prefix_len = (int)entry.prefix.length();
if (prefix_len >= fn_len) continue;
if (0 == memcmp(path.data(), entry.prefix.data(), prefix_len)) {
*backend = entry.backend;
*relativePath = path.substr(prefix_len);
return true;
}
}
ERROR_LOG(Log::IO, "VFS: '%.*s' has an unknown filesystem prefix.", STR_VIEW(path));
return false;
}
// The returned data should be free'd with delete[].
uint8_t *VFS::ReadFile(std::string_view filename, size_t *size) {
if (IsLocalAbsolutePath(filename)) {
@@ -45,26 +60,13 @@ uint8_t *VFS::ReadFile(std::string_view filename, size_t *size) {
return File::ReadLocalFile(Path(filename), size);
}
const int fn_len = (int)filename.length();
bool fileSystemFound = false;
for (const auto &entry : entries_) {
int prefix_len = (int)entry.prefix.length();
if (prefix_len >= fn_len) continue;
if (0 == memcmp(filename.data(), entry.prefix.data(), prefix_len)) {
fileSystemFound = true;
// INFO_LOG(Log::IO, "Prefix match: %s (%s) -> %s", entries[i].prefix, filename, filename + prefix_len);
uint8_t *data = entry.reader->ReadFile(filename.substr(prefix_len), size);
if (data)
return data;
else
continue;
// Else try the other registered file systems.
}
VFSBackend *backend = nullptr;
std::string_view relativePath;
if (!MapPath(filename, &backend, &relativePath)) {
return nullptr;
}
if (!fileSystemFound) {
ERROR_LOG(Log::IO, "Missing filesystem for '%.*s'", STR_VIEW(filename));
} // Otherwise, the file was just missing. No need to log.
return nullptr;
return backend->ReadFile(relativePath, size);
}
bool VFS::GetFileListing(std::string_view path, std::vector<File::FileInfo> *listing, const char *filter) {
@@ -75,23 +77,13 @@ bool VFS::GetFileListing(std::string_view path, std::vector<File::FileInfo> *lis
return true;
}
int fn_len = (int)path.length();
bool fileSystemFound = false;
for (const auto &entry : entries_) {
int prefix_len = (int)entry.prefix.length();
if (prefix_len >= fn_len) continue;
if (0 == memcmp(path.data(), entry.prefix.data(), prefix_len)) {
fileSystemFound = true;
if (entry.reader->GetFileListing(path.substr(prefix_len), listing, filter)) {
return true;
}
}
VFSBackend *backend = nullptr;
std::string_view relativePath;
if (!MapPath(path, &backend, &relativePath)) {
return false;
}
if (!fileSystemFound) {
ERROR_LOG(Log::IO, "Missing filesystem for %.*s", STR_VIEW(path));
} // Otherwise, the file was just missing. No need to log.
return false;
return backend->GetFileListing(relativePath, listing, filter);
}
bool VFS::GetFileInfo(std::string_view path, File::FileInfo *info) {
@@ -101,23 +93,13 @@ bool VFS::GetFileInfo(std::string_view path, File::FileInfo *info) {
return File::GetFileInfo(Path(path), info);
}
bool fileSystemFound = false;
int fn_len = (int)path.length();
for (const auto &entry : entries_) {
int prefix_len = (int)entry.prefix.length();
if (prefix_len >= fn_len) continue;
if (0 == memcmp(path.data(), entry.prefix.data(), prefix_len)) {
fileSystemFound = true;
if (entry.reader->GetFileInfo(path.substr(prefix_len), info))
return true;
else
continue;
}
VFSBackend *backend = nullptr;
std::string_view relativePath;
if (!MapPath(path, &backend, &relativePath)) {
return false;
}
if (!fileSystemFound) {
ERROR_LOG(Log::IO, "Missing filesystem for '%.*s'", STR_VIEW(path));
} // Otherwise, the file was just missing. No need to log.
return false;
return backend->GetFileInfo(relativePath, info);
}
bool VFS::Exists(std::string_view path) {
@@ -127,21 +109,11 @@ bool VFS::Exists(std::string_view path) {
return File::Exists(Path(path));
}
bool fileSystemFound = false;
int fn_len = (int)path.length();
for (const auto &entry : entries_) {
int prefix_len = (int)entry.prefix.length();
if (prefix_len >= fn_len) continue;
if (0 == memcmp(path.data(), entry.prefix.data(), prefix_len)) {
fileSystemFound = true;
if (entry.reader->Exists(path.substr(prefix_len)))
return true;
else
continue;
}
VFSBackend *backend = nullptr;
std::string_view relativePath;
if (!MapPath(path, &backend, &relativePath)) {
return false;
}
if (!fileSystemFound) {
ERROR_LOG(Log::IO, "Missing filesystem for '%.*s'", STR_VIEW(path));
} // Otherwise, the file was just missing. No need to log.
return false;
return backend->Exists(relativePath);
}
+3 -1
View File
@@ -81,9 +81,11 @@ public:
bool Exists(std::string_view path);
private:
bool MapPath(std::string_view filename, VFSBackend **backend, std::string_view *relativePath);
struct VFSEntry {
std::string_view prefix;
VFSBackend *reader;
VFSBackend *backend;
};
std::vector<VFSEntry> entries_;
};
+2 -1
View File
@@ -661,7 +661,8 @@ void __DisplayFlip(int cyclesLate) {
}
}
if (nextFrame) {
gpu->CopyDisplayToOutput(g_displayLayoutConfigCached, fbReallyDirty);
gpu->SetCurFramebufferDirty(fbReallyDirty);
gpu->CopyDisplayToOutput(g_displayLayoutConfigCached);
if (fbReallyDirty) {
DisplayFireActualFlip();
}
+1 -1
View File
@@ -795,7 +795,7 @@ static int ptp_send_postoffice(int idx, const void *data, int *len) {
}
if (ptp_send_status == AEMU_POSTOFFICE_CLIENT_OUT_OF_MEMORY) {
// this is pretty critical
ERROR_LOG(Log::sceNet, "%s: critical: huge client buf %d what is going on please fix", __func__, len);
ERROR_LOG(Log::sceNet, "%s: critical: huge client buf %d what is going on please fix", __func__, len ? *len : 0);
}
return 0;
+15 -8
View File
@@ -1536,15 +1536,15 @@ Draw::Texture *FramebufferManagerCommon::MakePixelTexture(const u8 *srcPixels, G
return tex;
}
// This is internal, called from CopyDisplayToOutput.
bool FramebufferManagerCommon::DrawFramebufferToOutput(const DisplayLayoutConfig &config, const u8 *srcPixels, int srcStride, GEBufferFormat srcPixelFormat) {
textureCache_->ForgetLastTexture();
shaderManager_->DirtyLastShader();
float u0 = 0.0f, u1 = 480.0f / 512.0f;
float v0 = 0.0f, v1 = 1.0f;
Draw::Texture *pixelsTex = MakePixelTexture(srcPixels, srcPixelFormat, srcStride, 512, 272);
if (!pixelsTex)
if (!pixelsTex) {
return false;
}
int uvRotation = useBufferedRendering_ ? config.iInternalScreenRotation : ROTATION_LOCKED_HORIZONTAL;
OutputFlags flags = config.iDisplayFilter == SCALE_LINEAR ? OutputFlags::LINEAR : OutputFlags::NEAREST;
@@ -1556,16 +1556,18 @@ bool FramebufferManagerCommon::DrawFramebufferToOutput(const DisplayLayoutConfig
flags |= OutputFlags::POSITION_FLIPPED;
}
constexpr float u0 = 0.0f, u1 = 480.0f / 512.0f;
constexpr float v0 = 0.0f, v1 = 1.0f;
presentation_->UpdateUniforms(textureCache_->VideoIsPlaying());
presentation_->SourceTexture(pixelsTex, 512, 272);
presentation_->CopyToOutput(config, flags, uvRotation, u0, v0, u1, v1);
presentation_->RunPostshaderPasses(config, flags, uvRotation, u0, v0, u1, v1);
// PresentationCommon sets all kinds of state, we can't rely on anything.
gstate_c.Dirty(DIRTY_ALL);
DiscardFramebufferCopy();
currentRenderVfb_ = nullptr;
return true;
}
@@ -1649,7 +1651,9 @@ void FramebufferManagerCommon::CopyDisplayToOutput(const DisplayLayoutConfig &co
if (Memory::IsValidAddress(fbaddr)) {
// 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_)) {
if (DrawFramebufferToOutput(config, Memory::GetPointerUnchecked(fbaddr), displayStride_, displayFormat_)) {
presentation_->CopyToOutput(config);
} else {
if (useBufferedRendering_) {
// Bind and clear the backbuffer. This should be the first time during the frame that it's bound.
draw_->BindFramebufferAsRenderTarget(nullptr, { Draw::RPAction::CLEAR, Draw::RPAction::CLEAR, Draw::RPAction::CLEAR }, "CopyDisplayToOutput_DrawError");
@@ -1727,7 +1731,8 @@ void FramebufferManagerCommon::CopyDisplayToOutput(const DisplayLayoutConfig &co
int actualHeight = (vfb->bufferHeight * vfb->renderHeight) / vfb->height;
presentation_->UpdateUniforms(textureCache_->VideoIsPlaying());
presentation_->SourceFramebuffer(vfb->fbo, actualWidth, actualHeight);
presentation_->CopyToOutput(config, flags, uvRotation, u0, v0, u1, v1);
presentation_->RunPostshaderPasses(config, flags, uvRotation, u0, v0, u1, v1);
presentation_->CopyToOutput(config);
} else if (useBufferedRendering_) {
WARN_LOG(Log::FrameBuf, "Using buffered rendering, and current VFB lacks an FBO: %08x", vfb->fb_address);
} else {
@@ -2799,7 +2804,9 @@ void FramebufferManagerCommon::NotifyBlockTransferAfter(u32 dstBasePtr, int dstS
if (isPrevDisplayBuffer || isDisplayBuffer) {
FlushBeforeCopy();
// HACK
DrawFramebufferToOutput(displayLayoutConfigCopy_, Memory::GetPointerUnchecked(dstBasePtr), dstStride, displayFormat_);
if (DrawFramebufferToOutput(displayLayoutConfigCopy_, Memory::GetPointerUnchecked(dstBasePtr), dstStride, displayFormat_)) {
presentation_->CopyToOutput(displayLayoutConfigCopy_);
}
return;
}
}
+43 -30
View File
@@ -651,9 +651,12 @@ void PresentationCommon::UpdateUniforms(bool hasVideo) {
hasVideo_ = hasVideo;
}
void PresentationCommon::CopyToOutput(const DisplayLayoutConfig &config, OutputFlags flags, int uvRotation, float u0, float v0, float u1, float v1) {
void PresentationCommon::RunPostshaderPasses(const DisplayLayoutConfig &config, OutputFlags flags, int uvRotation, float u0, float v0, float u1, float v1) {
draw_->Invalidate(InvalidationFlags::CACHED_RENDER_STATE);
postShaderOutput_ = nullptr;
outputFlags_ = flags;
// TODO: If shader objects have been created by now, we might have received errors.
// GLES can have the shader fail later, shader->failed / shader->error.
// This should auto-disable usePostShader_ and call ShowPostShaderError().
@@ -663,7 +666,6 @@ void PresentationCommon::CopyToOutput(const DisplayLayoutConfig &config, OutputF
const bool usePostShader = usePostShader_ && !useStereo && !(flags & OutputFlags::RB_SWIZZLE);
const bool isFinalAtOutputResolution = usePostShader && postShaderFramebuffers_.size() < postShaderPipelines_.size();
Draw::Framebuffer *postShaderOutput = nullptr;
int lastWidth = srcWidth_;
int lastHeight = srcHeight_;
@@ -678,8 +680,7 @@ void PresentationCommon::CopyToOutput(const DisplayLayoutConfig &config, OutputF
frame.w /= 2.0;
pixelWidth /= 2;
}
FRect rc;
CalculateDisplayOutputRect(config, &rc, 480.0f, 272.0f, frame, uvRotation);
CalculateDisplayOutputRect(config, &rc_, 480.0f, 272.0f, frame, uvRotation);
// To make buffer updates easier, we use one array of verts.
int postVertsOffset = (int)sizeof(Vertex) * 4;
@@ -699,10 +700,10 @@ void PresentationCommon::CopyToOutput(const DisplayLayoutConfig &config, OutputF
// 4-7: Post-processing, other passes
// 8-11: Post-processing, first pass (needs to handle cropping the input image, if wrong dimensions)
Vertex verts[12] = {
{ rc.x, rc.y, 0, finalU0, finalV0, 0xFFFFFFFF }, // TL
{ rc.x + rc.w, rc.y, 0, finalU1, finalV0, 0xFFFFFFFF }, // TR
{ rc.x, rc.y + rc.h, 0, finalU0, finalV1, 0xFFFFFFFF }, // BL
{ rc.x + rc.w, rc.y + rc.h, 0, finalU1, finalV1, 0xFFFFFFFF }, // BR
{ rc_.x, rc_.y, 0, finalU0, finalV0, 0xFFFFFFFF }, // TL
{ rc_.x + rc_.w, rc_.y, 0, finalU1, finalV0, 0xFFFFFFFF }, // TR
{ rc_.x, rc_.y + rc_.h, 0, finalU0, finalV1, 0xFFFFFFFF }, // BL
{ rc_.x + rc_.w, rc_.y + rc_.h, 0, finalU1, finalV1, 0xFFFFFFFF }, // BR
};
// Rescale X, Y to normalized coordinate system.
@@ -732,7 +733,7 @@ void PresentationCommon::CopyToOutput(const DisplayLayoutConfig &config, OutputF
rotation ^= 2;
}
static int rotLookup[4] = { 0, 1, 3, 2 };
static int rotLookup[4] = {0, 1, 3, 2};
for (int i = 0; i < 4; i++) {
int otherI = rotLookup[(rotLookup[i] + rotation) & 3];
@@ -775,10 +776,9 @@ void PresentationCommon::CopyToOutput(const DisplayLayoutConfig &config, OutputF
// Grab the previous framebuffer early so we can change previousIndex_ when we want.
Draw::Framebuffer *previousFramebuffer = previousFramebuffers_.empty() ? nullptr : previousFramebuffers_[previousIndex_];
PostShaderUniforms uniforms;
const auto performShaderPass = [&](const ShaderInfo *shaderInfo, Draw::Framebuffer *postShaderFramebuffer, Draw::Pipeline *postShaderPipeline, int vertsOffset) {
if (postShaderOutput) {
draw_->BindFramebufferAsTexture(postShaderOutput, 0, Draw::Aspect::COLOR_BIT, 0);
if (postShaderOutput_) {
draw_->BindFramebufferAsTexture(postShaderOutput_, 0, Draw::Aspect::COLOR_BIT, 0);
} else {
BindSource(0, false);
}
@@ -788,10 +788,11 @@ void PresentationCommon::CopyToOutput(const DisplayLayoutConfig &config, OutputF
int nextWidth, nextHeight;
draw_->GetFramebufferDimensions(postShaderFramebuffer, &nextWidth, &nextHeight);
Draw::Viewport viewport{ 0, 0, (float)nextWidth, (float)nextHeight, 0.0f, 1.0f };
Draw::Viewport viewport{0, 0, (float)nextWidth, (float)nextHeight, 0.0f, 1.0f};
draw_->SetViewport(viewport);
draw_->SetScissorRect(0, 0, nextWidth, nextHeight);
PostShaderUniforms uniforms;
CalculatePostShaderUniforms(lastWidth, lastHeight, nextWidth, nextHeight, shaderInfo, &uniforms);
draw_->BindPipeline(postShaderPipeline);
@@ -806,7 +807,7 @@ void PresentationCommon::CopyToOutput(const DisplayLayoutConfig &config, OutputF
draw_->BindVertexBuffer(vdata_, vertsOffset);
draw_->Draw(4, 0);
postShaderOutput = postShaderFramebuffer;
postShaderOutput_ = postShaderFramebuffer;
lastWidth = nextWidth;
lastHeight = nextHeight;
};
@@ -818,16 +819,16 @@ void PresentationCommon::CopyToOutput(const DisplayLayoutConfig &config, OutputF
bool flipped = flags & OutputFlags::POSITION_FLIPPED;
float y0 = flipped ? 1.0f : -1.0f;
float y1 = flipped ? -1.0f : 1.0f;
verts[4] = { -1.0f, y0, 0.0f, 0.0f, 0.0f, 0xFFFFFFFF }; // TL
verts[5] = { 1.0f, y0, 0.0f, 1.0f, 0.0f, 0xFFFFFFFF }; // TR
verts[6] = { -1.0f, y1, 0.0f, 0.0f, 1.0f, 0xFFFFFFFF }; // BL
verts[7] = { 1.0f, y1, 0.0f, 1.0f, 1.0f, 0xFFFFFFFF }; // BR
verts[4] = {-1.0f, y0, 0.0f, 0.0f, 0.0f, 0xFFFFFFFF}; // TL
verts[5] = {1.0f, y0, 0.0f, 1.0f, 0.0f, 0xFFFFFFFF}; // TR
verts[6] = {-1.0f, y1, 0.0f, 0.0f, 1.0f, 0xFFFFFFFF}; // BL
verts[7] = {1.0f, y1, 0.0f, 1.0f, 1.0f, 0xFFFFFFFF}; // BR
// Now, adjust for the desired input rectangle.
verts[8] = { -1.0f, y0, 0.0f, u0, v0, 0xFFFFFFFF }; // TL
verts[9] = { 1.0f, y0, 0.0f, u1, v0, 0xFFFFFFFF }; // TR
verts[10] = { -1.0f, y1, 0.0f, u0, v1, 0xFFFFFFFF }; // BL
verts[11] = { 1.0f, y1, 0.0f, u1, v1, 0xFFFFFFFF }; // BR
verts[8] = {-1.0f, y0, 0.0f, u0, v0, 0xFFFFFFFF}; // TL
verts[9] = {1.0f, y0, 0.0f, u1, v0, 0xFFFFFFFF}; // TR
verts[10] = {-1.0f, y1, 0.0f, u0, v1, 0xFFFFFFFF}; // BL
verts[11] = {1.0f, y1, 0.0f, u1, v1, 0xFFFFFFFF}; // BR
draw_->UpdateBuffer(vdata_, (const uint8_t *)verts, 0, sizeof(verts), Draw::UPDATE_DISCARD);
@@ -844,7 +845,7 @@ void PresentationCommon::CopyToOutput(const DisplayLayoutConfig &config, OutputF
postShaderFramebuffer = previousFramebuffers_[previousIndex_];
}
draw_->BindFramebufferAsRenderTarget(postShaderFramebuffer, { Draw::RPAction::DONT_CARE, Draw::RPAction::DONT_CARE, Draw::RPAction::DONT_CARE }, "PostShader");
draw_->BindFramebufferAsRenderTarget(postShaderFramebuffer, {Draw::RPAction::DONT_CARE, Draw::RPAction::DONT_CARE, Draw::RPAction::DONT_CARE}, "PostShader");
// Pick vertices 8-11 for the first pass.
int vertOffset = i == 0 ? (int)sizeof(Vertex) * 8 : (int)sizeof(Vertex) * 4;
@@ -869,14 +870,24 @@ void PresentationCommon::CopyToOutput(const DisplayLayoutConfig &config, OutputF
previousIndex_ = 0;
Draw::Framebuffer *postShaderFramebuffer = previousFramebuffers_[previousIndex_];
draw_->BindFramebufferAsRenderTarget(postShaderFramebuffer, { Draw::RPAction::CLEAR, Draw::RPAction::DONT_CARE, Draw::RPAction::DONT_CARE }, "InterFrameBlit");
draw_->BindFramebufferAsRenderTarget(postShaderFramebuffer, {Draw::RPAction::CLEAR, Draw::RPAction::DONT_CARE, Draw::RPAction::DONT_CARE}, "InterFrameBlit");
performShaderPass(shaderInfo, postShaderFramebuffer, postShaderPipeline, postVertsOffset);
}
}
void PresentationCommon::CopyToOutput(const DisplayLayoutConfig &config) {
bool useNearest = outputFlags_ & OutputFlags::NEAREST;
bool useStereo = gstate_c.Use(GPU_USE_SIMPLE_STEREO_PERSPECTIVE) && stereoPipeline_ != nullptr; // TODO: Also check that the backend has support for it.
const bool usePostShader = usePostShader_ && !useStereo && !(outputFlags_ & OutputFlags::RB_SWIZZLE);
const bool isFinalAtOutputResolution = usePostShader && postShaderFramebuffers_.size() < postShaderPipelines_.size();
int lastWidth = srcWidth_;
int lastHeight = srcHeight_;
draw_->BindFramebufferAsRenderTarget(nullptr, { Draw::RPAction::CLEAR, Draw::RPAction::DONT_CARE, Draw::RPAction::DONT_CARE }, "FinalBlit");
draw_->SetScissorRect(0, 0, pixelWidth_, pixelHeight_);
Draw::Pipeline *pipeline = (flags & OutputFlags::RB_SWIZZLE) ? texColorRBSwizzle_ : texColor_;
Draw::Pipeline *pipeline = (outputFlags_ & OutputFlags::RB_SWIZZLE) ? texColorRBSwizzle_ : texColor_;
if (useStereo) {
draw_->BindPipeline(stereoPipeline_);
@@ -891,20 +902,23 @@ void PresentationCommon::CopyToOutput(const DisplayLayoutConfig &config, OutputF
}
draw_->BindPipeline(pipeline);
if (postShaderOutput) {
draw_->BindFramebufferAsTexture(postShaderOutput, 0, Draw::Aspect::COLOR_BIT, 0);
if (postShaderOutput_) {
draw_->BindFramebufferAsTexture(postShaderOutput_, 0, Draw::Aspect::COLOR_BIT, 0);
} else {
BindSource(0, false);
}
}
BindSource(1, false);
PostShaderUniforms uniforms;
if (isFinalAtOutputResolution && previousFramebuffers_.empty()) {
CalculatePostShaderUniforms(lastWidth, lastHeight, (int)rc.w, (int)rc.h, &postShaderInfo_.back(), &uniforms);
CalculatePostShaderUniforms(lastWidth, lastHeight, (int)rc_.w, (int)rc_.h, &postShaderInfo_.back(), &uniforms);
draw_->UpdateDynamicUniformBuffer(&uniforms, sizeof(uniforms));
previousUniforms_ = uniforms;
} else if (useStereo) {
CalculatePostShaderUniforms(lastWidth, lastHeight, (int)rc.w, (int)rc.h, stereoShaderInfo_, &uniforms);
CalculatePostShaderUniforms(lastWidth, lastHeight, (int)rc_.w, (int)rc_.h, stereoShaderInfo_, &uniforms);
draw_->UpdateDynamicUniformBuffer(&uniforms, sizeof(uniforms));
previousUniforms_ = uniforms;
} else {
Draw::VsTexColUB ub{};
memcpy(ub.WorldViewProj, g_display.rot_matrix.m, sizeof(float) * 16);
@@ -945,7 +959,6 @@ void PresentationCommon::CopyToOutput(const DisplayLayoutConfig &config, OutputF
// Unbinds all textures and samplers too, needed since sometimes a MakePixelTexture is deleted etc.
draw_->Invalidate(InvalidationFlags::CACHED_RENDER_STATE);
previousUniforms_ = uniforms;
presentedThisFrame_ = true;
}
+9 -1
View File
@@ -69,6 +69,7 @@ struct ShaderInfo;
class TextureCacheCommon;
enum class OutputFlags {
DEFAULT = 0,
LINEAR = 0x0000,
NEAREST = 0x0001,
RB_SWIZZLE = 0x0002,
@@ -125,7 +126,9 @@ public:
void UpdateUniforms(bool hasVideo);
void SourceTexture(Draw::Texture *texture, int bufferWidth, int bufferHeight);
void SourceFramebuffer(Draw::Framebuffer *fb, int bufferWidth, int bufferHeight);
void CopyToOutput(const DisplayLayoutConfig &config, OutputFlags flags, int uvRotation, float u0, float v0, float u1, float v1);
void RunPostshaderPasses(const DisplayLayoutConfig &config, OutputFlags flags, int uvRotation, float u0, float v0, float u1, float v1);
void CopyToOutput(const DisplayLayoutConfig &config);
void CalculateRenderResolution(const DisplayLayoutConfig &config, int *width, int *height, int *scaleFactor, bool *upscaling, bool *ssaa) const;
@@ -189,4 +192,9 @@ protected:
int h;
};
std::vector<PrevFBO> postShaderFBOUsage_;
// Carry over info between RunPostShaderPasses and CopyToOutput.
Draw::Framebuffer *postShaderOutput_ = nullptr;
FRect rc_;
OutputFlags outputFlags_ = OutputFlags::DEFAULT;
};
+2 -1
View File
@@ -124,7 +124,8 @@ public:
uint32_t GetAddrTranslation() override;
virtual void SetDisplayFramebuffer(u32 framebuf, u32 stride, GEBufferFormat format) = 0;
virtual void CopyDisplayToOutput(const DisplayLayoutConfig &config, bool reallyDirty) = 0;
virtual void SetCurFramebufferDirty(bool dirty) = 0;
virtual void CopyDisplayToOutput(const DisplayLayoutConfig &config) = 0;
virtual bool PresentedThisFrame() const = 0;
// Invalidate any cached content sourced from the specified range.
+3 -2
View File
@@ -530,7 +530,7 @@ void GPUCommonHW::PreExecuteOp(u32 op, u32 diff) {
CheckFlushOp(op >> 24, diff);
}
void GPUCommonHW::CopyDisplayToOutput(const DisplayLayoutConfig &config, bool reallyDirty) {
void GPUCommonHW::CopyDisplayToOutput(const DisplayLayoutConfig &config) {
drawEngineCommon_->FlushQueuedDepth();
// Flush anything left over.
drawEngineCommon_->Flush();
@@ -538,7 +538,8 @@ void GPUCommonHW::CopyDisplayToOutput(const DisplayLayoutConfig &config, bool re
shaderManager_->DirtyLastShader();
// after this, render pass is active.
framebufferManager_->CopyDisplayToOutput(config, reallyDirty);
framebufferManager_->CopyDisplayToOutput(config, curFramebufferDirty_);
curFramebufferDirty_ = false;
gstate_c.Dirty(DIRTY_TEXTURE_IMAGE);
}
+4 -2
View File
@@ -7,10 +7,11 @@
class GPUCommonHW : public GPUCommon {
public:
GPUCommonHW(GraphicsContext *gfxCtx, Draw::DrawContext *draw);
~GPUCommonHW();
~GPUCommonHW() override;
// This can fail, and if so no render pass is active.
void CopyDisplayToOutput(const DisplayLayoutConfig &config, bool reallyDirty) override;
void SetCurFramebufferDirty(bool dirty) override { curFramebufferDirty_ = dirty; }
void CopyDisplayToOutput(const DisplayLayoutConfig &config) override;
void DoState(PointerWrap &p) override;
void DeviceLost() override;
void DeviceRestore(Draw::DrawContext *draw) override;
@@ -105,4 +106,5 @@ protected:
int msaaLevel_ = 0;
bool sawExactEqualDepth_ = false;
ShaderManagerCommon *shaderManager_ = nullptr;
bool curFramebufferDirty_ = false;
};
+3 -2
View File
@@ -643,10 +643,11 @@ void SoftGPU::CopyToCurrentFboFromDisplayRam(const DisplayLayoutConfig &config,
}
presentation_->SourceTexture(fbTex, desc.width, desc.height);
presentation_->CopyToOutput(config, outputFlags, config.iInternalScreenRotation, u0, v0, u1, v1);
presentation_->RunPostshaderPasses(config, outputFlags, config.iInternalScreenRotation, u0, v0, u1, v1);
presentation_->CopyToOutput(config);
}
void SoftGPU::CopyDisplayToOutput(const DisplayLayoutConfig &config, bool reallyDirty) {
void SoftGPU::CopyDisplayToOutput(const DisplayLayoutConfig &config) {
drawEngine_->transformUnit.Flush(this, "output");
// The display always shows 480x272.
CopyToCurrentFboFromDisplayRam(config, FB_WIDTH, FB_HEIGHT);
+2 -1
View File
@@ -137,7 +137,8 @@ public:
void UpdateCmdInfo() override {}
void SetDisplayFramebuffer(u32 framebuf, u32 stride, GEBufferFormat format) override;
void CopyDisplayToOutput(const DisplayLayoutConfig &config, bool reallyDirty) override;
void SetCurFramebufferDirty(bool dirty) override {}
void CopyDisplayToOutput(const DisplayLayoutConfig &config) override;
void GetStats(char *buffer, size_t bufsize) override;
std::vector<const VirtualFramebuffer *> GetFramebufferList() const override { return std::vector<const VirtualFramebuffer *>(); }
void InvalidateCache(u32 addr, int size, GPUInvalidationType type) override;
+27 -16
View File
@@ -1634,13 +1634,12 @@ ScreenRenderFlags EmuScreen::render(ScreenRenderMode mode) {
// If a boot is in progress, update it.
ProcessGameBoot(gamePath_);
ScreenRenderFlags flags = ScreenRenderFlags::NONE;
Draw::Viewport viewport{ 0.0f, 0.0f, (float)g_display.pixel_xres, (float)g_display.pixel_yres, 0.0f, 1.0f };
const Draw::Viewport viewport{0.0f, 0.0f, (float)g_display.pixel_xres, (float)g_display.pixel_yres, 0.0f, 1.0f};
using namespace Draw;
DrawContext *draw = screenManager()->getDrawContext();
if (!draw) {
return flags; // shouldn't really happen but I've seen a suspicious stack trace..
return ScreenRenderFlags::NONE; // shouldn't really happen but I've seen a suspicious stack trace..
}
ProcessQueuedVKeys();
@@ -1649,8 +1648,6 @@ ScreenRenderFlags EmuScreen::render(ScreenRenderMode mode) {
bool framebufferBound = false;
const DeviceOrientation orientation = GetDeviceOrientation();
if (mode & ScreenRenderMode::FIRST) {
// Actually, always gonna be first when it exists (?)
@@ -1664,9 +1661,9 @@ ScreenRenderFlags EmuScreen::render(ScreenRenderMode mode) {
if (skipBufferEffects && !g_Config.bSoftwareRendering) {
// We need to clear here already so that drawing during the frame is done on a clean slate.
if (Core_IsStepping() && gpuStats.numFlips != 0) {
draw->BindFramebufferAsRenderTarget(nullptr, { RPAction::KEEP, RPAction::CLEAR, RPAction::CLEAR }, "EmuScreen_BackBuffer");
draw->BindFramebufferAsRenderTarget(nullptr, {RPAction::KEEP, RPAction::CLEAR, RPAction::CLEAR}, "EmuScreen_BackBuffer");
} else {
draw->BindFramebufferAsRenderTarget(nullptr, { RPAction::CLEAR, RPAction::CLEAR, RPAction::CLEAR, 0xFF000000 }, "EmuScreen_BackBuffer");
draw->BindFramebufferAsRenderTarget(nullptr, {RPAction::CLEAR, RPAction::CLEAR, RPAction::CLEAR, 0xFF000000}, "EmuScreen_BackBuffer");
}
draw->SetViewport(viewport);
@@ -1681,6 +1678,7 @@ ScreenRenderFlags EmuScreen::render(ScreenRenderMode mode) {
g_OSD.NudgeIngameNotifications();
const DeviceOrientation orientation = GetDeviceOrientation();
const DisplayLayoutConfig &displayLayoutConfig = g_Config.GetDisplayLayoutConfig(orientation);
__DisplaySetDisplayLayoutConfig(displayLayoutConfig);
@@ -1692,14 +1690,15 @@ ScreenRenderFlags EmuScreen::render(ScreenRenderMode mode) {
if (PSP_IsInited() && !skipBufferEffects) {
_dbg_assert_(gpu);
gpu->BeginHostFrame(displayLayoutConfig);
gpu->CopyDisplayToOutput(displayLayoutConfig, true);
gpu->SetCurFramebufferDirty(true);
gpu->CopyDisplayToOutput(displayLayoutConfig);
gpu->EndHostFrame();
}
if (gpu && gpu->PresentedThisFrame()) {
framebufferBound = true;
}
if (!framebufferBound) {
draw->BindFramebufferAsRenderTarget(nullptr, { RPAction::CLEAR, RPAction::CLEAR, RPAction::CLEAR, }, "EmuScreen_Behind");
draw->BindFramebufferAsRenderTarget(nullptr, {RPAction::CLEAR, RPAction::CLEAR, RPAction::CLEAR,}, "EmuScreen_Behind");
}
Draw::BackendState state = draw->GetCurrentBackendState();
@@ -1708,7 +1707,7 @@ ScreenRenderFlags EmuScreen::render(ScreenRenderMode mode) {
// _dbg_assert_msg_(state.passes >= 1, "skipB: %d sw: %d mode: %d back: %d tag: %s behi: %d", (int)skipBufferEffects, (int)g_Config.bSoftwareRendering, (int)mode, (int)g_Config.iGPUBackend, screenManager()->topScreen()->tag(), (int)g_Config.bRunBehindPauseMenu);
// Workaround any remaining bugs like this.
if (state.passes == 0) {
draw->BindFramebufferAsRenderTarget(nullptr, { RPAction::CLEAR, RPAction::CLEAR, RPAction::CLEAR, }, "EmuScreen_SafeFallback");
draw->BindFramebufferAsRenderTarget(nullptr, {RPAction::CLEAR, RPAction::CLEAR, RPAction::CLEAR,}, "EmuScreen_SafeFallback");
}
}
@@ -1717,7 +1716,7 @@ ScreenRenderFlags EmuScreen::render(ScreenRenderMode mode) {
draw->SetViewport(viewport);
draw->SetScissorRect(0, 0, g_display.pixel_xres, g_display.pixel_yres);
darken();
return flags;
return ScreenRenderFlags::NONE;
}
if (!PSP_IsInited() || readyToFinishBoot_) {
@@ -1726,13 +1725,13 @@ ScreenRenderFlags EmuScreen::render(ScreenRenderMode mode) {
if (mode & ScreenRenderMode::TOP) {
checkPowerDown();
}
draw->BindFramebufferAsRenderTarget(nullptr, { RPAction::CLEAR, RPAction::CLEAR, RPAction::CLEAR }, "EmuScreen_Invalid");
draw->BindFramebufferAsRenderTarget(nullptr, {RPAction::CLEAR, RPAction::CLEAR, RPAction::CLEAR}, "EmuScreen_Invalid");
// Need to make sure the UI texture is available, for "darken".
screenManager()->getUIContext()->BeginFrame();
draw->SetViewport(viewport);
draw->SetScissorRect(0, 0, g_display.pixel_xres, g_display.pixel_yres);
renderUI();
return flags;
return ScreenRenderFlags::NONE;
}
// Freeze-frame functionality (loads a savestate on every frame).
@@ -1748,13 +1747,24 @@ ScreenRenderFlags EmuScreen::render(ScreenRenderMode mode) {
}
}
PSP_UpdateDebugStats((DebugOverlay)g_Config.iDebugOverlay == DebugOverlay::DEBUG_STATS || g_Config.bLogFrameDrops);
// Running it early allows things like direct readbacks of buffers, things we can't do
// when we have started the final render pass. Well, technically we probably could with some manipulation
// of pass order in the render managers..
runImDebugger();
return RunEmulation(mode, framebufferBound, skipBufferEffects);
}
ScreenRenderFlags EmuScreen::RunEmulation(ScreenRenderMode mode, bool framebufferBound, bool skipBufferEffects) {
using namespace Draw;
ScreenRenderFlags flags = ScreenRenderFlags::NONE;
const DeviceOrientation orientation = GetDeviceOrientation();
const DisplayLayoutConfig &displayLayoutConfig = g_Config.GetDisplayLayoutConfig(orientation);
DrawContext *draw = screenManager()->getDrawContext();
const Draw::Viewport viewport{0.0f, 0.0f, (float)g_display.pixel_xres, (float)g_display.pixel_yres, 0.0f, 1.0f};
PSP_UpdateDebugStats((DebugOverlay)g_Config.iDebugOverlay == DebugOverlay::DEBUG_STATS || g_Config.bLogFrameDrops);
bool blockedExecution = Achievements::IsBlockingExecution();
uint32_t clearColor = 0;
if (!blockedExecution) {
@@ -1794,7 +1804,8 @@ ScreenRenderFlags EmuScreen::render(ScreenRenderMode mode) {
// This won't work in non-buffered, but that's fine.
if (!framebufferBound && PSP_IsInited()) {
// draw->BindFramebufferAsRenderTarget(nullptr, { RPAction::CLEAR, RPAction::CLEAR, RPAction::CLEAR, clearColor }, "EmuScreen_Stepping");
gpu->CopyDisplayToOutput(displayLayoutConfig, true);
gpu->SetCurFramebufferDirty(true);
gpu->CopyDisplayToOutput(displayLayoutConfig);
framebufferBound = true;
}
}
+1
View File
@@ -73,6 +73,7 @@ protected:
private:
void CreateViews() override;
ScreenRenderFlags RunEmulation(ScreenRenderMode mode, bool framebufferBound, bool skipBufferEffects);
void OnDevTools(UI::EventParams &params);
void OnChat(UI::EventParams &params);
+1
View File
@@ -1405,6 +1405,7 @@ void GameSettingsScreen::CreateSystemSettings(UI::ViewGroup *systemSettings) {
if (System_GetPropertyInt(SYSPROP_DEVICE_TYPE) == DEVICE_TYPE_MOBILE) {
auto co = GetI18NCategory(I18NCat::CONTROLS);
// Display rotation
AddRotationPicker(screenManager(), systemSettings, true);
if (System_GetPropertyBool(SYSPROP_SUPPORTS_SUSTAINED_PERF_MODE)) {
+4 -2
View File
@@ -245,8 +245,10 @@ void AddRotationPicker(ScreenManager *screenManager, UI::ViewGroup *parent, bool
auto co = GetI18NCategory(I18NCat::CONTROLS);
PopupMultiChoice *rot = parent->Add(new PopupMultiChoice(&g_Config.iScreenRotation, text ? co->T("Screen Rotation") : "", screenRotation, 0, ARRAY_SIZE(screenRotation), I18NCat::CONTROLS, screenManager, text ? nullptr : new LinearLayoutParams(ITEM_HEIGHT, ITEM_HEIGHT)));
rot->SetHideTitle(true);
rot->SetIconOnly(true);
if (!text) {
rot->SetHideTitle(true);
rot->SetIconOnly(true);
}
rot->SetChoiceIcons(screenRotationIcons);
// Portrait Reversed is not recommended on iPhone (and we also ban it in the plist).
+4 -2
View File
@@ -268,8 +268,10 @@ bool RunAutoTest(HeadlessHost *headlessHost, CoreParameter &coreParameter, const
if (draw) {
draw->BindFramebufferAsRenderTarget(nullptr, { Draw::RPAction::CLEAR, Draw::RPAction::DONT_CARE, Draw::RPAction::DONT_CARE }, "Headless");
// Vulkan may get angry if we don't do a final present.
if (gpu)
gpu->CopyDisplayToOutput(g_Config.GetDisplayLayoutConfig(DeviceOrientation::Landscape), true);
if (gpu) {
gpu->SetCurFramebufferDirty(true);
gpu->CopyDisplayToOutput(g_Config.GetDisplayLayoutConfig(DeviceOrientation::Landscape));
}
draw->EndFrame();
}