mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-07-11 01:25:07 +02:00
Finish the split. Greatly simplifies the render code in EmuScreen.
This commit is contained in:
@@ -292,6 +292,11 @@ static VkAttachmentStoreOp ConvertStoreAction(VKRRenderPassStoreAction action) {
|
||||
|
||||
VkRenderPass CreateRenderPass(VulkanContext *vulkan, const RPKey &key, RenderPassType rpType, VkSampleCountFlagBits sampleCount) {
|
||||
bool isBackbuffer = rpType == RenderPassType::BACKBUFFER;
|
||||
if (isBackbuffer) {
|
||||
_dbg_assert_(key.colorLoadAction != VKRRenderPassLoadAction::KEEP);
|
||||
_dbg_assert_(key.depthLoadAction != VKRRenderPassLoadAction::KEEP);
|
||||
_dbg_assert_(key.stencilLoadAction != VKRRenderPassLoadAction::KEEP);
|
||||
}
|
||||
bool hasDepth = RenderPassTypeHasDepth(rpType);
|
||||
bool multiview = RenderPassTypeHasMultiView(rpType);
|
||||
bool multisample = RenderPassTypeHasMultisample(rpType);
|
||||
|
||||
@@ -982,20 +982,27 @@ void VulkanRenderManager::EndCurRenderStep() {
|
||||
curPipelineFlags_ = (PipelineFlags)0;
|
||||
}
|
||||
|
||||
void VulkanRenderManager::BindFramebufferAsRenderTarget(VKRFramebuffer *fb, VKRRenderPassLoadAction color, VKRRenderPassLoadAction depth, VKRRenderPassLoadAction stencil, uint32_t clearColor, float clearDepth, uint8_t clearStencil, const char *tag) {
|
||||
void VulkanRenderManager::BindFramebufferAsRenderTarget(VKRFramebuffer *fb, VKRRenderPassLoadAction colorLoad, VKRRenderPassLoadAction depthLoad, VKRRenderPassLoadAction stencilLoad, uint32_t clearColor, float clearDepth, uint8_t clearStencil, const char *tag) {
|
||||
_dbg_assert_(insideFrame_);
|
||||
|
||||
if (!fb) {
|
||||
// Backbuffer render passes have some requirements.
|
||||
_dbg_assert_(colorLoad != VKRRenderPassLoadAction::KEEP);
|
||||
_dbg_assert_(depthLoad != VKRRenderPassLoadAction::KEEP);
|
||||
_dbg_assert_(stencilLoad != VKRRenderPassLoadAction::KEEP);
|
||||
}
|
||||
|
||||
// Eliminate dupes (bind of the framebuffer we already are rendering to), instantly convert to a clear if possible.
|
||||
if (!steps_.empty() && steps_.back()->stepType == VKRStepType::RENDER && steps_.back()->render.framebuffer == fb) {
|
||||
u32 clearMask = 0;
|
||||
if (color == VKRRenderPassLoadAction::CLEAR) {
|
||||
if (colorLoad == VKRRenderPassLoadAction::CLEAR) {
|
||||
clearMask |= VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
}
|
||||
if (depth == VKRRenderPassLoadAction::CLEAR) {
|
||||
if (depthLoad == VKRRenderPassLoadAction::CLEAR) {
|
||||
clearMask |= VK_IMAGE_ASPECT_DEPTH_BIT;
|
||||
curPipelineFlags_ |= PipelineFlags::USES_DEPTH_STENCIL;
|
||||
}
|
||||
if (stencil == VKRRenderPassLoadAction::CLEAR) {
|
||||
if (stencilLoad == VKRRenderPassLoadAction::CLEAR) {
|
||||
clearMask |= VK_IMAGE_ASPECT_STENCIL_BIT;
|
||||
curPipelineFlags_ |= PipelineFlags::USES_DEPTH_STENCIL;
|
||||
}
|
||||
@@ -1057,25 +1064,25 @@ void VulkanRenderManager::BindFramebufferAsRenderTarget(VKRFramebuffer *fb, VKRR
|
||||
// Older Mali drivers have issues with depth and stencil don't match load/clear/etc.
|
||||
// TODO: Determine which versions and do this only where necessary.
|
||||
u32 lateClearMask = 0;
|
||||
if (depth != stencil && vulkan_->GetPhysicalDeviceProperties().properties.vendorID == VULKAN_VENDOR_ARM) {
|
||||
if (stencil == VKRRenderPassLoadAction::DONT_CARE) {
|
||||
stencil = depth;
|
||||
} else if (depth == VKRRenderPassLoadAction::DONT_CARE) {
|
||||
depth = stencil;
|
||||
} else if (stencil == VKRRenderPassLoadAction::CLEAR) {
|
||||
depth = stencil;
|
||||
if (depthLoad != stencilLoad && vulkan_->GetPhysicalDeviceProperties().properties.vendorID == VULKAN_VENDOR_ARM) {
|
||||
if (stencilLoad == VKRRenderPassLoadAction::DONT_CARE) {
|
||||
stencilLoad = depthLoad;
|
||||
} else if (depthLoad == VKRRenderPassLoadAction::DONT_CARE) {
|
||||
depthLoad = stencilLoad;
|
||||
} else if (stencilLoad == VKRRenderPassLoadAction::CLEAR) {
|
||||
depthLoad = stencilLoad;
|
||||
lateClearMask |= VK_IMAGE_ASPECT_STENCIL_BIT;
|
||||
} else if (depth == VKRRenderPassLoadAction::CLEAR) {
|
||||
stencil = depth;
|
||||
} else if (depthLoad == VKRRenderPassLoadAction::CLEAR) {
|
||||
stencilLoad = depthLoad;
|
||||
lateClearMask |= VK_IMAGE_ASPECT_DEPTH_BIT;
|
||||
}
|
||||
}
|
||||
|
||||
VKRStep *step = new VKRStep{ VKRStepType::RENDER };
|
||||
step->render.framebuffer = fb;
|
||||
step->render.colorLoad = color;
|
||||
step->render.depthLoad = depth;
|
||||
step->render.stencilLoad = stencil;
|
||||
step->render.colorLoad = colorLoad;
|
||||
step->render.depthLoad = depthLoad;
|
||||
step->render.stencilLoad = stencilLoad;
|
||||
step->render.colorStore = VKRRenderPassStoreAction::STORE;
|
||||
step->render.depthStore = VKRRenderPassStoreAction::STORE;
|
||||
step->render.stencilStore = VKRRenderPassStoreAction::STORE;
|
||||
@@ -1092,7 +1099,7 @@ void VulkanRenderManager::BindFramebufferAsRenderTarget(VKRFramebuffer *fb, VKRR
|
||||
|
||||
if (fb) {
|
||||
// If there's a KEEP, we naturally read from the framebuffer.
|
||||
if (color == VKRRenderPassLoadAction::KEEP || depth == VKRRenderPassLoadAction::KEEP || stencil == VKRRenderPassLoadAction::KEEP) {
|
||||
if (colorLoad == VKRRenderPassLoadAction::KEEP || depthLoad == VKRRenderPassLoadAction::KEEP || stencilLoad == VKRRenderPassLoadAction::KEEP) {
|
||||
step->dependencies.insert(fb);
|
||||
}
|
||||
}
|
||||
@@ -1118,7 +1125,7 @@ void VulkanRenderManager::BindFramebufferAsRenderTarget(VKRFramebuffer *fb, VKRR
|
||||
}
|
||||
}
|
||||
|
||||
if (color == VKRRenderPassLoadAction::CLEAR || depth == VKRRenderPassLoadAction::CLEAR || stencil == VKRRenderPassLoadAction::CLEAR) {
|
||||
if (colorLoad == VKRRenderPassLoadAction::CLEAR || depthLoad == VKRRenderPassLoadAction::CLEAR || stencilLoad == VKRRenderPassLoadAction::CLEAR) {
|
||||
curRenderArea_.SetRect(0, 0, curWidth_, curHeight_);
|
||||
}
|
||||
|
||||
|
||||
@@ -1839,6 +1839,8 @@ DataFormat VKContext::PreferredFramebufferReadbackFormat(Framebuffer *src) {
|
||||
}
|
||||
|
||||
void VKContext::BindFramebufferAsRenderTarget(Framebuffer *fbo, const RenderPassInfo &rp, const char *tag) {
|
||||
_dbg_assert_(fbo != nullptr || equals(tag, "BackBuffer"))
|
||||
|
||||
VKFramebuffer *fb = (VKFramebuffer *)fbo;
|
||||
VKRRenderPassLoadAction color = (VKRRenderPassLoadAction)rp.color;
|
||||
VKRRenderPassLoadAction depth = (VKRRenderPassLoadAction)rp.depth;
|
||||
|
||||
@@ -209,7 +209,25 @@ void ScreenManager::resized() {
|
||||
}
|
||||
|
||||
ScreenRenderFlags ScreenManager::render() {
|
||||
using namespace Draw;
|
||||
|
||||
ScreenRenderFlags flags = ScreenRenderFlags::NONE;
|
||||
|
||||
// First, go through the whole stack and have every screen render any non-backbuffer render passes.
|
||||
// In EmuScreen, this might result in running emulation.
|
||||
for (auto &layer : stack_) {
|
||||
flags |= layer.screen->PreRender();
|
||||
}
|
||||
|
||||
// Now, start the final render pass. This is now the ONLY place where binding the null fb is allowed.
|
||||
draw_->BindFramebufferAsRenderTarget(nullptr, {RPAction::CLEAR, RPAction::CLEAR, RPAction::CLEAR}, "BackBuffer");
|
||||
getUIContext()->BeginFrame();
|
||||
|
||||
const Draw::Viewport viewport{0.0f, 0.0f, (float)g_display.pixel_xres, (float)g_display.pixel_yres, 0.0f, 1.0f};
|
||||
draw_->SetViewport(viewport);
|
||||
draw_->SetScissorRect(0, 0, g_display.pixel_xres, g_display.pixel_yres);
|
||||
draw_->SetTargetSize(g_display.pixel_xres, g_display.pixel_yres);
|
||||
|
||||
if (!stack_.empty()) {
|
||||
// Collect the screens to render
|
||||
TinySet<Screen *, 6> layers;
|
||||
|
||||
+3
-2
@@ -72,11 +72,12 @@ ENUM_CLASS_BITOPS(ScreenRenderRole);
|
||||
|
||||
class Screen {
|
||||
public:
|
||||
Screen() : screenManager_(nullptr) { }
|
||||
Screen() = default;
|
||||
virtual ~Screen();
|
||||
|
||||
virtual void onFinish(DialogResult reason) {}
|
||||
virtual void update() {}
|
||||
virtual ScreenRenderFlags PreRender() { return ScreenRenderFlags::NONE; }
|
||||
virtual ScreenRenderFlags render(ScreenRenderMode mode) = 0;
|
||||
virtual void resized() {}
|
||||
virtual void dialogFinished(const Screen *dialog, DialogResult result) {}
|
||||
@@ -114,7 +115,7 @@ protected:
|
||||
}
|
||||
|
||||
private:
|
||||
ScreenManager *screenManager_;
|
||||
ScreenManager *screenManager_ = nullptr;
|
||||
int token_ = -1;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(Screen);
|
||||
|
||||
@@ -200,30 +200,7 @@ void UIScreen::deviceRestored(Draw::DrawContext *draw) {
|
||||
root_->DeviceRestored(draw);
|
||||
}
|
||||
|
||||
void UIScreen::SetupViewport() {
|
||||
using namespace Draw;
|
||||
Draw::DrawContext *draw = screenManager()->getDrawContext();
|
||||
_dbg_assert_(draw != nullptr);
|
||||
// Bind and clear the back buffer
|
||||
draw->BindFramebufferAsRenderTarget(nullptr, { RPAction::CLEAR, RPAction::CLEAR, RPAction::CLEAR, 0xFF000000 }, "UI");
|
||||
screenManager()->getUIContext()->BeginFrame();
|
||||
|
||||
Draw::Viewport viewport;
|
||||
viewport.TopLeftX = 0;
|
||||
viewport.TopLeftY = 0;
|
||||
viewport.Width = g_display.pixel_xres;
|
||||
viewport.Height = g_display.pixel_yres;
|
||||
viewport.MaxDepth = 1.0;
|
||||
viewport.MinDepth = 0.0;
|
||||
draw->SetViewport(viewport);
|
||||
draw->SetTargetSize(g_display.pixel_xres, g_display.pixel_yres);
|
||||
}
|
||||
|
||||
ScreenRenderFlags UIScreen::render(ScreenRenderMode mode) {
|
||||
if (mode & ScreenRenderMode::FIRST) {
|
||||
SetupViewport();
|
||||
}
|
||||
|
||||
DoRecreateViews();
|
||||
|
||||
UIContext &uiContext = *screenManager()->getUIContext();
|
||||
|
||||
@@ -77,7 +77,6 @@ protected:
|
||||
virtual void DrawBackground(UIContext &ui) {}
|
||||
virtual void DrawForeground(UIContext &ui) {}
|
||||
|
||||
void SetupViewport();
|
||||
void DoRecreateViews();
|
||||
|
||||
bool recreateViews_ = true;
|
||||
|
||||
@@ -662,7 +662,6 @@ void __DisplayFlip(int cyclesLate) {
|
||||
}
|
||||
if (nextFrame) {
|
||||
gpu->SetCurFramebufferDirty(fbReallyDirty);
|
||||
gpu->CopyDisplayToOutput(g_displayLayoutConfigCached);
|
||||
if (fbReallyDirty) {
|
||||
DisplayFireActualFlip();
|
||||
}
|
||||
|
||||
@@ -1665,6 +1665,8 @@ void FramebufferManagerCommon::PrepareCopyDisplayToOutput(const DisplayLayoutCon
|
||||
}
|
||||
} else {
|
||||
DEBUG_LOG(Log::FrameBuf, "Found no FBO to display! displayFBPtr = %08x", fbaddr);
|
||||
// No framebuffer to display! Clear to black.
|
||||
// TODO: Draw a black rectangle, will be important once we add backgrounds.
|
||||
gstate_c.Dirty(DIRTY_VIEWPORTSCISSOR_STATE);
|
||||
// No framebuffer to display! Clear to black.
|
||||
presentation_->SourceBlank();
|
||||
@@ -3434,10 +3436,6 @@ void FramebufferManagerCommon::DrawActiveTexture(float x, float y, float w, floa
|
||||
void FramebufferManagerCommon::BlitFramebuffer(VirtualFramebuffer *dst, int dstX, int dstY, VirtualFramebuffer *src, int srcX, int srcY, int w, int h, int bpp, RasterChannel channel, const char *tag) {
|
||||
if (!dst->fbo || !src->fbo || !useBufferedRendering_) {
|
||||
// This can happen if they recently switched from non-buffered.
|
||||
if (useBufferedRendering_) {
|
||||
// Just bind the back buffer for rendering, forget about doing anything else as we're in a weird state.
|
||||
draw_->BindFramebufferAsRenderTarget(nullptr, { Draw::RPAction::KEEP, Draw::RPAction::KEEP, Draw::RPAction::KEEP }, "BlitFramebuffer");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -898,7 +898,6 @@ void PresentationCommon::CopyToOutput(const DisplayLayoutConfig &config) {
|
||||
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_);
|
||||
|
||||
if (!srcFramebuffer_ && !srcTexture_) {
|
||||
|
||||
@@ -125,6 +125,7 @@ public:
|
||||
|
||||
virtual void SetDisplayFramebuffer(u32 framebuf, u32 stride, GEBufferFormat format) = 0;
|
||||
virtual void SetCurFramebufferDirty(bool dirty) = 0;
|
||||
virtual void PrepareCopyDisplayToOutput(const DisplayLayoutConfig &config) = 0;
|
||||
virtual void CopyDisplayToOutput(const DisplayLayoutConfig &config) = 0;
|
||||
virtual bool PresentedThisFrame() const = 0;
|
||||
|
||||
|
||||
+4
-1
@@ -530,7 +530,7 @@ void GPUCommonHW::PreExecuteOp(u32 op, u32 diff) {
|
||||
CheckFlushOp(op >> 24, diff);
|
||||
}
|
||||
|
||||
void GPUCommonHW::CopyDisplayToOutput(const DisplayLayoutConfig &config) {
|
||||
void GPUCommonHW::PrepareCopyDisplayToOutput(const DisplayLayoutConfig &config) {
|
||||
drawEngineCommon_->FlushQueuedDepth();
|
||||
// Flush anything left over.
|
||||
drawEngineCommon_->Flush();
|
||||
@@ -539,6 +539,9 @@ void GPUCommonHW::CopyDisplayToOutput(const DisplayLayoutConfig &config) {
|
||||
|
||||
// after this, render pass is active.
|
||||
framebufferManager_->PrepareCopyDisplayToOutput(config, curFramebufferDirty_);
|
||||
}
|
||||
|
||||
void GPUCommonHW::CopyDisplayToOutput(const DisplayLayoutConfig &config) {
|
||||
framebufferManager_->CopyDisplayToOutput(config);
|
||||
curFramebufferDirty_ = false;
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@ public:
|
||||
|
||||
// This can fail, and if so no render pass is active.
|
||||
void SetCurFramebufferDirty(bool dirty) override { curFramebufferDirty_ = dirty; }
|
||||
void PrepareCopyDisplayToOutput(const DisplayLayoutConfig &config) override;
|
||||
void CopyDisplayToOutput(const DisplayLayoutConfig &config) override;
|
||||
void DoState(PointerWrap &p) override;
|
||||
void DeviceLost() override;
|
||||
|
||||
@@ -624,7 +624,7 @@ void SoftGPU::CopyToCurrentFboFromDisplayRam(const DisplayLayoutConfig &config,
|
||||
u1 = 1.0f;
|
||||
}
|
||||
if (!hasImage) {
|
||||
draw_->BindFramebufferAsRenderTarget(nullptr, { Draw::RPAction::CLEAR, Draw::RPAction::DONT_CARE, Draw::RPAction::DONT_CARE }, "CopyToCurrentFboFromDisplayRam");
|
||||
presentation_->SourceBlank();
|
||||
presentation_->NotifyPresent();
|
||||
return;
|
||||
}
|
||||
@@ -644,13 +644,16 @@ void SoftGPU::CopyToCurrentFboFromDisplayRam(const DisplayLayoutConfig &config,
|
||||
|
||||
presentation_->SourceTexture(fbTex, desc.width, desc.height);
|
||||
presentation_->RunPostshaderPasses(config, outputFlags, config.iInternalScreenRotation, u0, v0, u1, v1);
|
||||
presentation_->CopyToOutput(config);
|
||||
}
|
||||
|
||||
void SoftGPU::CopyDisplayToOutput(const DisplayLayoutConfig &config) {
|
||||
void SoftGPU::PrepareCopyDisplayToOutput(const DisplayLayoutConfig &config) {
|
||||
drawEngine_->transformUnit.Flush(this, "output");
|
||||
// The display always shows 480x272.
|
||||
CopyToCurrentFboFromDisplayRam(config, FB_WIDTH, FB_HEIGHT);
|
||||
}
|
||||
|
||||
void SoftGPU::CopyDisplayToOutput(const DisplayLayoutConfig &config) {
|
||||
presentation_->CopyToOutput(config);
|
||||
MarkDirty(displayFramebuf_, displayStride_, 272, displayFormat_, SoftGPUVRAMDirty::CLEAR);
|
||||
}
|
||||
|
||||
|
||||
@@ -138,6 +138,7 @@ public:
|
||||
|
||||
void SetDisplayFramebuffer(u32 framebuf, u32 stride, GEBufferFormat format) override;
|
||||
void SetCurFramebufferDirty(bool dirty) override {}
|
||||
void PrepareCopyDisplayToOutput(const DisplayLayoutConfig &config) 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 *>(); }
|
||||
|
||||
+1
-1
@@ -446,7 +446,7 @@ void DrawBackground(UIContext &dc, float alpha, Lin::Vec3 focus) {
|
||||
}
|
||||
|
||||
uint32_t GetBackgroundColorWithAlpha(const UIContext &dc) {
|
||||
return colorAlpha(colorBlend(dc.GetTheme().backgroundColor, 0, 0.5f), 0.65f); // 0.65 = 166 = A6
|
||||
return colorAlpha(colorBlend(dc.GetTheme().backgroundColor, 0, 0.5f), 0.72f); // 0.72 = 183 = B7
|
||||
}
|
||||
|
||||
enum class BackgroundFillMode {
|
||||
|
||||
+83
-162
@@ -1627,14 +1627,23 @@ void EmuScreen::HandleFlip() {
|
||||
#endif
|
||||
}
|
||||
|
||||
ScreenRenderFlags EmuScreen::PreRender() {
|
||||
// If a boot is in progress, update it.
|
||||
ProcessGameBoot(gamePath_);
|
||||
|
||||
using namespace Draw;
|
||||
skipBufferEffects_ = g_Config.bSkipBufferEffects;
|
||||
if (!skipBufferEffects_) {
|
||||
// We need to run emulation here, and perform all the normal render passes.
|
||||
return RunEmulation(false);
|
||||
}
|
||||
return ScreenRenderFlags::NONE;
|
||||
}
|
||||
|
||||
ScreenRenderFlags EmuScreen::render(ScreenRenderMode mode) {
|
||||
// Moved from update, because we want it to be possible for booting to happen even when the screen
|
||||
// is in the background, like when choosing Reset from the pause menu.
|
||||
|
||||
// If a boot is in progress, update it.
|
||||
ProcessGameBoot(gamePath_);
|
||||
|
||||
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();
|
||||
@@ -1642,81 +1651,35 @@ ScreenRenderFlags EmuScreen::render(ScreenRenderMode mode) {
|
||||
return ScreenRenderFlags::NONE; // shouldn't really happen but I've seen a suspicious stack trace..
|
||||
}
|
||||
|
||||
ProcessQueuedVKeys();
|
||||
ScreenRenderFlags screenRenderFlags = ScreenRenderFlags::NONE;
|
||||
|
||||
const bool skipBufferEffects = g_Config.bSkipBufferEffects;
|
||||
|
||||
bool framebufferBound = false;
|
||||
|
||||
if (mode & ScreenRenderMode::FIRST) {
|
||||
// Actually, always gonna be first when it exists (?)
|
||||
|
||||
// Here we do NOT bind the backbuffer or clear the screen, unless non-buffered.
|
||||
// The emuscreen is different than the others - we really want to allow the game to render to framebuffers
|
||||
// before we ever bind the backbuffer for rendering. On mobile GPUs, switching back and forth between render
|
||||
// targets is a mortal sin so it's very important that we don't bind the backbuffer unnecessarily here.
|
||||
// We only bind it in FramebufferManager::CopyDisplayToOutput (unless non-buffered)...
|
||||
// We do, however, start the frame in other ways.
|
||||
|
||||
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");
|
||||
} else {
|
||||
draw->BindFramebufferAsRenderTarget(nullptr, {RPAction::CLEAR, RPAction::CLEAR, RPAction::CLEAR, 0xFF000000}, "EmuScreen_BackBuffer");
|
||||
}
|
||||
|
||||
draw->SetViewport(viewport);
|
||||
draw->SetScissorRect(0, 0, g_display.pixel_xres, g_display.pixel_yres);
|
||||
framebufferBound = true;
|
||||
}
|
||||
draw->SetTargetSize(g_display.pixel_xres, g_display.pixel_yres);
|
||||
} else {
|
||||
// Some other screen bound the backbuffer first.
|
||||
framebufferBound = true;
|
||||
if (skipBufferEffects_) {
|
||||
// In skip buffer effects mode, we run emulation *after* the backbuffer bind.
|
||||
screenRenderFlags = RunEmulation(true);
|
||||
}
|
||||
|
||||
g_OSD.NudgeIngameNotifications();
|
||||
// We might have a bad viewport after RunEmulation, reset.
|
||||
Viewport viewport{0.0f, 0.0f, (float)g_display.pixel_xres, (float)g_display.pixel_yres, 0.0f, 1.0f};
|
||||
draw->SetViewport(viewport);
|
||||
|
||||
ProcessQueuedVKeys();
|
||||
|
||||
const bool skipBufferEffects = skipBufferEffects_;
|
||||
|
||||
const DeviceOrientation orientation = GetDeviceOrientation();
|
||||
const DisplayLayoutConfig &displayLayoutConfig = g_Config.GetDisplayLayoutConfig(orientation);
|
||||
__DisplaySetDisplayLayoutConfig(displayLayoutConfig);
|
||||
|
||||
// Gotta copy the output at some point.
|
||||
if (gpu) {
|
||||
gpu->CopyDisplayToOutput(displayLayoutConfig);
|
||||
}
|
||||
|
||||
if (mode & ScreenRenderMode::TOP) {
|
||||
System_Notify(SystemNotification::KEEP_SCREEN_AWAKE);
|
||||
} else if (!ShouldRunBehind() && strcmp(screenManager()->topScreen()->tag(), "DevMenu") != 0) {
|
||||
// NOTE: The strcmp is != 0 - so all popped-over screens EXCEPT DevMenu
|
||||
// Just to make sure.
|
||||
if (PSP_IsInited() && !skipBufferEffects) {
|
||||
_dbg_assert_(gpu);
|
||||
gpu->BeginHostFrame(displayLayoutConfig);
|
||||
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::BackendState state = draw->GetCurrentBackendState();
|
||||
if (state.valid) {
|
||||
// The below can trigger when switching from skip-buffer-effects. We don't really care anymore...
|
||||
// _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");
|
||||
}
|
||||
}
|
||||
|
||||
// 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);
|
||||
darken();
|
||||
return ScreenRenderFlags::NONE;
|
||||
return screenRenderFlags;
|
||||
}
|
||||
|
||||
if (!PSP_IsInited() || readyToFinishBoot_) {
|
||||
@@ -1725,42 +1688,52 @@ ScreenRenderFlags EmuScreen::render(ScreenRenderMode mode) {
|
||||
if (mode & ScreenRenderMode::TOP) {
|
||||
checkPowerDown();
|
||||
}
|
||||
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 ScreenRenderFlags::NONE;
|
||||
return screenRenderFlags;
|
||||
}
|
||||
|
||||
// Freeze-frame functionality (loads a savestate on every frame).
|
||||
if (PSP_CoreParameter().freezeNext) {
|
||||
PSP_CoreParameter().frozen = true;
|
||||
PSP_CoreParameter().freezeNext = false;
|
||||
SaveState::SaveToRam(freezeState_);
|
||||
} else if (PSP_CoreParameter().frozen) {
|
||||
std::string errorString;
|
||||
if (CChunkFileReader::ERROR_NONE != SaveState::LoadFromRam(freezeState_, &errorString)) {
|
||||
ERROR_LOG(Log::SaveState, "Failed to load freeze state (%s). Unfreezing.", errorString.c_str());
|
||||
PSP_CoreParameter().frozen = false;
|
||||
}
|
||||
}
|
||||
|
||||
// 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);
|
||||
Draw::BackendState state = draw->GetCurrentBackendState();
|
||||
|
||||
if (!(mode & ScreenRenderMode::TOP)) {
|
||||
renderImDebugger();
|
||||
// We're in run-behind mode, but we don't want to draw chat, debug UI and stuff. We do draw the imdebugger though.
|
||||
// So, darken and bail here.
|
||||
// Reset viewport/scissor to be sure.
|
||||
darken();
|
||||
return screenRenderFlags;
|
||||
}
|
||||
|
||||
// NOTE: We don't check for powerdown if we're not the top screen.
|
||||
checkPowerDown();
|
||||
|
||||
if (hasVisibleUI()) {
|
||||
cardboardDisableButton_->SetVisibility(displayLayoutConfig.bEnableCardboardVR ? UI::V_VISIBLE : UI::V_GONE);
|
||||
renderUI();
|
||||
}
|
||||
|
||||
if (chatMenu_ && (chatMenu_->GetVisibility() == UI::V_VISIBLE)) {
|
||||
SetVRAppMode(VRAppMode::VR_DIALOG_MODE);
|
||||
} else {
|
||||
SetVRAppMode(screenManager()->topScreen() == this ? VRAppMode::VR_GAME_MODE : VRAppMode::VR_DIALOG_MODE);
|
||||
}
|
||||
|
||||
renderImDebugger();
|
||||
return screenRenderFlags;
|
||||
}
|
||||
|
||||
ScreenRenderFlags EmuScreen::RunEmulation(ScreenRenderMode mode, bool framebufferBound, bool skipBufferEffects) {
|
||||
ScreenRenderFlags EmuScreen::RunEmulation(bool skipBufferEffects) {
|
||||
using namespace Draw;
|
||||
ScreenRenderFlags flags = ScreenRenderFlags::NONE;
|
||||
|
||||
g_OSD.NudgeIngameNotifications();
|
||||
|
||||
const DeviceOrientation orientation = GetDeviceOrientation();
|
||||
const DisplayLayoutConfig &displayLayoutConfig = g_Config.GetDisplayLayoutConfig(orientation);
|
||||
__DisplaySetDisplayLayoutConfig(displayLayoutConfig);
|
||||
|
||||
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};
|
||||
|
||||
@@ -1771,12 +1744,23 @@ ScreenRenderFlags EmuScreen::RunEmulation(ScreenRenderMode mode, bool framebuffe
|
||||
if (gpu) {
|
||||
gpu->BeginHostFrame(displayLayoutConfig);
|
||||
}
|
||||
if (SaveState::Process()) {
|
||||
// We might have lost the framebuffer bind if we had one, due to a readback.
|
||||
if (framebufferBound) {
|
||||
draw->BindFramebufferAsRenderTarget(nullptr, { RPAction::CLEAR, RPAction::CLEAR, RPAction::CLEAR, clearColor }, "EmuScreen_SavestateRebind");
|
||||
|
||||
// Freeze-frame functionality (loads a savestate on every frame).
|
||||
if (PSP_CoreParameter().freezeNext) {
|
||||
PSP_CoreParameter().frozen = true;
|
||||
PSP_CoreParameter().freezeNext = false;
|
||||
SaveState::SaveToRam(freezeState_);
|
||||
} else if (PSP_CoreParameter().frozen) {
|
||||
std::string errorString;
|
||||
if (CChunkFileReader::ERROR_NONE != SaveState::LoadFromRam(freezeState_, &errorString)) {
|
||||
ERROR_LOG(Log::SaveState, "Failed to load freeze state (%s). Unfreezing.", errorString.c_str());
|
||||
PSP_CoreParameter().frozen = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (SaveState::Process()) {
|
||||
// TODO: investigate.
|
||||
}
|
||||
PSP_RunLoopWhileState();
|
||||
|
||||
// Hopefully, after running, coreState is now CORE_NEXTFRAME
|
||||
@@ -1796,17 +1780,13 @@ ScreenRenderFlags EmuScreen::RunEmulation(ScreenRenderMode mode, bool framebuffe
|
||||
// Clear to blue background screen
|
||||
bool dangerousSettings = !Reporting::IsSupported();
|
||||
clearColor = dangerousSettings ? 0xFF900050 : 0xFF900000;
|
||||
draw->BindFramebufferAsRenderTarget(nullptr, { RPAction::CLEAR, RPAction::CLEAR, RPAction::CLEAR, clearColor }, "EmuScreen_RuntimeError");
|
||||
framebufferBound = true;
|
||||
draw->Clear(Draw::Aspect::COLOR_BIT, clearColor, 0.0f, 0);
|
||||
// The info is drawn later in renderUI
|
||||
} else {
|
||||
// If we're stepping, it's convenient not to clear the screen entirely, so we copy display to output.
|
||||
// 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");
|
||||
if (PSP_IsInited()) {
|
||||
gpu->SetCurFramebufferDirty(true);
|
||||
gpu->CopyDisplayToOutput(displayLayoutConfig);
|
||||
framebufferBound = true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -1823,6 +1803,8 @@ ScreenRenderFlags EmuScreen::RunEmulation(ScreenRenderMode mode, bool framebuffe
|
||||
}
|
||||
|
||||
if (gpu) {
|
||||
// Run post processing and other passes.
|
||||
gpu->PrepareCopyDisplayToOutput(displayLayoutConfig);
|
||||
gpu->EndHostFrame();
|
||||
}
|
||||
|
||||
@@ -1850,58 +1832,6 @@ ScreenRenderFlags EmuScreen::RunEmulation(ScreenRenderMode mode, bool framebuffe
|
||||
}
|
||||
}
|
||||
|
||||
if (gpu && gpu->PresentedThisFrame()) {
|
||||
framebufferBound = true;
|
||||
}
|
||||
|
||||
if (!framebufferBound) {
|
||||
draw->BindFramebufferAsRenderTarget(nullptr, { RPAction::CLEAR, RPAction::CLEAR, RPAction::CLEAR, clearColor }, "EmuScreen_NoFrame");
|
||||
draw->SetViewport(viewport);
|
||||
draw->SetScissorRect(0, 0, g_display.pixel_xres, g_display.pixel_yres);
|
||||
}
|
||||
|
||||
Draw::BackendState state = draw->GetCurrentBackendState();
|
||||
|
||||
// State.valid just states whether the passes parameter has a meaningful value.
|
||||
if (state.valid) {
|
||||
_dbg_assert_msg_(state.passes >= 1, "skipB: %d sw: %d mode: %d back: %d bound: %d", (int)skipBufferEffects, (int)g_Config.bSoftwareRendering, (int)mode, (int)g_Config.iGPUBackend, (int)framebufferBound);
|
||||
if (state.passes == 0) {
|
||||
// Workaround any remaining bugs like this.
|
||||
draw->BindFramebufferAsRenderTarget(nullptr, { RPAction::CLEAR, RPAction::CLEAR, RPAction::CLEAR, }, "EmuScreen_SafeFallback");
|
||||
}
|
||||
}
|
||||
|
||||
screenManager()->getUIContext()->BeginFrame();
|
||||
|
||||
if (!(mode & ScreenRenderMode::TOP)) {
|
||||
renderImDebugger();
|
||||
// We're in run-behind mode, but we don't want to draw chat, debug UI and stuff. We do draw the imdebugger though.
|
||||
// So, darken and bail here.
|
||||
// Reset viewport/scissor to be sure.
|
||||
draw->SetViewport(viewport);
|
||||
draw->SetScissorRect(0, 0, g_display.pixel_xres, g_display.pixel_yres);
|
||||
darken();
|
||||
return flags;
|
||||
}
|
||||
|
||||
// NOTE: We don't check for powerdown if we're not the top screen.
|
||||
if (checkPowerDown()) {
|
||||
draw->BindFramebufferAsRenderTarget(nullptr, { RPAction::CLEAR, RPAction::CLEAR, RPAction::CLEAR, clearColor }, "EmuScreen_PowerDown");
|
||||
}
|
||||
|
||||
if (hasVisibleUI()) {
|
||||
draw->SetViewport(viewport);
|
||||
cardboardDisableButton_->SetVisibility(displayLayoutConfig.bEnableCardboardVR ? UI::V_VISIBLE : UI::V_GONE);
|
||||
renderUI();
|
||||
}
|
||||
|
||||
if (chatMenu_ && (chatMenu_->GetVisibility() == UI::V_VISIBLE)) {
|
||||
SetVRAppMode(VRAppMode::VR_DIALOG_MODE);
|
||||
} else {
|
||||
SetVRAppMode(screenManager()->topScreen() == this ? VRAppMode::VR_GAME_MODE : VRAppMode::VR_DIALOG_MODE);
|
||||
}
|
||||
|
||||
renderImDebugger();
|
||||
return flags;
|
||||
}
|
||||
|
||||
@@ -2017,21 +1947,12 @@ bool EmuScreen::hasVisibleUI() {
|
||||
void EmuScreen::renderUI() {
|
||||
using namespace Draw;
|
||||
|
||||
DrawContext *thin3d = screenManager()->getDrawContext();
|
||||
DrawContext *draw = screenManager()->getDrawContext();
|
||||
UIContext *ctx = screenManager()->getUIContext();
|
||||
ctx->BeginFrame();
|
||||
// This sets up some important states but not the viewport.
|
||||
ctx->Begin();
|
||||
|
||||
Viewport viewport;
|
||||
viewport.TopLeftX = 0;
|
||||
viewport.TopLeftY = 0;
|
||||
viewport.Width = g_display.pixel_xres;
|
||||
viewport.Height = g_display.pixel_yres;
|
||||
viewport.MaxDepth = 1.0;
|
||||
viewport.MinDepth = 0.0;
|
||||
thin3d->SetViewport(viewport);
|
||||
|
||||
if (root_) {
|
||||
UI::LayoutViewHierarchy(*ctx, RootMargins(), root_, false, false);
|
||||
root_->Draw(*ctx);
|
||||
|
||||
+3
-1
@@ -70,10 +70,11 @@ public:
|
||||
protected:
|
||||
void darken();
|
||||
void focusChanged(ScreenFocusChange focusChange) override;
|
||||
ScreenRenderFlags PreRender() override;
|
||||
|
||||
private:
|
||||
void CreateViews() override;
|
||||
ScreenRenderFlags RunEmulation(ScreenRenderMode mode, bool framebufferBound, bool skipBufferEffects);
|
||||
ScreenRenderFlags RunEmulation(bool skipBufferEffects);
|
||||
void OnDevTools(UI::EventParams ¶ms);
|
||||
void OnChat(UI::EventParams ¶ms);
|
||||
|
||||
@@ -159,6 +160,7 @@ private:
|
||||
#endif
|
||||
bool autoLoadFailed_ = false; // to prevent repeat reloads
|
||||
bool readyToFinishBoot_ = false;
|
||||
bool skipBufferEffects_ = false; // cached state, fetched once per frame.
|
||||
};
|
||||
|
||||
bool MustRunBehind();
|
||||
|
||||
@@ -98,12 +98,6 @@ void HandleCommonMessages(UIMessage message, const char *value, ScreenManager *m
|
||||
}
|
||||
|
||||
ScreenRenderFlags BackgroundScreen::render(ScreenRenderMode mode) {
|
||||
if (mode & ScreenRenderMode::FIRST) {
|
||||
SetupViewport();
|
||||
} else {
|
||||
_dbg_assert_(false);
|
||||
}
|
||||
|
||||
UIContext *uiContext = screenManager()->getUIContext();
|
||||
|
||||
uiContext->PushTransform({ translation_, scale_, alpha_ });
|
||||
|
||||
+1
-1
@@ -1151,7 +1151,7 @@ void NativeFrame(GraphicsContext *graphicsContext) {
|
||||
|
||||
g_screenManager->getUIContext()->SetTintSaturation(g_Config.fUITint, g_Config.fUISaturation);
|
||||
|
||||
// All actual rendering happen in here.
|
||||
// All actual rendering (and also emulation) happens in here.
|
||||
ScreenRenderFlags renderFlags = g_screenManager->render();
|
||||
if (g_screenManager->getUIContext()->Text()) {
|
||||
g_screenManager->getUIContext()->Text()->OncePerFrame();
|
||||
|
||||
@@ -266,10 +266,11 @@ bool RunAutoTest(HeadlessHost *headlessHost, CoreParameter &coreParameter, const
|
||||
}
|
||||
|
||||
if (draw) {
|
||||
draw->BindFramebufferAsRenderTarget(nullptr, { Draw::RPAction::CLEAR, Draw::RPAction::DONT_CARE, Draw::RPAction::DONT_CARE }, "Headless");
|
||||
draw->BindFramebufferAsRenderTarget(nullptr, { Draw::RPAction::CLEAR, Draw::RPAction::DONT_CARE, Draw::RPAction::DONT_CARE }, "Backbuffer");
|
||||
// Vulkan may get angry if we don't do a final present.
|
||||
if (gpu) {
|
||||
gpu->SetCurFramebufferDirty(true);
|
||||
gpu->PrepareCopyDisplayToOutput(g_Config.GetDisplayLayoutConfig(DeviceOrientation::Landscape));
|
||||
gpu->CopyDisplayToOutput(g_Config.GetDisplayLayoutConfig(DeviceOrientation::Landscape));
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user