renderer_opengl: Add driver class to report info/bugs
This commit is contained in:
@ -59,6 +59,60 @@ __declspec(dllimport) void __stdcall DebugBreak(void);
|
||||
|
||||
#endif // _MSC_VER ndef
|
||||
|
||||
#define DECLARE_ENUM_FLAG_OPERATORS(type) \
|
||||
[[nodiscard]] constexpr type operator|(type a, type b) noexcept { \
|
||||
using T = std::underlying_type_t<type>; \
|
||||
return static_cast<type>(static_cast<T>(a) | static_cast<T>(b)); \
|
||||
} \
|
||||
[[nodiscard]] constexpr type operator&(type a, type b) noexcept { \
|
||||
using T = std::underlying_type_t<type>; \
|
||||
return static_cast<type>(static_cast<T>(a) & static_cast<T>(b)); \
|
||||
} \
|
||||
[[nodiscard]] constexpr type operator^(type a, type b) noexcept { \
|
||||
using T = std::underlying_type_t<type>; \
|
||||
return static_cast<type>(static_cast<T>(a) ^ static_cast<T>(b)); \
|
||||
} \
|
||||
[[nodiscard]] constexpr type operator<<(type a, type b) noexcept { \
|
||||
using T = std::underlying_type_t<type>; \
|
||||
return static_cast<type>(static_cast<T>(a) << static_cast<T>(b)); \
|
||||
} \
|
||||
[[nodiscard]] constexpr type operator>>(type a, type b) noexcept { \
|
||||
using T = std::underlying_type_t<type>; \
|
||||
return static_cast<type>(static_cast<T>(a) >> static_cast<T>(b)); \
|
||||
} \
|
||||
constexpr type& operator|=(type& a, type b) noexcept { \
|
||||
a = a | b; \
|
||||
return a; \
|
||||
} \
|
||||
constexpr type& operator&=(type& a, type b) noexcept { \
|
||||
a = a & b; \
|
||||
return a; \
|
||||
} \
|
||||
constexpr type& operator^=(type& a, type b) noexcept { \
|
||||
a = a ^ b; \
|
||||
return a; \
|
||||
} \
|
||||
constexpr type& operator<<=(type& a, type b) noexcept { \
|
||||
a = a << b; \
|
||||
return a; \
|
||||
} \
|
||||
constexpr type& operator>>=(type& a, type b) noexcept { \
|
||||
a = a >> b; \
|
||||
return a; \
|
||||
} \
|
||||
[[nodiscard]] constexpr type operator~(type key) noexcept { \
|
||||
using T = std::underlying_type_t<type>; \
|
||||
return static_cast<type>(~static_cast<T>(key)); \
|
||||
} \
|
||||
[[nodiscard]] constexpr bool True(type key) noexcept { \
|
||||
using T = std::underlying_type_t<type>; \
|
||||
return static_cast<T>(key) != 0; \
|
||||
} \
|
||||
[[nodiscard]] constexpr bool False(type key) noexcept { \
|
||||
using T = std::underlying_type_t<type>; \
|
||||
return static_cast<T>(key) == 0; \
|
||||
}
|
||||
|
||||
// Generic function to get last error message.
|
||||
// Call directly after the command or use the error num.
|
||||
// This function might change the error code.
|
||||
|
@ -41,6 +41,8 @@ add_library(video_core STATIC
|
||||
rasterizer_cache/texture_runtime.h
|
||||
renderer_opengl/frame_dumper_opengl.cpp
|
||||
renderer_opengl/frame_dumper_opengl.h
|
||||
renderer_opengl/gl_driver.cpp
|
||||
renderer_opengl/gl_driver.h
|
||||
renderer_opengl/gl_rasterizer.cpp
|
||||
renderer_opengl/gl_rasterizer.h
|
||||
renderer_opengl/gl_resource_manager.cpp
|
||||
|
@ -3,7 +3,6 @@
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
#include <list>
|
||||
#include "common/assert.h"
|
||||
#include "core/custom_tex_cache.h"
|
||||
#include "video_core/rasterizer_cache/surface_params.h"
|
||||
@ -78,7 +77,7 @@ public:
|
||||
|
||||
std::shared_ptr<SurfaceWatcher> CreateWatcher() {
|
||||
auto watcher = std::make_shared<SurfaceWatcher>(weak_from_this());
|
||||
watchers.push_front(watcher);
|
||||
watchers[watcher_count++] = watcher;
|
||||
return watcher;
|
||||
}
|
||||
|
||||
@ -98,7 +97,8 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
watchers.clear();
|
||||
watchers = {};
|
||||
watcher_count = 0;
|
||||
}
|
||||
|
||||
public:
|
||||
@ -111,7 +111,6 @@ public:
|
||||
std::array<u8, 4> fill_data;
|
||||
OGLTexture texture;
|
||||
|
||||
// level_watchers[i] watches the (i+1)-th level mipmap source surface
|
||||
std::array<std::shared_ptr<SurfaceWatcher>, 7> level_watchers;
|
||||
u32 max_level = 0;
|
||||
|
||||
@ -122,7 +121,8 @@ public:
|
||||
private:
|
||||
RasterizerCache& owner;
|
||||
TextureRuntime& runtime;
|
||||
std::list<std::weak_ptr<SurfaceWatcher>> watchers;
|
||||
u32 watcher_count = 0;
|
||||
std::array<std::weak_ptr<SurfaceWatcher>, 8> watchers;
|
||||
};
|
||||
|
||||
struct CachedTextureCube {
|
||||
|
@ -203,8 +203,8 @@ static Surface FindMatch(const SurfaceCache& surface_cache, const SurfaceParams&
|
||||
return match_surface;
|
||||
}
|
||||
|
||||
RasterizerCache::RasterizerCache(VideoCore::RasterizerAccelerated& rasterizer)
|
||||
: rasterizer(rasterizer) {
|
||||
RasterizerCache::RasterizerCache(VideoCore::RasterizerAccelerated& rasterizer, Driver& driver)
|
||||
: rasterizer(rasterizer), runtime(driver) {
|
||||
resolution_scale_factor = VideoCore::GetResolutionScaleFactor();
|
||||
texture_filterer = std::make_unique<TextureFilterer>(
|
||||
Settings::values.texture_filter_name.GetValue(), resolution_scale_factor);
|
||||
|
@ -38,13 +38,14 @@ enum class ScaleMatch {
|
||||
Ignore // Accept every scaled res
|
||||
};
|
||||
|
||||
class Driver;
|
||||
class TextureDownloaderES;
|
||||
class TextureFilterer;
|
||||
class FormatReinterpreterOpenGL;
|
||||
|
||||
class RasterizerCache : NonCopyable {
|
||||
public:
|
||||
RasterizerCache(VideoCore::RasterizerAccelerated& rasterizer);
|
||||
RasterizerCache(VideoCore::RasterizerAccelerated& rasterizer, Driver& driver);
|
||||
~RasterizerCache();
|
||||
|
||||
/// Blit one surface's texture to another
|
||||
|
@ -5,8 +5,8 @@
|
||||
#include "common/scope_exit.h"
|
||||
#include "video_core/rasterizer_cache/utils.h"
|
||||
#include "video_core/rasterizer_cache/texture_runtime.h"
|
||||
#include "video_core/renderer_opengl/gl_driver.h"
|
||||
#include "video_core/renderer_opengl/gl_state.h"
|
||||
#include "video_core/renderer_opengl/gl_vars.h"
|
||||
|
||||
namespace OpenGL {
|
||||
|
||||
@ -27,7 +27,7 @@ GLbitfield MakeBufferMask(SurfaceType type) {
|
||||
return GL_COLOR_BUFFER_BIT;
|
||||
}
|
||||
|
||||
TextureRuntime::TextureRuntime() {
|
||||
TextureRuntime::TextureRuntime(Driver& driver) : driver(driver) {
|
||||
read_fbo.Create();
|
||||
draw_fbo.Create();
|
||||
}
|
||||
@ -225,18 +225,20 @@ const StagingBuffer& TextureRuntime::FindStaging(u32 size, bool upload) {
|
||||
|
||||
// Allocate a new buffer and map the data to the host
|
||||
void* data = nullptr;
|
||||
if (GLES) {
|
||||
if (driver.IsOpenGLES() && driver.HasExtBufferStorage()) {
|
||||
const GLbitfield storage = upload ? GL_MAP_WRITE_BIT : GL_MAP_READ_BIT | GL_CLIENT_STORAGE_BIT_EXT;
|
||||
glBufferStorageEXT(GL_PIXEL_UNPACK_BUFFER, size, nullptr, storage | GL_MAP_PERSISTENT_BIT_EXT |
|
||||
GL_MAP_COHERENT_BIT_EXT);
|
||||
data = glMapBufferRange(GL_PIXEL_UNPACK_BUFFER, 0, size, access | GL_MAP_PERSISTENT_BIT_EXT |
|
||||
GL_MAP_COHERENT_BIT_EXT);
|
||||
} else {
|
||||
} else if (driver.HasArbBufferStorage()) {
|
||||
const GLbitfield storage = upload ? GL_MAP_WRITE_BIT : GL_MAP_READ_BIT | GL_CLIENT_STORAGE_BIT;
|
||||
glBufferStorage(GL_PIXEL_UNPACK_BUFFER, size, nullptr, storage | GL_MAP_PERSISTENT_BIT |
|
||||
GL_MAP_COHERENT_BIT);
|
||||
data = glMapBufferRange(GL_PIXEL_UNPACK_BUFFER, 0, size, access | GL_MAP_PERSISTENT_BIT |
|
||||
GL_MAP_COHERENT_BIT);
|
||||
} else {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
// Insert it to the cache and return the memory
|
||||
|
@ -22,13 +22,15 @@ struct StagingBuffer {
|
||||
}
|
||||
};
|
||||
|
||||
class Driver;
|
||||
|
||||
/**
|
||||
* Provides texture manipulation functions to the rasterizer cache
|
||||
* Separating this into a class makes it easier to abstract graphics API code
|
||||
*/
|
||||
class TextureRuntime {
|
||||
public:
|
||||
TextureRuntime();
|
||||
TextureRuntime(Driver& driver);
|
||||
~TextureRuntime() = default;
|
||||
|
||||
/// Copies the GPU pixel data to the provided pixels buffer
|
||||
@ -51,6 +53,7 @@ public:
|
||||
const StagingBuffer& FindStaging(u32 size, bool upload);
|
||||
|
||||
private:
|
||||
Driver& driver;
|
||||
OGLFramebuffer read_fbo, draw_fbo;
|
||||
std::set<StagingBuffer> upload_buffers;
|
||||
std::set<StagingBuffer> download_buffers;
|
||||
|
@ -5,9 +5,6 @@
|
||||
#include <memory>
|
||||
#include "core/frontend/emu_window.h"
|
||||
#include "video_core/renderer_base.h"
|
||||
#include "video_core/renderer_opengl/gl_rasterizer.h"
|
||||
#include "video_core/swrasterizer/swrasterizer.h"
|
||||
#include "video_core/video_core.h"
|
||||
|
||||
RendererBase::RendererBase(Frontend::EmuWindow& window, Frontend::EmuWindow* secondary_window_)
|
||||
: render_window{window}, secondary_window{secondary_window_} {}
|
||||
@ -25,19 +22,6 @@ void RendererBase::UpdateCurrentFramebufferLayout(bool is_portrait_mode) {
|
||||
}
|
||||
}
|
||||
|
||||
void RendererBase::RefreshRasterizerSetting() {
|
||||
bool hw_renderer_enabled = VideoCore::g_hw_renderer_enabled;
|
||||
if (rasterizer == nullptr || opengl_rasterizer_active != hw_renderer_enabled) {
|
||||
opengl_rasterizer_active = hw_renderer_enabled;
|
||||
|
||||
if (hw_renderer_enabled) {
|
||||
rasterizer = std::make_unique<OpenGL::RasterizerOpenGL>(render_window);
|
||||
} else {
|
||||
rasterizer = std::make_unique<VideoCore::SWRasterizer>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RendererBase::Sync() {
|
||||
rasterizer->SyncEntireState();
|
||||
}
|
||||
|
@ -66,7 +66,6 @@ public:
|
||||
return render_window;
|
||||
}
|
||||
|
||||
void RefreshRasterizerSetting();
|
||||
void Sync();
|
||||
|
||||
protected:
|
||||
@ -75,7 +74,4 @@ protected:
|
||||
std::unique_ptr<VideoCore::RasterizerInterface> rasterizer;
|
||||
f32 m_current_fps = 0.0f; ///< Current framerate, should be set by the renderer
|
||||
int m_current_frame = 0; ///< Current frame, should be set by the renderer
|
||||
|
||||
private:
|
||||
bool opengl_rasterizer_active = false;
|
||||
};
|
||||
|
152
src/video_core/renderer_opengl/gl_driver.cpp
Normal file
152
src/video_core/renderer_opengl/gl_driver.cpp
Normal file
@ -0,0 +1,152 @@
|
||||
// Copyright 2022 Citra Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <glad/glad.h>
|
||||
#include "common/assert.h"
|
||||
#include "core/core.h"
|
||||
#include "video_core/renderer_opengl/gl_driver.h"
|
||||
|
||||
namespace OpenGL {
|
||||
|
||||
DECLARE_ENUM_FLAG_OPERATORS(DriverBug);
|
||||
|
||||
inline std::string_view GetSource(GLenum source) {
|
||||
#define RET(s) \
|
||||
case GL_DEBUG_SOURCE_##s: \
|
||||
return #s
|
||||
switch (source) {
|
||||
RET(API);
|
||||
RET(WINDOW_SYSTEM);
|
||||
RET(SHADER_COMPILER);
|
||||
RET(THIRD_PARTY);
|
||||
RET(APPLICATION);
|
||||
RET(OTHER);
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
#undef RET
|
||||
|
||||
return std::string_view{};
|
||||
}
|
||||
|
||||
inline std::string_view GetType(GLenum type) {
|
||||
#define RET(t) \
|
||||
case GL_DEBUG_TYPE_##t: \
|
||||
return #t
|
||||
switch (type) {
|
||||
RET(ERROR);
|
||||
RET(DEPRECATED_BEHAVIOR);
|
||||
RET(UNDEFINED_BEHAVIOR);
|
||||
RET(PORTABILITY);
|
||||
RET(PERFORMANCE);
|
||||
RET(OTHER);
|
||||
RET(MARKER);
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
#undef RET
|
||||
|
||||
return std::string_view{};
|
||||
}
|
||||
|
||||
static void APIENTRY DebugHandler(GLenum source, GLenum type, GLuint id, GLenum severity,
|
||||
GLsizei length, const GLchar* message, const void* user_param) {
|
||||
Log::Level level = Log::Level::Info;
|
||||
switch (severity) {
|
||||
case GL_DEBUG_SEVERITY_HIGH:
|
||||
level = Log::Level::Critical;
|
||||
break;
|
||||
case GL_DEBUG_SEVERITY_MEDIUM:
|
||||
level = Log::Level::Warning;
|
||||
break;
|
||||
case GL_DEBUG_SEVERITY_NOTIFICATION:
|
||||
case GL_DEBUG_SEVERITY_LOW:
|
||||
level = Log::Level::Debug;
|
||||
break;
|
||||
}
|
||||
LOG_GENERIC(Log::Class::Render_OpenGL, level, "{} {} {}: {}", GetSource(source), GetType(type),
|
||||
id, message);
|
||||
}
|
||||
|
||||
Driver::Driver(bool gles) : is_gles{gles} {
|
||||
#ifndef ANDROID
|
||||
if (!gladLoadGL()) {
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Qualcomm has some spammy info messages that are marked as errors but not important
|
||||
* https://developer.qualcomm.com/comment/11845
|
||||
*/
|
||||
glEnable(GL_DEBUG_OUTPUT);
|
||||
glDebugMessageCallback(DebugHandler, nullptr);
|
||||
#endif
|
||||
|
||||
ReportDriverInfo();
|
||||
DeduceVendor();
|
||||
CheckExtensionSupport();
|
||||
FindBugs();
|
||||
}
|
||||
|
||||
bool Driver::HasBug(DriverBug bug) const {
|
||||
return True(bugs & bug);
|
||||
}
|
||||
|
||||
void Driver::ReportDriverInfo() {
|
||||
// Report the context version and the vendor string
|
||||
gl_version = std::string_view{reinterpret_cast<const char*>(glGetString(GL_VERSION))};
|
||||
gpu_vendor = std::string_view{reinterpret_cast<const char*>(glGetString(GL_VENDOR))};
|
||||
gpu_model = std::string_view{reinterpret_cast<const char*>(glGetString(GL_RENDERER))};
|
||||
|
||||
LOG_INFO(Render_OpenGL, "GL_VERSION: {}", gl_version);
|
||||
LOG_INFO(Render_OpenGL, "GL_VENDOR: {}", gpu_vendor);
|
||||
LOG_INFO(Render_OpenGL, "GL_RENDERER: {}", gpu_model);
|
||||
|
||||
// Add the information to the telemetry system
|
||||
auto& telemetry_session = Core::System::GetInstance().TelemetrySession();
|
||||
constexpr auto user_system = Common::Telemetry::FieldType::UserSystem;
|
||||
telemetry_session.AddField(user_system, "GPU_Vendor", std::string{gpu_vendor});
|
||||
telemetry_session.AddField(user_system, "GPU_Model", std::string{gpu_model});
|
||||
telemetry_session.AddField(user_system, "GPU_OpenGL_Version", std::string{gl_version});
|
||||
}
|
||||
|
||||
void Driver::DeduceVendor() {
|
||||
if (gpu_vendor.contains("NVIDIA")) {
|
||||
vendor = Vendor::Nvidia;
|
||||
} else if (gpu_vendor.contains("ATI") ||
|
||||
gpu_vendor.contains("Advanced Micro Devices")) {
|
||||
vendor = Vendor::AMD;
|
||||
} else if (gpu_vendor.contains("Intel")) {
|
||||
vendor = Vendor::Intel;
|
||||
} else if (gpu_vendor.contains("GDI Generic")) {
|
||||
vendor = Vendor::Generic;
|
||||
}
|
||||
}
|
||||
|
||||
void Driver::CheckExtensionSupport() {
|
||||
ext_buffer_storage = GLAD_GL_EXT_buffer_storage;
|
||||
arb_buffer_storage = GLAD_GL_ARB_buffer_storage;
|
||||
ext_clip_cull_distance = GLAD_GL_EXT_clip_cull_distance;
|
||||
arb_direct_state_access = GLAD_GL_ARB_direct_state_access;
|
||||
}
|
||||
|
||||
void Driver::FindBugs() {
|
||||
#ifdef __unix__
|
||||
const bool is_linux = true;
|
||||
#else
|
||||
const bool is_linux = false;
|
||||
#endif
|
||||
|
||||
// TODO: Check if these have been fixed in the newer driver
|
||||
if (vendor == Vendor::AMD) {
|
||||
bugs |= DriverBug::ShaderStageChangeFreeze | DriverBug::VertexArrayOutOfBound;
|
||||
}
|
||||
|
||||
if (vendor == Vendor::AMD || (vendor == Vendor::Intel && !is_linux)) {
|
||||
bugs |= DriverBug::BrokenTextureView;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} // namespace OpenGL
|
86
src/video_core/renderer_opengl/gl_driver.h
Normal file
86
src/video_core/renderer_opengl/gl_driver.h
Normal file
@ -0,0 +1,86 @@
|
||||
// Copyright 2022 Citra Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
#include <string_view>
|
||||
|
||||
namespace OpenGL {
|
||||
|
||||
enum class Vendor {
|
||||
Unknown = 0,
|
||||
AMD = 1,
|
||||
Nvidia = 2,
|
||||
Intel = 3,
|
||||
Generic = 4
|
||||
};
|
||||
|
||||
enum class DriverBug {
|
||||
// AMD drivers sometimes freeze when one shader stage is changed but not the others.
|
||||
ShaderStageChangeFreeze = 1 << 0,
|
||||
// On AMD drivers there is a strange crash in indexed drawing. The crash happens when the buffer
|
||||
// read position is near the end and is an out-of-bound access to the vertex buffer. This is
|
||||
// probably a bug in the driver and is related to the usage of vec3<byte> attributes in the
|
||||
// vertex array. Doubling the allocation size for the vertex buffer seems to avoid the crash.
|
||||
VertexArrayOutOfBound = 1 << 1,
|
||||
// On AMD and Intel drivers on Windows glTextureView produces incorrect results
|
||||
BrokenTextureView = 1 << 2,
|
||||
};
|
||||
|
||||
/**
|
||||
* Utility class that loads the OpenGL function pointers and reports
|
||||
* information about the graphics device and driver used
|
||||
*/
|
||||
class Driver {
|
||||
public:
|
||||
Driver(bool gles);
|
||||
|
||||
/// Returns true of the driver has a particular bug stated in the DriverBug enum
|
||||
bool HasBug(DriverBug bug) const;
|
||||
|
||||
Vendor GetVendor() const {
|
||||
return vendor;
|
||||
}
|
||||
|
||||
bool IsOpenGLES() const {
|
||||
return is_gles;
|
||||
}
|
||||
|
||||
bool HasArbBufferStorage() const {
|
||||
return arb_buffer_storage;
|
||||
}
|
||||
|
||||
bool HasExtBufferStorage() const {
|
||||
return ext_buffer_storage;
|
||||
}
|
||||
|
||||
bool HasExtClipCullDistance() const {
|
||||
return ext_clip_cull_distance;
|
||||
}
|
||||
|
||||
bool HasArbDirectStateAccess() const {
|
||||
return arb_direct_state_access;
|
||||
}
|
||||
|
||||
private:
|
||||
void ReportDriverInfo();
|
||||
void DeduceVendor();
|
||||
void CheckExtensionSupport();
|
||||
void FindBugs();
|
||||
|
||||
private:
|
||||
Vendor vendor = Vendor::Unknown;
|
||||
DriverBug bugs{};
|
||||
|
||||
bool is_gles{};
|
||||
bool ext_buffer_storage{};
|
||||
bool arb_buffer_storage{};
|
||||
bool ext_clip_cull_distance{};
|
||||
bool arb_direct_state_access{};
|
||||
|
||||
std::string_view gl_version{};
|
||||
std::string_view gpu_vendor{};
|
||||
std::string_view gpu_model{};
|
||||
};
|
||||
|
||||
} // namespace OpenGL
|
@ -10,6 +10,7 @@
|
||||
#include "video_core/pica_state.h"
|
||||
#include "video_core/regs_framebuffer.h"
|
||||
#include "video_core/regs_rasterizer.h"
|
||||
#include "video_core/renderer_opengl/gl_driver.h"
|
||||
#include "video_core/renderer_opengl/gl_rasterizer.h"
|
||||
#include "video_core/renderer_opengl/gl_shader_gen.h"
|
||||
#include "video_core/renderer_opengl/gl_vars.h"
|
||||
@ -37,8 +38,8 @@ static bool IsVendorIntel() {
|
||||
}
|
||||
#endif
|
||||
|
||||
RasterizerOpenGL::RasterizerOpenGL(Frontend::EmuWindow& emu_window)
|
||||
: is_amd(IsVendorAmd()), vertex_buffer(GL_ARRAY_BUFFER, VERTEX_BUFFER_SIZE, is_amd),
|
||||
RasterizerOpenGL::RasterizerOpenGL(Frontend::EmuWindow& emu_window, Driver& driver)
|
||||
: driver(driver), is_amd(IsVendorAmd()), vertex_buffer(GL_ARRAY_BUFFER, VERTEX_BUFFER_SIZE, is_amd),
|
||||
uniform_buffer(GL_UNIFORM_BUFFER, UNIFORM_BUFFER_SIZE, false),
|
||||
index_buffer(GL_ELEMENT_ARRAY_BUFFER, INDEX_BUFFER_SIZE, false),
|
||||
texture_buffer(GL_TEXTURE_BUFFER, TEXTURE_BUFFER_SIZE, false),
|
||||
|
@ -20,11 +20,12 @@ class EmuWindow;
|
||||
}
|
||||
|
||||
namespace OpenGL {
|
||||
class Driver;
|
||||
class ShaderProgramManager;
|
||||
|
||||
class RasterizerOpenGL : public VideoCore::RasterizerAccelerated {
|
||||
public:
|
||||
explicit RasterizerOpenGL(Frontend::EmuWindow& emu_window);
|
||||
explicit RasterizerOpenGL(Frontend::EmuWindow& emu_window, Driver& driver);
|
||||
~RasterizerOpenGL() override;
|
||||
|
||||
void LoadDiskResources(const std::atomic_bool& stop_loading,
|
||||
@ -247,8 +248,8 @@ private:
|
||||
/// Setup geometry shader for AccelerateDrawBatch
|
||||
bool SetupGeometryShader();
|
||||
|
||||
bool is_amd;
|
||||
|
||||
private:
|
||||
Driver& driver;
|
||||
OpenGLState state;
|
||||
GLuint default_texture;
|
||||
|
||||
@ -256,6 +257,7 @@ private:
|
||||
|
||||
std::vector<HardwareVertex> vertex_batch;
|
||||
|
||||
bool is_amd;
|
||||
bool shader_dirty = true;
|
||||
|
||||
struct {
|
||||
|
@ -16,6 +16,7 @@
|
||||
#include "core/tracer/recorder.h"
|
||||
#include "video_core/debug_utils/debug_utils.h"
|
||||
#include "video_core/rasterizer_interface.h"
|
||||
#include "video_core/renderer_opengl/gl_rasterizer.h"
|
||||
#include "video_core/renderer_opengl/gl_shader_util.h"
|
||||
#include "video_core/renderer_opengl/gl_state.h"
|
||||
#include "video_core/renderer_opengl/gl_vars.h"
|
||||
@ -353,7 +354,7 @@ static std::array<GLfloat, 3 * 2> MakeOrthographicMatrix(const float width, cons
|
||||
}
|
||||
|
||||
RendererOpenGL::RendererOpenGL(Frontend::EmuWindow& window, Frontend::EmuWindow* secondary_window)
|
||||
: RendererBase{window, secondary_window},
|
||||
: RendererBase{window, secondary_window}, driver{Settings::values.graphics_api == Settings::GraphicsAPI::OpenGLES},
|
||||
frame_dumper(Core::System::GetInstance().VideoDumper(), window) {
|
||||
window.mailbox = std::make_unique<OGLTextureMailbox>();
|
||||
if (secondary_window) {
|
||||
@ -364,6 +365,27 @@ RendererOpenGL::RendererOpenGL(Frontend::EmuWindow& window, Frontend::EmuWindow*
|
||||
|
||||
RendererOpenGL::~RendererOpenGL() = default;
|
||||
|
||||
/// Initialize the renderer
|
||||
VideoCore::ResultStatus RendererOpenGL::Init() {
|
||||
const Vendor vendor = driver.GetVendor();
|
||||
switch (vendor) {
|
||||
case Vendor::Generic:
|
||||
return VideoCore::ResultStatus::ErrorGenericDrivers;
|
||||
case Vendor::Unknown:
|
||||
return VideoCore::ResultStatus::ErrorRendererInit;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
InitOpenGLObjects();
|
||||
rasterizer = std::make_unique<RasterizerOpenGL>(render_window, driver);
|
||||
|
||||
return VideoCore::ResultStatus::Success;
|
||||
}
|
||||
|
||||
/// Shutdown the renderer
|
||||
void RendererOpenGL::ShutDown() {}
|
||||
|
||||
MICROPROFILE_DEFINE(OpenGL_RenderFrame, "OpenGL", "Render Frame", MP_RGB(128, 128, 64));
|
||||
MICROPROFILE_DEFINE(OpenGL_WaitPresent, "OpenGL", "Wait For Present", MP_RGB(128, 128, 128));
|
||||
|
||||
@ -398,16 +420,15 @@ void RendererOpenGL::SwapBuffers() {
|
||||
|
||||
m_current_frame++;
|
||||
|
||||
Core::System::GetInstance().perf_stats->EndSystemFrame();
|
||||
Core::System& system = Core::System::GetInstance();
|
||||
system.perf_stats->EndSystemFrame();
|
||||
|
||||
render_window.PollEvents();
|
||||
|
||||
Core::System::GetInstance().frame_limiter.DoFrameLimiting(
|
||||
Core::System::GetInstance().CoreTiming().GetGlobalTimeUs());
|
||||
Core::System::GetInstance().perf_stats->BeginSystemFrame();
|
||||
system.frame_limiter.DoFrameLimiting(system.CoreTiming().GetGlobalTimeUs());
|
||||
system.perf_stats->BeginSystemFrame();
|
||||
|
||||
prev_state.Apply();
|
||||
RefreshRasterizerSetting();
|
||||
|
||||
if (Pica::g_debug_context && Pica::g_debug_context->recorder) {
|
||||
Pica::g_debug_context->recorder->FrameFinished();
|
||||
@ -1193,111 +1214,4 @@ void RendererOpenGL::CleanupVideoDumping() {
|
||||
mailbox->free_cv.notify_one();
|
||||
}
|
||||
|
||||
static const char* GetSource(GLenum source) {
|
||||
#define RET(s) \
|
||||
case GL_DEBUG_SOURCE_##s: \
|
||||
return #s
|
||||
switch (source) {
|
||||
RET(API);
|
||||
RET(WINDOW_SYSTEM);
|
||||
RET(SHADER_COMPILER);
|
||||
RET(THIRD_PARTY);
|
||||
RET(APPLICATION);
|
||||
RET(OTHER);
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
#undef RET
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
static const char* GetType(GLenum type) {
|
||||
#define RET(t) \
|
||||
case GL_DEBUG_TYPE_##t: \
|
||||
return #t
|
||||
switch (type) {
|
||||
RET(ERROR);
|
||||
RET(DEPRECATED_BEHAVIOR);
|
||||
RET(UNDEFINED_BEHAVIOR);
|
||||
RET(PORTABILITY);
|
||||
RET(PERFORMANCE);
|
||||
RET(OTHER);
|
||||
RET(MARKER);
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
#undef RET
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
static void APIENTRY DebugHandler(GLenum source, GLenum type, GLuint id, GLenum severity,
|
||||
GLsizei length, const GLchar* message, const void* user_param) {
|
||||
Log::Level level;
|
||||
switch (severity) {
|
||||
case GL_DEBUG_SEVERITY_HIGH:
|
||||
level = Log::Level::Critical;
|
||||
break;
|
||||
case GL_DEBUG_SEVERITY_MEDIUM:
|
||||
level = Log::Level::Warning;
|
||||
break;
|
||||
case GL_DEBUG_SEVERITY_NOTIFICATION:
|
||||
case GL_DEBUG_SEVERITY_LOW:
|
||||
level = Log::Level::Debug;
|
||||
break;
|
||||
}
|
||||
LOG_GENERIC(Log::Class::Render_OpenGL, level, "{} {} {}: {}", GetSource(source), GetType(type),
|
||||
id, message);
|
||||
}
|
||||
|
||||
/// Initialize the renderer
|
||||
VideoCore::ResultStatus RendererOpenGL::Init() {
|
||||
#ifndef ANDROID
|
||||
if (!gladLoadGL()) {
|
||||
return VideoCore::ResultStatus::ErrorRendererInit;
|
||||
}
|
||||
|
||||
// Qualcomm has some spammy info messages that are marked as errors but not important
|
||||
// https://developer.qualcomm.com/comment/11845
|
||||
glEnable(GL_DEBUG_OUTPUT);
|
||||
glDebugMessageCallback(DebugHandler, nullptr);
|
||||
#endif
|
||||
|
||||
const std::string_view gl_version{reinterpret_cast<char const*>(glGetString(GL_VERSION))};
|
||||
const std::string_view gpu_vendor{reinterpret_cast<char const*>(glGetString(GL_VENDOR))};
|
||||
const std::string_view gpu_model{reinterpret_cast<char const*>(glGetString(GL_RENDERER))};
|
||||
|
||||
LOG_INFO(Render_OpenGL, "GL_VERSION: {}", gl_version);
|
||||
LOG_INFO(Render_OpenGL, "GL_VENDOR: {}", gpu_vendor);
|
||||
LOG_INFO(Render_OpenGL, "GL_RENDERER: {}", gpu_model);
|
||||
|
||||
auto& telemetry_session = Core::System::GetInstance().TelemetrySession();
|
||||
constexpr auto user_system = Common::Telemetry::FieldType::UserSystem;
|
||||
telemetry_session.AddField(user_system, "GPU_Vendor", std::string{gpu_vendor});
|
||||
telemetry_session.AddField(user_system, "GPU_Model", std::string{gpu_model});
|
||||
telemetry_session.AddField(user_system, "GPU_OpenGL_Version", std::string{gl_version});
|
||||
|
||||
if (gpu_vendor == "GDI Generic") {
|
||||
return VideoCore::ResultStatus::ErrorGenericDrivers;
|
||||
}
|
||||
|
||||
if (!(GLAD_GL_VERSION_4_4 || GLAD_GL_ES_VERSION_3_2)) {
|
||||
return VideoCore::ResultStatus::ErrorRendererInit;
|
||||
}
|
||||
|
||||
// We require glBufferStorage(EXT)
|
||||
if (GLES && !GLAD_GL_EXT_buffer_storage) {
|
||||
return VideoCore::ResultStatus::ErrorRendererInit;
|
||||
}
|
||||
|
||||
InitOpenGLObjects();
|
||||
RefreshRasterizerSetting();
|
||||
|
||||
return VideoCore::ResultStatus::Success;
|
||||
}
|
||||
|
||||
/// Shutdown the renderer
|
||||
void RendererOpenGL::ShutDown() {}
|
||||
|
||||
} // namespace OpenGL
|
||||
|
@ -7,6 +7,7 @@
|
||||
#include <array>
|
||||
#include "core/hw/gpu.h"
|
||||
#include "video_core/renderer_base.h"
|
||||
#include "video_core/renderer_opengl/gl_driver.h"
|
||||
#include "video_core/renderer_opengl/frame_dumper_opengl.h"
|
||||
#include "video_core/renderer_opengl/gl_resource_manager.h"
|
||||
#include "video_core/renderer_opengl/gl_state.h"
|
||||
@ -104,6 +105,8 @@ private:
|
||||
// Fills active OpenGL texture with the given RGB color.
|
||||
void LoadColorToActiveGLTexture(u8 color_r, u8 color_g, u8 color_b, const TextureInfo& texture);
|
||||
|
||||
private:
|
||||
Driver driver;
|
||||
OpenGLState state;
|
||||
|
||||
// OpenGL object IDs
|
||||
|
Reference in New Issue
Block a user