Frontend PR fixes (#6378)

* citra_qt: Check if renderer is null

* core: Fix dynarmic use-after-free error

* bootmanager: Add current context check in DoneCurrent

* Loading a save state would destroy the frame dumper class, which contains a shared context. That context would call DoneCurrent without checking if it was actually bound or not, resulting in crashes when calling opengl functions

* externals: Correct glad readme

* common: Log renderer debug setting

* citra: Make lambda lower case

* Consistency with review comments on the PR

* video_core: Kill more global state

* GetResolutionScaleFactor would be called somewhere in the renderer constructor chain but it relies on the yet unitialized g_renderer, resulting in crashes when the resolution scale is set to auto. Rather than adding a workaround, let's kill this global state to fix this for good
This commit is contained in:
GPUCode
2023-03-30 14:24:49 +03:00
committed by GitHub
parent 5346ca27b5
commit ffc95eb59b
17 changed files with 102 additions and 93 deletions

View File

@@ -9,6 +9,7 @@
#include "common/microprofile.h"
#include "video_core/pica_state.h"
#include "video_core/rasterizer_cache/rasterizer_cache.h"
#include "video_core/renderer_base.h"
#include "video_core/renderer_opengl/gl_format_reinterpreter.h"
#include "video_core/renderer_opengl/texture_downloader_es.h"
#include "video_core/renderer_opengl/texture_filters/texture_filterer.h"
@@ -239,8 +240,9 @@ static Surface FindMatch(const SurfaceCache& surface_cache, const SurfaceParams&
return match_surface;
}
RasterizerCacheOpenGL::RasterizerCacheOpenGL() {
resolution_scale_factor = VideoCore::GetResolutionScaleFactor();
RasterizerCacheOpenGL::RasterizerCacheOpenGL(VideoCore::RendererBase& renderer_)
: renderer{renderer_} {
resolution_scale_factor = renderer.GetResolutionScaleFactor();
texture_filterer = std::make_unique<TextureFilterer>(
Settings::values.texture_filter_name.GetValue(), resolution_scale_factor);
format_reinterpreter = std::make_unique<FormatReinterpreterOpenGL>();
@@ -588,15 +590,14 @@ SurfaceSurfaceRect_Tuple RasterizerCacheOpenGL::GetFramebufferSurfaces(
const auto& config = regs.framebuffer.framebuffer;
// Update resolution_scale_factor and reset cache if changed
const bool resolution_scale_changed =
resolution_scale_factor != VideoCore::GetResolutionScaleFactor();
const u32 scale_factor = renderer.GetResolutionScaleFactor();
const bool resolution_scale_changed = resolution_scale_factor != scale_factor;
const bool texture_filter_changed =
VideoCore::g_texture_filter_update_requested.exchange(false) &&
texture_filterer->Reset(Settings::values.texture_filter_name.GetValue(),
VideoCore::GetResolutionScaleFactor());
renderer.Settings().texture_filter_update_requested.exchange(false) &&
texture_filterer->Reset(Settings::values.texture_filter_name.GetValue(), scale_factor);
if (resolution_scale_changed || texture_filter_changed) {
resolution_scale_factor = VideoCore::GetResolutionScaleFactor();
resolution_scale_factor = scale_factor;
FlushAll();
while (!surface_cache.empty())
UnregisterSurface(*surface_cache.begin()->second.begin());

View File

@@ -9,6 +9,10 @@
#include "video_core/rasterizer_cache/surface_params.h"
#include "video_core/texture/texture_decode.h"
namespace VideoCore {
class RendererBase;
}
namespace OpenGL {
enum class ScaleMatch {
@@ -23,7 +27,7 @@ class FormatReinterpreterOpenGL;
class RasterizerCacheOpenGL : NonCopyable {
public:
RasterizerCacheOpenGL();
RasterizerCacheOpenGL(VideoCore::RendererBase& renderer);
~RasterizerCacheOpenGL();
/// Blit one surface's texture to another
@@ -108,6 +112,7 @@ private:
/// Increase/decrease the number of surface in pages touching the specified region
void UpdatePagesCachedCount(PAddr addr, u32 size, int delta);
VideoCore::RendererBase& renderer;
TextureRuntime runtime;
SurfaceCache surface_cache;
PageMap cached_pages;

View File

@@ -16,6 +16,18 @@ RendererBase::RendererBase(Core::System& system_, Frontend::EmuWindow& window,
RendererBase::~RendererBase() = default;
u32 RendererBase::GetResolutionScaleFactor() {
const auto graphics_api = Settings::values.graphics_api.GetValue();
if (graphics_api == Settings::GraphicsAPI::Software) {
// Software renderer always render at native resolution
return 1;
}
const u32 scale_factor = Settings::values.resolution_factor.GetValue();
return scale_factor != 0 ? scale_factor
: render_window.GetFramebufferLayout().GetScalingRatio();
}
void RendererBase::UpdateCurrentFramebufferLayout(bool is_portrait_mode) {
const auto update_layout = [is_portrait_mode](Frontend::EmuWindow& window) {
const Layout::FramebufferLayout& layout = window.GetFramebufferLayout();
@@ -43,19 +55,19 @@ void RendererBase::EndFrame() {
}
bool RendererBase::IsScreenshotPending() const {
return renderer_settings.screenshot_requested;
return settings.screenshot_requested;
}
void RendererBase::RequestScreenshot(void* data, std::function<void()> callback,
const Layout::FramebufferLayout& layout) {
if (renderer_settings.screenshot_requested) {
if (settings.screenshot_requested) {
LOG_ERROR(Render, "A screenshot is already requested or in progress, ignoring the request");
return;
}
renderer_settings.screenshot_bits = data;
renderer_settings.screenshot_complete_callback = callback;
renderer_settings.screenshot_framebuffer_layout = layout;
renderer_settings.screenshot_requested = true;
settings.screenshot_bits = data;
settings.screenshot_complete_callback = callback;
settings.screenshot_framebuffer_layout = layout;
settings.screenshot_requested = true;
}
} // namespace VideoCore

View File

@@ -24,6 +24,11 @@ struct RendererSettings {
void* screenshot_bits{};
std::function<void()> screenshot_complete_callback;
Layout::FramebufferLayout screenshot_framebuffer_layout;
// Renderer
std::atomic_bool texture_filter_update_requested{false};
std::atomic_bool bg_color_update_requested{false};
std::atomic_bool sampler_update_requested{false};
std::atomic_bool shader_update_requested{false};
};
class RendererBase : NonCopyable {
@@ -54,6 +59,9 @@ public:
/// Synchronizes fixed function renderer state
virtual void Sync() {}
/// Returns the resolution scale factor relative to the native 3DS screen resolution
u32 GetResolutionScaleFactor();
/// Updates the framebuffer layout of the contained render window handle.
void UpdateCurrentFramebufferLayout(bool is_portrait_mode = {});
@@ -80,11 +88,11 @@ public:
}
[[nodiscard]] RendererSettings& Settings() {
return renderer_settings;
return settings;
}
[[nodiscard]] const RendererSettings& Settings() const {
return renderer_settings;
return settings;
}
/// Returns true if a screenshot is being processed
@@ -96,7 +104,7 @@ public:
protected:
Core::System& system;
RendererSettings renderer_settings;
RendererSettings settings;
Frontend::EmuWindow& render_window; ///< Reference to the render window handle.
Frontend::EmuWindow* secondary_window; ///< Reference to the secondary render window handle.
f32 current_fps = 0.0f; ///< Current framerate, should be set by the renderer

View File

@@ -64,11 +64,10 @@ GLenum MakeAttributeType(Pica::PipelineRegs::VertexAttributeFormat format) {
} // Anonymous namespace
RasterizerOpenGL::RasterizerOpenGL(Memory::MemorySystem& memory, Frontend::EmuWindow& emu_window,
RasterizerOpenGL::RasterizerOpenGL(Memory::MemorySystem& memory, VideoCore::RendererBase& renderer,
Driver& driver_)
: VideoCore::RasterizerAccelerated{memory}, driver{driver_}, vertex_buffer{driver,
GL_ARRAY_BUFFER,
VERTEX_BUFFER_SIZE},
: VideoCore::RasterizerAccelerated{memory}, driver{driver_}, res_cache{renderer},
vertex_buffer{driver, GL_ARRAY_BUFFER, VERTEX_BUFFER_SIZE},
uniform_buffer{driver, GL_UNIFORM_BUFFER, UNIFORM_BUFFER_SIZE},
index_buffer{driver, GL_ELEMENT_ARRAY_BUFFER, INDEX_BUFFER_SIZE},
texture_buffer{driver, GL_TEXTURE_BUFFER, TEXTURE_BUFFER_SIZE}, texture_lf_buffer{
@@ -167,12 +166,14 @@ RasterizerOpenGL::RasterizerOpenGL(Memory::MemorySystem& memory, Frontend::EmuWi
#ifdef __APPLE__
if (driver.GetVendor() == Vendor::Intel) {
shader_program_manager = std::make_unique<ShaderProgramManager>(
emu_window, driver, VideoCore::g_separable_shader_enabled);
renderer.GetRenderWindow(), driver, VideoCore::g_separable_shader_enabled);
} else {
shader_program_manager = std::make_unique<ShaderProgramManager>(emu_window, driver, true);
shader_program_manager =
std::make_unique<ShaderProgramManager>(renderer.GetRenderWindow(), driver, true);
}
#else
shader_program_manager = std::make_unique<ShaderProgramManager>(emu_window, driver, !GLES);
shader_program_manager =
std::make_unique<ShaderProgramManager>(renderer.GetRenderWindow(), driver, !GLES);
#endif
glEnable(GL_BLEND);

View File

@@ -14,8 +14,8 @@
#include "video_core/renderer_opengl/gl_stream_buffer.h"
#include "video_core/shader/shader.h"
namespace Frontend {
class EmuWindow;
namespace VideoCore {
class RendererBase;
}
namespace OpenGL {
@@ -25,7 +25,7 @@ class ShaderProgramManager;
class RasterizerOpenGL : public VideoCore::RasterizerAccelerated {
public:
explicit RasterizerOpenGL(Memory::MemorySystem& memory, Frontend::EmuWindow& emu_window,
explicit RasterizerOpenGL(Memory::MemorySystem& memory, VideoCore::RendererBase& renderer,
Driver& driver);
~RasterizerOpenGL() override;

View File

@@ -360,7 +360,7 @@ RendererOpenGL::RendererOpenGL(Core::System& system, Frontend::EmuWindow& window
}
frame_dumper.mailbox = std::make_unique<OGLVideoDumpingMailbox>();
InitOpenGLObjects();
rasterizer = std::make_unique<RasterizerOpenGL>(system.Memory(), render_window, driver);
rasterizer = std::make_unique<RasterizerOpenGL>(system.Memory(), *this, driver);
}
RendererOpenGL::~RendererOpenGL() = default;
@@ -401,7 +401,7 @@ void RendererOpenGL::SwapBuffers() {
}
void RendererOpenGL::RenderScreenshot() {
if (renderer_settings.screenshot_requested.exchange(false)) {
if (settings.screenshot_requested.exchange(false)) {
// Draw this frame to the screenshot framebuffer
screenshot_framebuffer.Create();
GLuint old_read_fb = state.draw.read_framebuffer;
@@ -409,7 +409,7 @@ void RendererOpenGL::RenderScreenshot() {
state.draw.read_framebuffer = state.draw.draw_framebuffer = screenshot_framebuffer.handle;
state.Apply();
const auto layout{renderer_settings.screenshot_framebuffer_layout};
const Layout::FramebufferLayout layout{settings.screenshot_framebuffer_layout};
GLuint renderbuffer;
glGenRenderbuffers(1, &renderbuffer);
@@ -421,7 +421,7 @@ void RendererOpenGL::RenderScreenshot() {
DrawScreens(layout, false);
glReadPixels(0, 0, layout.width, layout.height, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV,
renderer_settings.screenshot_bits);
settings.screenshot_bits);
screenshot_framebuffer.Release();
state.draw.read_framebuffer = old_read_fb;
@@ -429,7 +429,7 @@ void RendererOpenGL::RenderScreenshot() {
state.Apply();
glDeleteRenderbuffers(1, &renderbuffer);
renderer_settings.screenshot_complete_callback();
settings.screenshot_complete_callback();
}
}
@@ -808,7 +808,7 @@ void RendererOpenGL::DrawSingleScreenRotated(const ScreenInfo& screen_info, floa
// As this is the "DrawSingleScreenRotated" function, the output resolution dimensions have been
// swapped. If a non-rotated draw-screen function were to be added for book-mode games, those
// should probably be set to the standard (w, h, 1.0 / w, 1.0 / h) ordering.
const u16 scale_factor = VideoCore::GetResolutionScaleFactor();
const u32 scale_factor = GetResolutionScaleFactor();
glUniform4f(uniform_i_resolution, static_cast<float>(screen_info.texture.width * scale_factor),
static_cast<float>(screen_info.texture.height * scale_factor),
1.0f / static_cast<float>(screen_info.texture.width * scale_factor),
@@ -837,7 +837,7 @@ void RendererOpenGL::DrawSingleScreen(const ScreenInfo& screen_info, float x, fl
ScreenRectVertex(x + w, y + h, texcoords.top, texcoords.left),
}};
const u16 scale_factor = VideoCore::GetResolutionScaleFactor();
const u32 scale_factor = GetResolutionScaleFactor();
glUniform4f(uniform_i_resolution, static_cast<float>(screen_info.texture.width * scale_factor),
static_cast<float>(screen_info.texture.height * scale_factor),
1.0f / static_cast<float>(screen_info.texture.width * scale_factor),
@@ -871,7 +871,7 @@ void RendererOpenGL::DrawSingleScreenStereoRotated(const ScreenInfo& screen_info
ScreenRectVertex(x + w, y + h, texcoords.top, texcoords.right),
}};
const u16 scale_factor = VideoCore::GetResolutionScaleFactor();
const u32 scale_factor = GetResolutionScaleFactor();
glUniform4f(uniform_i_resolution,
static_cast<float>(screen_info_l.texture.width * scale_factor),
static_cast<float>(screen_info_l.texture.height * scale_factor),
@@ -906,7 +906,7 @@ void RendererOpenGL::DrawSingleScreenStereo(const ScreenInfo& screen_info_l,
ScreenRectVertex(x + w, y + h, texcoords.top, texcoords.left),
}};
const u16 scale_factor = VideoCore::GetResolutionScaleFactor();
const u32 scale_factor = GetResolutionScaleFactor();
glUniform4f(uniform_i_resolution,
static_cast<float>(screen_info_l.texture.width * scale_factor),
static_cast<float>(screen_info_l.texture.height * scale_factor),
@@ -933,18 +933,18 @@ void RendererOpenGL::DrawSingleScreenStereo(const ScreenInfo& screen_info_l,
* Draws the emulated screens to the emulator window.
*/
void RendererOpenGL::DrawScreens(const Layout::FramebufferLayout& layout, bool flipped) {
if (VideoCore::g_renderer_bg_color_update_requested.exchange(false)) {
if (settings.bg_color_update_requested.exchange(false)) {
// Update background color before drawing
glClearColor(Settings::values.bg_red.GetValue(), Settings::values.bg_green.GetValue(),
Settings::values.bg_blue.GetValue(), 0.0f);
}
if (VideoCore::g_renderer_sampler_update_requested.exchange(false)) {
if (settings.sampler_update_requested.exchange(false)) {
// Set the new filtering mode for the sampler
ReloadSampler();
}
if (VideoCore::g_renderer_shader_update_requested.exchange(false)) {
if (settings.shader_update_requested.exchange(false)) {
// Update fragment shader before drawing
shader.Release();
// Link shaders and get variable locations

View File

@@ -26,11 +26,6 @@ std::atomic<bool> g_shader_jit_enabled;
std::atomic<bool> g_hw_shader_enabled;
std::atomic<bool> g_separable_shader_enabled;
std::atomic<bool> g_hw_shader_accurate_mul;
std::atomic<bool> g_use_disk_shader_cache;
std::atomic<bool> g_renderer_bg_color_update_requested;
std::atomic<bool> g_renderer_sampler_update_requested;
std::atomic<bool> g_renderer_shader_update_requested;
std::atomic<bool> g_texture_filter_update_requested;
Memory::MemorySystem* g_memory;
@@ -64,18 +59,6 @@ void Shutdown() {
LOG_DEBUG(Render, "shutdown OK");
}
u16 GetResolutionScaleFactor() {
const auto graphics_api = Settings::values.graphics_api.GetValue();
if (graphics_api == Settings::GraphicsAPI::Software) {
// Software renderer always render at native resolution
return 1;
}
return Settings::values.resolution_factor.GetValue()
? Settings::values.resolution_factor.GetValue()
: g_renderer->GetRenderWindow().GetFramebufferLayout().GetScalingRatio();
}
template <class Archive>
void serialize(Archive& ar, const unsigned int) {
ar& Pica::g_state;

View File

@@ -37,11 +37,6 @@ extern std::atomic<bool> g_shader_jit_enabled;
extern std::atomic<bool> g_hw_shader_enabled;
extern std::atomic<bool> g_separable_shader_enabled;
extern std::atomic<bool> g_hw_shader_accurate_mul;
extern std::atomic<bool> g_use_disk_shader_cache;
extern std::atomic<bool> g_renderer_bg_color_update_requested;
extern std::atomic<bool> g_renderer_sampler_update_requested;
extern std::atomic<bool> g_renderer_shader_update_requested;
extern std::atomic<bool> g_texture_filter_update_requested;
extern Memory::MemorySystem* g_memory;
@@ -52,8 +47,6 @@ void Init(Frontend::EmuWindow& emu_window, Frontend::EmuWindow* secondary_window
/// Shutdown the video core
void Shutdown();
u16 GetResolutionScaleFactor();
template <class Archive>
void serialize(Archive& ar, const unsigned int file_version);