diff options
-rw-r--r-- | src/video_core/renderer_opengl/gl_device.cpp | 1 | ||||
-rw-r--r-- | src/video_core/renderer_opengl/gl_device.h | 5 | ||||
-rw-r--r-- | src/video_core/renderer_opengl/renderer_opengl.cpp | 297 |
3 files changed, 159 insertions, 144 deletions
diff --git a/src/video_core/renderer_opengl/gl_device.cpp b/src/video_core/renderer_opengl/gl_device.cpp index e824e216d..1a2e2a9f7 100644 --- a/src/video_core/renderer_opengl/gl_device.cpp +++ b/src/video_core/renderer_opengl/gl_device.cpp @@ -157,7 +157,6 @@ Device::Device() : base_bindings{BuildBaseBindings()} { has_precise_bug = TestPreciseBug(); has_broken_compute = is_intel_proprietary; has_fast_buffer_sub_data = is_nvidia; - has_debug_tool = HasExtension(extensions, "GL_EXT_debug_tool"); LOG_INFO(Render_OpenGL, "Renderer_VariableAOFFI: {}", has_variable_aoffi); LOG_INFO(Render_OpenGL, "Renderer_ComponentIndexingBug: {}", has_component_indexing_bug); diff --git a/src/video_core/renderer_opengl/gl_device.h b/src/video_core/renderer_opengl/gl_device.h index 7aaa3a077..d73b099d0 100644 --- a/src/video_core/renderer_opengl/gl_device.h +++ b/src/video_core/renderer_opengl/gl_device.h @@ -84,10 +84,6 @@ public: return has_fast_buffer_sub_data; } - bool HasDebugTool() const { - return has_debug_tool; - } - private: static bool TestVariableAoffi(); static bool TestPreciseBug(); @@ -106,7 +102,6 @@ private: bool has_precise_bug{}; bool has_broken_compute{}; bool has_fast_buffer_sub_data{}; - bool has_debug_tool{}; }; } // namespace OpenGL diff --git a/src/video_core/renderer_opengl/renderer_opengl.cpp b/src/video_core/renderer_opengl/renderer_opengl.cpp index c91658cd1..fca5e3ec0 100644 --- a/src/video_core/renderer_opengl/renderer_opengl.cpp +++ b/src/video_core/renderer_opengl/renderer_opengl.cpp @@ -5,8 +5,11 @@ #include <algorithm> #include <cstddef> #include <cstdlib> +#include <cstring> #include <memory> + #include <glad/glad.h> + #include "common/assert.h" #include "common/logging/log.h" #include "common/microprofile.h" @@ -25,6 +28,8 @@ namespace OpenGL { +namespace { + // If the size of this is too small, it ends up creating a soft cap on FPS as the renderer will have // to wait on available presentation frames. constexpr std::size_t SWAP_CHAIN_SIZE = 3; @@ -41,6 +46,159 @@ struct Frame { bool is_srgb{}; /// Framebuffer is sRGB or RGB }; +constexpr char VERTEX_SHADER[] = R"( +#version 430 core + +out gl_PerVertex { + vec4 gl_Position; +}; + +layout (location = 0) in vec2 vert_position; +layout (location = 1) in vec2 vert_tex_coord; +layout (location = 0) out vec2 frag_tex_coord; + +// This is a truncated 3x3 matrix for 2D transformations: +// The upper-left 2x2 submatrix performs scaling/rotation/mirroring. +// The third column performs translation. +// The third row could be used for projection, which we don't need in 2D. It hence is assumed to +// implicitly be [0, 0, 1] +layout (location = 0) uniform mat3x2 modelview_matrix; + +void main() { + // Multiply input position by the rotscale part of the matrix and then manually translate by + // the last column. This is equivalent to using a full 3x3 matrix and expanding the vector + // to `vec3(vert_position.xy, 1.0)` + gl_Position = vec4(mat2(modelview_matrix) * vert_position + modelview_matrix[2], 0.0, 1.0); + frag_tex_coord = vert_tex_coord; +} +)"; + +constexpr char FRAGMENT_SHADER[] = R"( +#version 430 core + +layout (location = 0) in vec2 frag_tex_coord; +layout (location = 0) out vec4 color; + +layout (binding = 0) uniform sampler2D color_texture; + +void main() { + color = vec4(texture(color_texture, frag_tex_coord).rgb, 1.0f); +} +)"; + +constexpr GLint PositionLocation = 0; +constexpr GLint TexCoordLocation = 1; +constexpr GLint ModelViewMatrixLocation = 0; + +struct ScreenRectVertex { + constexpr ScreenRectVertex(u32 x, u32 y, GLfloat u, GLfloat v) + : position{{static_cast<GLfloat>(x), static_cast<GLfloat>(y)}}, tex_coord{{u, v}} {} + + std::array<GLfloat, 2> position; + std::array<GLfloat, 2> tex_coord; +}; + +/// Returns true if any debug tool is attached +bool HasDebugTool() { + const bool nsight = std::getenv("NVTX_INJECTION64_PATH") || std::getenv("NSIGHT_LAUNCHED"); + if (nsight) { + return true; + } + + GLint num_extensions; + glGetIntegerv(GL_NUM_EXTENSIONS, &num_extensions); + for (GLuint index = 0; index < static_cast<GLuint>(num_extensions); ++index) { + const auto name = reinterpret_cast<const char*>(glGetStringi(GL_EXTENSIONS, index)); + if (!std::strcmp(name, "GL_EXT_debug_tool")) { + return true; + } + } + return false; +} + +/** + * Defines a 1:1 pixel ortographic projection matrix with (0,0) on the top-left + * corner and (width, height) on the lower-bottom. + * + * The projection part of the matrix is trivial, hence these operations are represented + * by a 3x2 matrix. + */ +std::array<GLfloat, 3 * 2> MakeOrthographicMatrix(float width, float height) { + std::array<GLfloat, 3 * 2> matrix; // Laid out in column-major order + + // clang-format off + matrix[0] = 2.f / width; matrix[2] = 0.f; matrix[4] = -1.f; + matrix[1] = 0.f; matrix[3] = -2.f / height; matrix[5] = 1.f; + // Last matrix row is implicitly assumed to be [0, 0, 1]. + // clang-format on + + return matrix; +} + +const char* GetSource(GLenum source) { + switch (source) { + case GL_DEBUG_SOURCE_API: + return "API"; + case GL_DEBUG_SOURCE_WINDOW_SYSTEM: + return "WINDOW_SYSTEM"; + case GL_DEBUG_SOURCE_SHADER_COMPILER: + return "SHADER_COMPILER"; + case GL_DEBUG_SOURCE_THIRD_PARTY: + return "THIRD_PARTY"; + case GL_DEBUG_SOURCE_APPLICATION: + return "APPLICATION"; + case GL_DEBUG_SOURCE_OTHER: + return "OTHER"; + default: + UNREACHABLE(); + return "Unknown source"; + } +} + +const char* GetType(GLenum type) { + switch (type) { + case GL_DEBUG_TYPE_ERROR: + return "ERROR"; + case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR: + return "DEPRECATED_BEHAVIOR"; + case GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR: + return "UNDEFINED_BEHAVIOR"; + case GL_DEBUG_TYPE_PORTABILITY: + return "PORTABILITY"; + case GL_DEBUG_TYPE_PERFORMANCE: + return "PERFORMANCE"; + case GL_DEBUG_TYPE_OTHER: + return "OTHER"; + case GL_DEBUG_TYPE_MARKER: + return "MARKER"; + default: + UNREACHABLE(); + return "Unknown type"; + } +} + +void APIENTRY DebugHandler(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, + const GLchar* message, const void* user_param) { + const char format[] = "{} {} {}: {}"; + const char* const str_source = GetSource(source); + const char* const str_type = GetType(type); + + switch (severity) { + case GL_DEBUG_SEVERITY_HIGH: + LOG_CRITICAL(Render_OpenGL, format, str_source, str_type, id, message); + break; + case GL_DEBUG_SEVERITY_MEDIUM: + LOG_WARNING(Render_OpenGL, format, str_source, str_type, id, message); + break; + case GL_DEBUG_SEVERITY_NOTIFICATION: + case GL_DEBUG_SEVERITY_LOW: + LOG_DEBUG(Render_OpenGL, format, str_source, str_type, id, message); + break; + } +} + +} // Anonymous namespace + /** * For smooth Vsync rendering, we want to always present the latest frame that the core generates, * but also make sure that rendering happens at the pace that the frontend dictates. This is a @@ -56,7 +214,7 @@ public: std::deque<Frame*> present_queue; Frame* previous_frame{}; - FrameMailbox() : has_debug_tool{Device().HasDebugTool()} { + FrameMailbox() : has_debug_tool{HasDebugTool()} { for (auto& frame : swap_chain) { free_queue.push(&frame); } @@ -188,143 +346,6 @@ private: } }; -namespace { - -constexpr char VERTEX_SHADER[] = R"( -#version 430 core - -out gl_PerVertex { - vec4 gl_Position; -}; - -layout (location = 0) in vec2 vert_position; -layout (location = 1) in vec2 vert_tex_coord; -layout (location = 0) out vec2 frag_tex_coord; - -// This is a truncated 3x3 matrix for 2D transformations: -// The upper-left 2x2 submatrix performs scaling/rotation/mirroring. -// The third column performs translation. -// The third row could be used for projection, which we don't need in 2D. It hence is assumed to -// implicitly be [0, 0, 1] -layout (location = 0) uniform mat3x2 modelview_matrix; - -void main() { - // Multiply input position by the rotscale part of the matrix and then manually translate by - // the last column. This is equivalent to using a full 3x3 matrix and expanding the vector - // to `vec3(vert_position.xy, 1.0)` - gl_Position = vec4(mat2(modelview_matrix) * vert_position + modelview_matrix[2], 0.0, 1.0); - frag_tex_coord = vert_tex_coord; -} -)"; - -constexpr char FRAGMENT_SHADER[] = R"( -#version 430 core - -layout (location = 0) in vec2 frag_tex_coord; -layout (location = 0) out vec4 color; - -layout (binding = 0) uniform sampler2D color_texture; - -void main() { - color = vec4(texture(color_texture, frag_tex_coord).rgb, 1.0f); -} -)"; - -constexpr GLint PositionLocation = 0; -constexpr GLint TexCoordLocation = 1; -constexpr GLint ModelViewMatrixLocation = 0; - -struct ScreenRectVertex { - constexpr ScreenRectVertex(u32 x, u32 y, GLfloat u, GLfloat v) - : position{{static_cast<GLfloat>(x), static_cast<GLfloat>(y)}}, tex_coord{{u, v}} {} - - std::array<GLfloat, 2> position; - std::array<GLfloat, 2> tex_coord; -}; - -/** - * Defines a 1:1 pixel ortographic projection matrix with (0,0) on the top-left - * corner and (width, height) on the lower-bottom. - * - * The projection part of the matrix is trivial, hence these operations are represented - * by a 3x2 matrix. - */ -std::array<GLfloat, 3 * 2> MakeOrthographicMatrix(float width, float height) { - std::array<GLfloat, 3 * 2> matrix; // Laid out in column-major order - - // clang-format off - matrix[0] = 2.f / width; matrix[2] = 0.f; matrix[4] = -1.f; - matrix[1] = 0.f; matrix[3] = -2.f / height; matrix[5] = 1.f; - // Last matrix row is implicitly assumed to be [0, 0, 1]. - // clang-format on - - return matrix; -} - -const char* GetSource(GLenum source) { - switch (source) { - case GL_DEBUG_SOURCE_API: - return "API"; - case GL_DEBUG_SOURCE_WINDOW_SYSTEM: - return "WINDOW_SYSTEM"; - case GL_DEBUG_SOURCE_SHADER_COMPILER: - return "SHADER_COMPILER"; - case GL_DEBUG_SOURCE_THIRD_PARTY: - return "THIRD_PARTY"; - case GL_DEBUG_SOURCE_APPLICATION: - return "APPLICATION"; - case GL_DEBUG_SOURCE_OTHER: - return "OTHER"; - default: - UNREACHABLE(); - return "Unknown source"; - } -} - -const char* GetType(GLenum type) { - switch (type) { - case GL_DEBUG_TYPE_ERROR: - return "ERROR"; - case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR: - return "DEPRECATED_BEHAVIOR"; - case GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR: - return "UNDEFINED_BEHAVIOR"; - case GL_DEBUG_TYPE_PORTABILITY: - return "PORTABILITY"; - case GL_DEBUG_TYPE_PERFORMANCE: - return "PERFORMANCE"; - case GL_DEBUG_TYPE_OTHER: - return "OTHER"; - case GL_DEBUG_TYPE_MARKER: - return "MARKER"; - default: - UNREACHABLE(); - return "Unknown type"; - } -} - -void APIENTRY DebugHandler(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, - const GLchar* message, const void* user_param) { - const char format[] = "{} {} {}: {}"; - const char* const str_source = GetSource(source); - const char* const str_type = GetType(type); - - switch (severity) { - case GL_DEBUG_SEVERITY_HIGH: - LOG_CRITICAL(Render_OpenGL, format, str_source, str_type, id, message); - break; - case GL_DEBUG_SEVERITY_MEDIUM: - LOG_WARNING(Render_OpenGL, format, str_source, str_type, id, message); - break; - case GL_DEBUG_SEVERITY_NOTIFICATION: - case GL_DEBUG_SEVERITY_LOW: - LOG_DEBUG(Render_OpenGL, format, str_source, str_type, id, message); - break; - } -} - -} // Anonymous namespace - RendererOpenGL::RendererOpenGL(Core::Frontend::EmuWindow& emu_window, Core::System& system) : VideoCore::RendererBase{emu_window}, emu_window{emu_window}, system{system}, frame_mailbox{std::make_unique<FrameMailbox>()} {} |