renderer_opengl: Move some logic to an anonymous namespace
This commit is contained in:
parent
311d2fc768
commit
53d673a7d3
|
@ -28,6 +28,76 @@
|
||||||
|
|
||||||
namespace OpenGL {
|
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;
|
||||||
|
|
||||||
|
struct Frame {
|
||||||
|
u32 width{}; /// Width of the frame (to detect resize)
|
||||||
|
u32 height{}; /// Height of the frame
|
||||||
|
bool color_reloaded{}; /// Texture attachment was recreated (ie: resized)
|
||||||
|
OpenGL::OGLRenderbuffer color{}; /// Buffer shared between the render/present FBO
|
||||||
|
OpenGL::OGLFramebuffer render{}; /// FBO created on the render thread
|
||||||
|
OpenGL::OGLFramebuffer present{}; /// FBO created on the present thread
|
||||||
|
GLsync render_fence{}; /// Fence created on the render thread
|
||||||
|
GLsync present_fence{}; /// Fence created on the presentation thread
|
||||||
|
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
|
/// Returns true if any debug tool is attached
|
||||||
bool HasDebugTool() {
|
bool HasDebugTool() {
|
||||||
const bool nsight = std::getenv("NVTX_INJECTION64_PATH") || std::getenv("NSIGHT_LAUNCHED");
|
const bool nsight = std::getenv("NVTX_INJECTION64_PATH") || std::getenv("NSIGHT_LAUNCHED");
|
||||||
|
@ -46,21 +116,88 @@ bool HasDebugTool() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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.
|
* Defines a 1:1 pixel ortographic projection matrix with (0,0) on the top-left
|
||||||
constexpr std::size_t SWAP_CHAIN_SIZE = 3;
|
* 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
|
||||||
|
|
||||||
struct Frame {
|
// clang-format off
|
||||||
u32 width{}; /// Width of the frame (to detect resize)
|
matrix[0] = 2.f / width; matrix[2] = 0.f; matrix[4] = -1.f;
|
||||||
u32 height{}; /// Height of the frame
|
matrix[1] = 0.f; matrix[3] = -2.f / height; matrix[5] = 1.f;
|
||||||
bool color_reloaded{}; /// Texture attachment was recreated (ie: resized)
|
// Last matrix row is implicitly assumed to be [0, 0, 1].
|
||||||
OpenGL::OGLRenderbuffer color{}; /// Buffer shared between the render/present FBO
|
// clang-format on
|
||||||
OpenGL::OGLFramebuffer render{}; /// FBO created on the render thread
|
|
||||||
OpenGL::OGLFramebuffer present{}; /// FBO created on the present thread
|
return matrix;
|
||||||
GLsync render_fence{}; /// Fence created on the render thread
|
}
|
||||||
GLsync present_fence{}; /// Fence created on the presentation thread
|
|
||||||
bool is_srgb{}; /// Framebuffer is sRGB or RGB
|
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,
|
* For smooth Vsync rendering, we want to always present the latest frame that the core generates,
|
||||||
|
@ -209,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)
|
RendererOpenGL::RendererOpenGL(Core::Frontend::EmuWindow& emu_window, Core::System& system)
|
||||||
: VideoCore::RendererBase{emu_window}, emu_window{emu_window}, system{system},
|
: VideoCore::RendererBase{emu_window}, emu_window{emu_window}, system{system},
|
||||||
frame_mailbox{std::make_unique<FrameMailbox>()} {}
|
frame_mailbox{std::make_unique<FrameMailbox>()} {}
|
||||||
|
|
Reference in New Issue