split game framebuffers to allow custom resolutions/shaders (#1641)

* split rendering framebuffer

* fix blackout

* unhardcode c++ stuff

* optimization

* implement goal side of all this

* fix msaa

* sprite distort fixes

* fix resolution menu options

* save & load msaa

* linear filtering on the game screen

* fix bad texture units

* fun!

* unused

* make screenshot button capture the framebuffer and not the window buffer

* panik

* screenshot settings

* fix black screen on first frame of new framebuffer

* default fullscreen resolution to the screen size

* hide funny resolutions in windowed since it makes no sense
This commit is contained in:
ManDude
2022-07-15 02:37:03 +01:00
committed by GitHub
parent 8c940ea529
commit 20ab48796d
21 changed files with 386 additions and 116 deletions
+9
View File
@@ -274,6 +274,15 @@ void set_window_lock(bool lock) {
}
}
void set_game_resolution(int w, int h) {
g_global_settings.game_res_w = w;
g_global_settings.game_res_h = h;
}
void set_msaa(int samples) {
g_global_settings.msaa_samples = samples;
}
void input_mode_set(u32 enable) {
if (enable == s7.offset + jak1_symbols::FIX_SYM_TRUE) { // #t
Pad::g_input_mode_mapping = g_settings.pad_mapping_info;
+9
View File
@@ -76,6 +76,13 @@ struct GfxGlobalSettings {
int lbox_w;
int lbox_h;
// actual game resolution
int game_res_w = 640;
int game_res_h = 480;
// multi-sampled anti-aliasing sample count. 1 = disabled.
int msaa_samples = 4;
// current renderer
const GfxRendererModule* renderer;
@@ -137,6 +144,8 @@ void set_vsync(bool vsync);
void set_letterbox(int w, int h);
void set_fullscreen(GfxDisplayMode mode, int screen);
void set_window_lock(bool lock);
void set_game_resolution(int w, int h);
void set_msaa(int samples);
void input_mode_set(u32 enable);
void input_mode_save();
s64 get_mapped_button(s64 pad, s64 button);
@@ -16,6 +16,41 @@ struct LevelVis {
u8 data[2048];
};
struct FboState {
GLuint fbo = -1;
GLuint tex = -1;
GLuint fbo2 = -1;
GLuint tex2 = -1;
GLuint zbuf = -1;
GLenum render_targets[1] = {GL_COLOR_ATTACHMENT0};
int width = 640;
int height = 480;
int msaa = 4;
void delete_objects() {
if (fbo != -1) {
glDeleteFramebuffers(1, &fbo);
fbo = -1;
}
if (tex != -1) {
glDeleteTextures(1, &tex);
tex = -1;
}
if (fbo2 != -1) {
glDeleteFramebuffers(1, &fbo2);
fbo2 = -1;
}
if (tex2 != -1) {
glDeleteTextures(1, &tex2);
tex2 = -1;
}
if (zbuf != -1) {
glDeleteRenderbuffers(1, &zbuf);
zbuf = -1;
}
}
};
class EyeRenderer;
/*!
* The main renderer will contain a single SharedRenderState that's passed to all bucket renderers.
@@ -61,6 +96,8 @@ struct SharedRenderState {
int window_height_px;
int window_offset_x_px;
int window_offset_y_px;
FboState fbo_state;
};
/*!
+135 -25
View File
@@ -274,8 +274,7 @@ void OpenGLRenderer::init_bucket_renderers() {
init_bucket_renderer<DirectRenderer>("debug", BucketCategory::OTHER, BucketId::DEBUG, 0x20000);
init_bucket_renderer<DirectRenderer>("debug-no-zbuf", BucketCategory::OTHER,
BucketId::DEBUG_NO_ZBUF, 0x8000);
init_bucket_renderer<DirectRenderer>("subtitle", BucketCategory::OTHER, BucketId::SUBTITLE,
0x2000);
init_bucket_renderer<DirectRenderer>("subtitle", BucketCategory::OTHER, BucketId::SUBTITLE, 2000);
// for now, for any unset renderers, just set them to an EmptyBucketRenderer.
for (size_t i = 0; i < m_bucket_renderers.size(); i++) {
@@ -303,8 +302,7 @@ void OpenGLRenderer::render(DmaFollower dma, const RenderOptions& settings) {
{
auto prof = m_profiler.root()->make_scoped_child("frame-setup");
setup_frame(settings.window_width_px, settings.window_height_px, settings.lbox_width_px,
settings.lbox_height_px);
setup_frame(settings);
}
{
@@ -364,8 +362,8 @@ void OpenGLRenderer::render(DmaFollower dma, const RenderOptions& settings) {
}
if (settings.save_screenshot) {
finish_screenshot(settings.screenshot_path, settings.window_width_px, settings.window_height_px,
settings.lbox_width_px, settings.lbox_height_px);
finish_screenshot(settings.screenshot_path, m_render_state.fbo_state.width,
m_render_state.fbo_state.height, 0, 0, m_render_state.fbo_state.fbo2);
}
}
@@ -404,21 +402,104 @@ void OpenGLRenderer::draw_renderer_selection_window() {
/*!
* Pre-render frame setup.
*/
void OpenGLRenderer::setup_frame(int window_width_px,
int window_height_px,
int offset_x,
int offset_y) {
glViewport(offset_x, offset_y, window_width_px, window_height_px);
void OpenGLRenderer::setup_frame(const RenderOptions& settings) {
auto& fbo_state = m_render_state.fbo_state;
// restart the buffers if settings changed.
if (settings.game_res_w != fbo_state.width || settings.game_res_h != fbo_state.height ||
settings.msaa_samples != fbo_state.msaa) {
fbo_state.delete_objects();
}
if (fbo_state.fbo == -1 || fbo_state.fbo2 == -1 || fbo_state.tex == -1 || fbo_state.tex2 == -1 ||
fbo_state.zbuf == -1) {
fbo_state.width = settings.game_res_w;
fbo_state.height = settings.game_res_h;
fbo_state.msaa = settings.msaa_samples;
bool bad = false;
// make framebuffer object
if (fbo_state.fbo == -1) {
glGenFramebuffers(1, &fbo_state.fbo);
}
glBindFramebuffer(GL_FRAMEBUFFER, fbo_state.fbo);
// make texture that will hold the colors of the framebuffer
if (fbo_state.tex == -1) {
glGenTextures(1, &fbo_state.tex);
}
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, fbo_state.tex);
glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, fbo_state.msaa, GL_RGBA8, fbo_state.width,
fbo_state.height, GL_TRUE);
// make depth and stencil buffers that will hold the... depth and stencil buffers
if (fbo_state.zbuf == -1) {
glGenRenderbuffers(1, &fbo_state.zbuf);
}
glBindRenderbuffer(GL_RENDERBUFFER, fbo_state.zbuf);
glRenderbufferStorageMultisample(GL_RENDERBUFFER, fbo_state.msaa, GL_DEPTH24_STENCIL8,
fbo_state.width, fbo_state.height);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER,
fbo_state.zbuf);
// attach texture to framebuffer as target for colors
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D_MULTISAMPLE,
fbo_state.tex, 0);
glDrawBuffers(1, fbo_state.render_targets);
bad |= glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE;
// make framebuffer object
if (fbo_state.fbo2 == -1) {
glGenFramebuffers(1, &fbo_state.fbo2);
}
glBindFramebuffer(GL_FRAMEBUFFER, fbo_state.fbo2);
// make texture that will hold the msaa resolved color buffer
if (fbo_state.tex2 == -1) {
glGenTextures(1, &fbo_state.tex2);
}
glActiveTexture(GL_TEXTURE30);
glBindTexture(GL_TEXTURE_2D, fbo_state.tex2);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, fbo_state.width, fbo_state.height, 0, GL_RGBA,
GL_UNSIGNED_BYTE, nullptr);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
// attach texture to framebuffer as target for colors
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, fbo_state.tex2, 0);
glDrawBuffers(1, fbo_state.render_targets);
bad |= glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE;
if (!bad) {
glBindFramebuffer(GL_FRAMEBUFFER, fbo_state.fbo);
} else {
lg::error("bad framebuffer setup. fbo: {}, tex: {}, zbuf: {}, fbo2: {}, tex2: {}",
fbo_state.fbo, fbo_state.tex, fbo_state.zbuf, fbo_state.fbo2, fbo_state.tex2);
fbo_state.delete_objects();
}
} else {
// we have the objects. bind framebuffer.
glBindFramebuffer(GL_FRAMEBUFFER, fbo_state.fbo);
}
glViewport(0, 0, settings.game_res_w, settings.game_res_h);
glClearColor(0.0, 0.0, 0.0, 0.0);
glClearDepth(0.0);
glDepthMask(GL_TRUE);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
glDisable(GL_BLEND);
m_render_state.window_width_px = window_width_px;
m_render_state.window_height_px = window_height_px;
m_render_state.window_offset_x_px = offset_x;
m_render_state.window_offset_y_px = offset_y;
m_render_state.window_width_px = settings.window_width_px;
m_render_state.window_height_px = settings.window_height_px;
m_render_state.window_offset_x_px = settings.lbox_width_px;
m_render_state.window_offset_y_px = settings.lbox_height_px;
}
/*!
@@ -488,10 +569,14 @@ void OpenGLRenderer::finish_screenshot(const std::string& output_name,
int width,
int height,
int x,
int y) {
int y,
GLuint fbo) {
std::vector<u32> buffer(width * height);
glPixelStorei(GL_PACK_ALIGNMENT, 1);
glReadBuffer(GL_BACK);
GLint oldbuf;
glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING, &oldbuf);
glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo);
glReadBuffer(GL_COLOR_ATTACHMENT0);
glReadPixels(x, y, width, height, GL_RGBA, GL_UNSIGNED_BYTE, buffer.data());
// flip upside down in place
for (int h = 0; h < height / 2; h++) {
@@ -505,19 +590,44 @@ void OpenGLRenderer::finish_screenshot(const std::string& output_name,
px |= 0xff000000;
}
file_util::write_rgba_png(output_name, buffer.data(), width, height);
glBindFramebuffer(GL_READ_FRAMEBUFFER, oldbuf);
}
void OpenGLRenderer::do_pcrtc_effects(float alp,
SharedRenderState* render_state,
ScopedProfilerNode& prof) {
if (alp < 1) {
glDisable(GL_DEPTH_TEST);
glEnable(GL_BLEND);
glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ZERO);
glBlendEquation(GL_FUNC_ADD);
int w = render_state->fbo_state.width;
int h = render_state->fbo_state.height;
glBindFramebuffer(GL_READ_FRAMEBUFFER, render_state->fbo_state.fbo);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, render_state->fbo_state.fbo2);
glBlitFramebuffer(0, // srcX0
0, // srcY0
w, // srcX1
h, // srcY1
0, // dstX0
0, // dstY0
w, // dstX1
h, // dstY1
GL_COLOR_BUFFER_BIT, // mask
GL_LINEAR // filter
);
m_blackout_renderer.draw(Vector4f(0, 0, 0, 1.f - alp), render_state, prof);
// Render to the screen directly now
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glViewport(render_state->window_offset_x_px, render_state->window_offset_y_px,
render_state->window_width_px, render_state->window_height_px);
glEnable(GL_DEPTH_TEST);
}
glClearColor(0.0, 0.0, 0.0, 0.0);
glClearDepth(0.0);
glDepthMask(GL_TRUE);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
glDisable(GL_BLEND);
glDisable(GL_DEPTH_TEST);
glEnable(GL_BLEND);
glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ZERO);
glBlendEquation(GL_FUNC_ADD);
m_blackout_renderer.draw(Vector4f(0, 0, 0, alp), render_state, prof);
glEnable(GL_DEPTH_TEST);
}
@@ -22,6 +22,10 @@ struct RenderOptions {
bool draw_small_profiler_window = false;
bool draw_subtitle_editor_window = false;
int msaa_samples = 4;
int game_res_w = 640;
int game_res_h = 480;
bool save_screenshot = false;
std::string screenshot_path;
@@ -44,12 +48,12 @@ class OpenGLRenderer {
void render(DmaFollower dma, const RenderOptions& settings);
private:
void setup_frame(int window_width_px, int window_height_px, int offset_x, int offset_y);
void setup_frame(const RenderOptions& settings);
void dispatch_buckets(DmaFollower dma, ScopedProfilerNode& prof);
void do_pcrtc_effects(float alp, SharedRenderState* render_state, ScopedProfilerNode& prof);
void init_bucket_renderers();
void draw_renderer_selection_window();
void finish_screenshot(const std::string& output_name, int px, int py, int x, int y);
void finish_screenshot(const std::string& output_name, int px, int py, int x, int y, GLuint fbo);
template <typename T, class... Args>
T* init_bucket_renderer(const std::string& name,
BucketCategory cat,
+1
View File
@@ -89,6 +89,7 @@ ShaderLibrary::ShaderLibrary() {
at(ShaderId::MERC2) = {"merc2"};
at(ShaderId::SPRITE_DISTORT) = {"sprite_distort"};
at(ShaderId::SPRITE_DISTORT_INSTANCED) = {"sprite_distort_instanced"};
at(ShaderId::POST_PROCESSING) = {"post_processing"};
for (auto& shader : m_shaders) {
ASSERT_MSG(shader.okay(), "Shader compiled");
+1
View File
@@ -44,6 +44,7 @@ enum class ShaderId {
MERC2 = 19,
SPRITE_DISTORT = 20,
SPRITE_DISTORT_INSTANCED = 21,
POST_PROCESSING = 22,
MAX_SHADERS
};
+22 -22
View File
@@ -44,9 +44,9 @@ bool looks_like_distort_frame_data(const DmaFollower& dma) {
}
} // namespace
constexpr int SPRITE_RENDERER_MAX_SPRITES = 8000;
constexpr int SPRITE_RENDERER_MAX_SPRITES = 1920 * 10;
constexpr int SPRITE_RENDERER_MAX_DISTORT_SPRITES =
256 * 8; // size of sprite-aux-list in GOAL code * SPRITE_MAX_AMOUNT_MULT
256 * 10; // size of sprite-aux-list in GOAL code * SPRITE_MAX_AMOUNT_MULT
Sprite3::Sprite3(const std::string& name, BucketId my_id)
: BucketRenderer(name, my_id), m_direct(name, my_id, 1024) {
@@ -519,10 +519,10 @@ void Sprite3::distort_setup(ScopedProfilerNode& /*prof*/) {
*/
void Sprite3::distort_setup_instanced(SharedRenderState* render_state,
ScopedProfilerNode& /*prof*/) {
if (m_distort_instanced_ogl.last_window_width != render_state->window_width_px ||
m_distort_instanced_ogl.last_window_height != render_state->window_height_px) {
m_distort_instanced_ogl.last_window_width = render_state->window_width_px;
m_distort_instanced_ogl.last_window_height = render_state->window_height_px;
if (m_distort_instanced_ogl.last_width != render_state->fbo_state.width ||
m_distort_instanced_ogl.last_height != render_state->fbo_state.height) {
m_distort_instanced_ogl.last_width = render_state->fbo_state.width;
m_distort_instanced_ogl.last_height = render_state->fbo_state.height;
// Window dimensions changed, which means the aspect ratio may have changed, which means we have
// a new sine table
@@ -702,22 +702,22 @@ void Sprite3::distort_draw_instanced(SharedRenderState* render_state, ScopedProf
void Sprite3::distort_draw_common(SharedRenderState* render_state, ScopedProfilerNode& /*prof*/) {
// The distort effect needs to read the current framebuffer, so copy what's been rendered so far
// to a texture that we can then pass to the shader
glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
glBindFramebuffer(GL_READ_FRAMEBUFFER, render_state->fbo_state.fbo);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_distort_ogl.fbo);
glBlitFramebuffer(render_state->window_offset_x_px, // srcX0
render_state->window_offset_y_px, // srcY0
render_state->window_width_px + render_state->window_offset_x_px, // srcX1
render_state->window_height_px + render_state->window_offset_y_px, // srcY1
0, // dstX0
0, // dstY0
m_distort_ogl.fbo_width, // dstX1
m_distort_ogl.fbo_height, // dstY1
GL_COLOR_BUFFER_BIT, // mask
GL_NEAREST // filter
glBlitFramebuffer(0, // srcX0
0, // srcY0
render_state->fbo_state.width, // srcX1
render_state->fbo_state.height, // srcY1
0, // dstX0
0, // dstY0
m_distort_ogl.fbo_width, // dstX1
m_distort_ogl.fbo_height, // dstY1
GL_COLOR_BUFFER_BIT, // mask
GL_NEAREST // filter
);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glBindFramebuffer(GL_FRAMEBUFFER, render_state->fbo_state.fbo);
// Set up OpenGL state
m_current_mode.set_depth_write_enable(!m_sprite_distorter_setup.zbuf.zmsk()); // zbuf
@@ -732,10 +732,10 @@ void Sprite3::distort_draw_common(SharedRenderState* render_state, ScopedProfile
void Sprite3::distort_setup_framebuffer_dims(SharedRenderState* render_state) {
// Distort framebuffer must be the same dimensions as the default window framebuffer
if (m_distort_ogl.fbo_width != render_state->window_width_px ||
m_distort_ogl.fbo_height != render_state->window_height_px) {
m_distort_ogl.fbo_width = render_state->window_width_px;
m_distort_ogl.fbo_height = render_state->window_height_px;
if (m_distort_ogl.fbo_width != render_state->fbo_state.width ||
m_distort_ogl.fbo_height != render_state->fbo_state.height) {
m_distort_ogl.fbo_width = render_state->fbo_state.width;
m_distort_ogl.fbo_height = render_state->fbo_state.height;
glBindTexture(GL_TEXTURE_2D, m_distort_ogl.fbo_texture);
+2 -2
View File
@@ -117,8 +117,8 @@ class Sprite3 : public BucketRenderer {
GLuint vao;
GLuint vertex_buffer; // contains vertex data for each possible sprite resolution (3-11)
GLuint instance_buffer; // contains all instance specific data for each sprite per frame
int last_window_width = -1;
int last_window_height = -1;
int last_width = -1;
int last_height = -1;
bool vertex_data_changed = false;
} m_distort_instanced_ogl;
@@ -110,6 +110,9 @@ void OpenGlDebugGui::draw(const DmaStats& dma_stats) {
if (ImGui::BeginMenu("Screenshot")) {
ImGui::MenuItem("Screenshot Next Frame!", nullptr, &m_want_screenshot);
ImGui::InputText("File", m_screenshot_save_name, 50);
ImGui::InputInt("Width", &screenshot_width);
ImGui::InputInt("Height", &screenshot_height);
ImGui::InputInt("MSAA", &screenshot_samples);
ImGui::EndMenu();
}
@@ -63,6 +63,10 @@ class OpenGlDebugGui {
bool dump_events = false;
bool want_reboot_in_debug = false;
int screenshot_width = 1920;
int screenshot_height = 1080;
int screenshot_samples = 16;
private:
FrameTimeRecorder m_frame_timer;
bool m_draw_frame_time = false;
@@ -140,11 +140,12 @@ void FullScreenDraw::draw(const math::Vector4f& color,
ScopedProfilerNode& prof) {
glBindVertexArray(m_vao);
glBindBuffer(GL_ARRAY_BUFFER, m_vertex_buffer);
auto& shader = render_state->shaders[ShaderId::SOLID_COLOR];
auto& shader = render_state->shaders[ShaderId::POST_PROCESSING];
shader.activate();
glUniform4f(glGetUniformLocation(shader.id(), "fragment_color"), color[0], color[1], color[2],
color[3]);
prof.add_tri(2);
prof.add_draw_call();
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
}
}
@@ -0,0 +1,13 @@
#version 430 core
in vec2 screen_pos;
out vec4 color;
uniform vec4 fragment_color;
layout (binding = 30) uniform sampler2D screen_tex;
void main() {
color = vec4(texture(screen_tex, screen_pos).rgb * fragment_color.a, 1.0);
}
@@ -0,0 +1,10 @@
#version 430 core
layout (location = 0) in vec2 position_in;
out vec2 screen_pos;
void main() {
gl_Position = vec4(position_in, 0, 1.0);
screen_pos = (position_in + 1) / 2;
}
+32 -10
View File
@@ -140,7 +140,6 @@ static int gl_init(GfxSettings& settings) {
glfwWindowHint(GLFW_OPENGL_DEBUG_CONTEXT, GLFW_FALSE);
}
glfwWindowHint(GLFW_DOUBLEBUFFER, GLFW_TRUE);
glfwWindowHint(GLFW_SAMPLES, 1);
glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE);
return 0;
@@ -263,7 +262,13 @@ static bool endsWith(std::string_view str, std::string_view suffix) {
0 == str.compare(str.size() - suffix.size(), suffix.size(), suffix);
}
void render_game_frame(int width, int height, int lbox_width, int lbox_height) {
void render_game_frame(int game_width,
int game_height,
int window_width,
int window_height,
int lbox_width,
int lbox_height,
int msaa_samples) {
// wait for a copied chain.
bool got_chain = false;
{
@@ -278,16 +283,32 @@ void render_game_frame(int width, int height, int lbox_width, int lbox_height) {
if (got_chain) {
g_gfx_data->frame_idx_of_input_data = g_gfx_data->frame_idx;
RenderOptions options;
options.window_height_px = height;
options.window_width_px = width;
options.game_res_w = game_width;
options.game_res_h = game_height;
options.window_height_px = window_height;
options.window_width_px = window_width;
options.lbox_height_px = lbox_height;
options.lbox_width_px = lbox_width;
options.msaa_samples = msaa_samples;
options.draw_render_debug_window = g_gfx_data->debug_gui.should_draw_render_debug();
options.draw_profiler_window = g_gfx_data->debug_gui.should_draw_profiler();
options.draw_subtitle_editor_window = g_gfx_data->debug_gui.should_draw_subtitle_editor();
options.save_screenshot = g_gfx_data->debug_gui.get_screenshot_flag();
options.save_screenshot = false;
if (g_gfx_data->debug_gui.get_screenshot_flag()) {
options.save_screenshot = true;
options.game_res_w = g_gfx_data->debug_gui.screenshot_width;
options.game_res_h = g_gfx_data->debug_gui.screenshot_height;
options.msaa_samples = g_gfx_data->debug_gui.screenshot_samples;
}
options.draw_small_profiler_window = g_gfx_data->debug_gui.small_profiler;
options.pmode_alp_register = g_gfx_data->pmode_alp;
GLint msaa_max;
glGetIntegerv(GL_MAX_SAMPLES, &msaa_max);
if (options.msaa_samples > msaa_max) {
options.msaa_samples = msaa_max;
}
if (options.save_screenshot) {
// ensure the screenshot has an extension
std::string temp_path = g_gfx_data->debug_gui.screenshot_name();
@@ -471,8 +492,8 @@ void GLDisplay::render() {
}
// window size
int width = Gfx::g_global_settings.lbox_w;
int height = Gfx::g_global_settings.lbox_h;
int win_w = Gfx::g_global_settings.lbox_w;
int win_h = Gfx::g_global_settings.lbox_h;
int fbuf_w, fbuf_h;
glfwGetFramebufferSize(m_window, &fbuf_w, &fbuf_h);
#ifdef _WIN32
@@ -482,9 +503,9 @@ void GLDisplay::render() {
}
#endif
// horizontal letterbox size
int lbox_w = (fbuf_w - width) / 2;
int lbox_w = (fbuf_w - win_w) / 2;
// vertical letterbox size
int lbox_h = (fbuf_h - height) / 2;
int lbox_h = (fbuf_h - win_h) / 2;
#ifdef _WIN32
if (last_fullscreen_mode() == GfxDisplayMode::Borderless) {
// add one pixel of vertical letterbox on borderless to make up for extra line
@@ -495,7 +516,8 @@ void GLDisplay::render() {
// render game!
if (g_gfx_data->debug_gui.should_advance_frame()) {
auto p = scoped_prof("game-render");
render_game_frame(width, height, lbox_w, lbox_h);
render_game_frame(Gfx::g_global_settings.game_res_w, Gfx::g_global_settings.game_res_h, win_w,
win_h, lbox_w, lbox_h, Gfx::g_global_settings.msaa_samples);
}
if (g_gfx_data->debug_gui.should_gl_finish()) {
+10
View File
@@ -586,6 +586,14 @@ void set_fullscreen(u32 symptr, s64 screen) {
}
}
void set_game_resolution(s64 w, s64 h) {
Gfx::set_game_resolution(w, h);
}
void set_msaa(s64 samples) {
Gfx::set_msaa(samples);
}
void InitMachine_PCPort() {
// PC Port added functions
@@ -619,6 +627,8 @@ void InitMachine_PCPort() {
make_function_symbol_from_c("pc-set-frame-rate", (void*)set_frame_rate);
make_function_symbol_from_c("pc-set-vsync", (void*)set_vsync);
make_function_symbol_from_c("pc-set-window-lock", (void*)set_window_lock);
make_function_symbol_from_c("pc-set-game-resolution", (void*)set_game_resolution);
make_function_symbol_from_c("pc-set-msaa", (void*)set_msaa);
// graphics things
make_function_symbol_from_c("pc-set-letterbox", (void*)Gfx::set_letterbox);
@@ -4540,6 +4540,8 @@
(function "2560 x 1440" #f (lambda () (set-size! *pc-settings* 2560 1440)))
(function "2880 x 2160" #f (lambda () (set-size! *pc-settings* 2880 2160)))
(function "3840 x 2160" #f (lambda () (set-size! *pc-settings* 3840 2160)))
(function "512 x 224" #f (lambda () (set-size! *pc-settings* 512 224)))
(function "512 x 256" #f (lambda () (set-size! *pc-settings* 512 256)))
(function "512 x 448" #f (lambda () (set-size! *pc-settings* 512 448)))
(function "512 x 512" #f (lambda () (set-size! *pc-settings* 512 512)))
)
+2
View File
@@ -358,6 +358,8 @@
(define-extern pc-sound-set-flava-hack (function int none))
(define-extern pc-sound-set-fade-hack (function int none))
(define-extern pc-set-window-lock (function symbol none))
(define-extern pc-set-game-resolution (function int int none))
(define-extern pc-set-msaa (function int none))
(defenum pc-prof-event
(begin 0)
+3 -4
View File
@@ -29,7 +29,7 @@
(defglobalconstant PC_KERNEL_VERSION_BUILD #x0001)
(defglobalconstant PC_KERNEL_VERSION_REVISION #x0007)
(defglobalconstant PC_KERNEL_VERSION_REVISION #x0008)
(defglobalconstant PC_KERNEL_VERSION_MINOR #x0006)
(defglobalconstant PC_KERNEL_VERSION_MAJOR #x0001)
@@ -256,7 +256,7 @@
(gfx-renderer pc-gfx-renderer) ;; the renderer to use
(gfx-resolution float) ;; for supersampling
(gfx-anisotropy float) ;; for anisotropy
(gfx-msaa int) ;; for MSAA
(gfx-msaa int32) ;; for MSAA
;; ps2 settings
(ps2-read-speed? symbol) ;; emulate DVD loads
@@ -417,8 +417,7 @@
"Set the default graphics settings"
(set! (-> obj target-fps) 60)
(set! (-> obj width) PC_BASE_WIDTH)
(set! (-> obj height) PC_BASE_HEIGHT)
(pc-get-screen-size -1 (&-> obj width) (&-> obj height))
(set! (-> obj use-vis?) #f)
(set! (-> obj aspect-ratio-auto?) #f)
(set! (-> obj vsync?) #t)
+23 -4
View File
@@ -66,8 +66,8 @@
(set! (-> obj win-height) height)
)
(else
(format 0 "Nope! No changing fullscreen resolution for now!~%")
(format #t "Nope! No changing fullscreen resolution for now!~%")
(set! (-> obj width) width)
(set! (-> obj height) height)
)
)
(none))
@@ -98,7 +98,7 @@
(defmethod set-frame-rate! pc-settings ((obj pc-settings) (rate int))
"set the aspect ratio used for rendering."
(pc-set-frame-rate rate)
(if (and (!= 'fullscreen (-> obj display-mode))
(!= (pc-get-screen-rate -1) rate))
@@ -120,7 +120,7 @@
(set-video-mode '150fps)
)
)
rate)
(defmethod commit-to-file pc-settings ((obj pc-settings))
@@ -187,7 +187,9 @@
)
)
;; set fullscreen to what we want
(pc-set-fullscreen (-> obj display-mode) 0)
;; set window size and fps automatically if the window lock is enabled.
(when (-> obj window-lock?)
(pc-set-vsync (-> obj vsync?))
@@ -201,6 +203,21 @@
(!= (-> obj win-height) (-> obj real-height))))
(pc-set-window-size (max PC_MIN_WIDTH (-> obj win-width)) (max PC_MIN_HEIGHT (-> obj win-height))))
)
;; do game resolution
(if (= (-> obj display-mode) 'windowed)
(pc-set-game-resolution (-> obj win-width) (-> obj win-height))
(pc-set-game-resolution (-> obj width) (-> obj height)))
;; set msaa sample rate. if invalid, just reset to 4.
(let ((valid? #f))
(dotimes (i 31)
(if (= (-> obj gfx-msaa) (ash 1 i))
(true! valid?))
)
(if (not valid?) (set! (-> obj gfx-msaa) 4))
(pc-set-msaa (-> obj gfx-msaa))
)
(pc-discord-rpc-set (if (-> obj discord-rpc?) 1 0))
@@ -753,6 +770,7 @@
(set! (-> obj width) (file-stream-read-int file))
(set! (-> obj height) (file-stream-read-int file))
)
(("msaa") (set! (-> obj gfx-msaa) (file-stream-read-int file)))
(("aspect") (set-aspect! obj (file-stream-read-int file) (file-stream-read-int file)))
(("aspect-test")
(set! (-> obj aspect-custom-x) (file-stream-read-int file))
@@ -872,6 +890,7 @@
(format file " (fps ~D)~%" (-> obj target-fps))
(format file " (game-size ~D ~D)~%" (-> obj width) (-> obj height))
(format file " (msaa ~D)~%" (-> obj gfx-msaa))
(format file " (window-size ~D ~D)~%" (-> obj win-width) (-> obj win-height))
(format file " (aspect ~D ~D)~%" (-> obj width) (-> obj height))
(format file " (aspect-test ~D ~D)~%" (-> obj aspect-custom-x) (-> obj aspect-custom-y))
+59 -45
View File
@@ -62,7 +62,7 @@
(subtitle-backup pc-subtitle-lang)
(aspect-native-choice symbol)
(current-carousell (array game-text-id))
(selection int)
(direction symbol)
(transition symbol)
@@ -127,7 +127,7 @@
(new 'static 'game-option :option-type (game-option-type display-mode) :name (game-text-id display-mode) :scale #t)
(new 'static 'game-option :option-type (game-option-type on-off) :name (game-text-id vsync) :scale #t)
(new 'static 'game-option :option-type (game-option-type menu) :name (game-text-id aspect-ratio) :scale #t :param3 (game-option-menu aspect-ratio))
;(new 'static 'game-option :option-type (game-option-type msaa) :name (game-text-id msaa) :scale #t)
(new 'static 'game-option :option-type (game-option-type msaa) :name (game-text-id msaa) :scale #t)
(new 'static 'game-option :option-type (game-option-type frame-rate) :name (game-text-id frame-rate) :scale #t)
(new 'static 'game-option :option-type (game-option-type menu) :name (game-text-id ps2-options) :scale #t :param3 (game-option-menu gfx-ps2-options))
(new 'static 'game-option :option-type (game-option-type button) :name (game-text-id back) :scale #t)
@@ -139,7 +139,7 @@
(new 'static 'game-option :option-type (game-option-type display-mode) :name (game-text-id display-mode) :scale #t)
(new 'static 'game-option :option-type (game-option-type on-off) :name (game-text-id vsync) :scale #t)
(new 'static 'game-option :option-type (game-option-type menu) :name (game-text-id aspect-ratio) :scale #t :param3 (game-option-menu aspect-ratio))
;(new 'static 'game-option :option-type (game-option-type msaa) :name (game-text-id msaa) :scale #t)
(new 'static 'game-option :option-type (game-option-type msaa) :name (game-text-id msaa) :scale #t)
(new 'static 'game-option :option-type (game-option-type menu) :name (game-text-id ps2-options) :scale #t :param3 (game-option-menu gfx-ps2-options))
(new 'static 'game-option :option-type (game-option-type button) :name (game-text-id back) :scale #t)
)
@@ -321,14 +321,14 @@
(defun find-highest-resolution ()
(let ((sx 0) (sy 0) (found #f) (mult GAME_MIN_RES_MULT) (lastr 0) (hir 0) (lor 0))
(pc-get-screen-size -1 (the (pointer int32) (& sx)) (the (pointer int32) (& sy)))
(if (> sy sx)
(set! sy sx))
(until found
(dotimes (i (-> *resolutions* length))
(let ((thisr (the int (* mult (the float (-> *resolutions* i))))))
(cond
@@ -342,15 +342,15 @@
(set! lastr thisr))
)
))
(if (not found)
(*! mult 2))
)
(set! hir lastr)
mult
)
)
(defmacro add-resolution-option (x y)
@@ -361,7 +361,7 @@
(set! (-> option param1) (the float ,x))
(set! (-> option param2) (the float ,y))
(set! (-> option scale) #t)
(1+! (-> *temp-options* length))
)
)
@@ -373,7 +373,7 @@
(set! (-> option name) ,text-id)
(set! (-> option param1) (the float ,flava))
(set! (-> option scale) #t)
(1+! (-> *temp-options* length))
)
)
@@ -384,35 +384,34 @@
(set! (-> option option-type) (game-option-type button))
(set! (-> option name) (game-text-id back))
(set! (-> option scale) #t)
(1+! (-> *temp-options* length))
)
)
(defun build-resolution-options ((skip int) (amount int))
(set! (-> *temp-options* length) 0)
(let ((done? #f) (mult (find-highest-resolution)) (sx 0) (sy 0) (flip? #f) (aspect 0.0)
(let* ((done? #f) (mult (find-highest-resolution)) (sx 0) (sy 0)
(display-mode (pc-get-fullscreen))
;; hack - do not use screen resolution in windowed mode, taskbar etc. messes it up and makes it useless!
(skip? (= 'windowed (pc-get-fullscreen)))
(skip? (= 'windowed display-mode))
;; shortcut
(max-options (1- (-> *temp-options* allocated-length))))
;; get screen size (for capping)
(pc-get-screen-size -1 (the (pointer int32) (& sx)) (the (pointer int32) (& sy)))
;; portrait mode. unused
(set! flip? (> sy sx))
(case (pc-get-fullscreen)
(('fullscreen)
(case display-mode
#|(('fullscreen)
;; insert psyched out trollface here
(set! sx 0)
(set! sy 0)
(countdown (i (pc-get-screen-vmode-count))
(let ((thisx 0) (thisy 0))
(pc-get-screen-size i (the (pointer int32) (& thisx)) (the (pointer int32) (& thisy)))
(when (not (and (= thisx sx) (= thisy sy)))
(add-resolution-option thisx thisy)
)
@@ -420,24 +419,32 @@
(set! sy thisy)
)
)
)
)|#
(else
;; extra button when fullscreen
(when (not skip?)
(add-resolution-option sx sy)
(set! (-> *temp-options* (1- (length *temp-options*)) name) (game-text-id fit-to-screen))
)
;; supersampling in fullscreen and stuff. this results in way too many resolution options lol.
(when (!= display-mode 'windowed)
(*! sx 4)
(*! sy 4)
(*! mult 4)
)
;; game aspect ratio
(set! aspect (-> *pc-settings* aspect-ratio))
(let ((aspect (-> *pc-settings* aspect-ratio)))
(until (or done? (= (length *temp-options*) max-options))
(countdown (i (-> *resolutions* length))
(let* ((thisr (the int (* mult (the float (-> *resolutions* i)))))
(thisx (the int (* aspect (the float thisr))))
(thisy thisr)
)
(when (and (not skip?) (< (length *temp-options*) max-options)
(<= thisy sy) (<= thisx sx)
(= aspect (/ (the float thisx) (the float thisy)))
@@ -446,31 +453,38 @@
))
(false! skip?)
)
(if (> mult GAME_MIN_RES_MULT)
(*! mult 0.5)
(/! mult 2)
(true! done?))
)
))
)
)
;; extra funny options
(when (and (!= display-mode 'windowed)
(< (length *temp-options*) (- (-> *temp-options* allocated-length) 3)))
(add-resolution-option 512 224)
(add-resolution-option 512 448)
)
(add-back-option)
)
*temp-options*
)
(defun build-flava-player-options ((mus-idx int))
(set! (-> *temp-options* length) 0)
(dotimes (i (-> *music-flava-name-list* mus-idx length))
(if (nonzero? (-> *music-flava-name-list* mus-idx i))
(add-flava-player-option (-> *music-flava-name-list* mus-idx i) i)
)
)
(add-back-option)
*temp-options*
)
@@ -511,7 +525,7 @@
(defun progress-draw-carousell-from-string-list ((options (array game-text-id)) (font font-context) (y-off int) (new-val int))
"yep."
(let ((old-lang (-> *progress-carousell* selection))
(new-lang new-val)
(max-lang (length options))
@@ -647,12 +661,12 @@
(set! (-> *options-remap* (progress-screen flava-player)) *temp-options*)
(set! (-> *options-remap* (progress-screen memcard-disable-auto-save)) *yes-no-options*)
(set! (-> *options-remap* (progress-screen memcard-auto-save-disabled)) *ok-options*)
;; set default params
(set! (-> *progress-state* aspect-ratio-choice) (get-aspect-ratio))
(set! (-> *progress-state* video-mode-choice) (get-video-mode))
(set! (-> *progress-state* yes-no-choice) #f)
;; set variable pointers
(set! (-> *game-options* 0 value-to-modify) (&-> *setting-control* default vibration))
(set! (-> *game-options* 1 value-to-modify) (&-> *setting-control* default play-hints))
@@ -677,11 +691,11 @@
(set! (-> *game-options-pc* 7 value-to-modify) (&-> *progress-carousell* int-backup))
(set! (-> *graphic-options-pc* 1 value-to-modify) (&-> *progress-carousell* int-backup))
(set! (-> *graphic-options-pc* 2 value-to-modify) (&-> *pc-settings* vsync?))
;(set! (-> *graphic-options-pc* 4 value-to-modify) (&-> *progress-carousell* int-backup))
(set! (-> *graphic-options-pc* 4 value-to-modify) (&-> *progress-carousell* int-backup))
(set! (-> *graphic-options-pc* 5 value-to-modify) (&-> *progress-carousell* int-backup))
(set! (-> *graphic-options-no-frame-rate-pc* 1 value-to-modify) (&-> *progress-carousell* int-backup))
(set! (-> *graphic-options-no-frame-rate-pc* 2 value-to-modify) (&-> *pc-settings* vsync?))
;(set! (-> *graphic-options-pc* 4 value-to-modify) (&-> *progress-carousell* int-backup))
(set! (-> *graphic-options-pc* 4 value-to-modify) (&-> *progress-carousell* int-backup))
(set! (-> *misc-options* 0 value-to-modify) (&-> *pc-settings* discord-rpc?))
(set! (-> *misc-options* 1 value-to-modify) (&-> *pc-settings* money-starburst?))
(set! (-> *camera-options* 0 value-to-modify) (&-> *pc-settings* first-camera-h-inverted?))
@@ -697,7 +711,7 @@
(set! (-> *sound-options-pc* 2 value-to-modify) (&-> *setting-control* default dialog-volume))
;(set! (-> *sound-options-pc* 3 value-to-modify) (&-> *pc-settings* music-fadein?))
(set! (-> *progress-carousell* aspect-native-choice) (-> *pc-settings* use-vis?))
;; scroll stuff!
(progress-scroll-reset)
(none)
@@ -1339,7 +1353,7 @@
(defmethod respond-memcard progress ((obj progress))
"logic for handling input in memcard screens."
(let ((s5-0 (-> obj card-info)))
(when (and s5-0 (not (-> obj in-transition)))
(when (or (cpad-pressed? 0 x) (cpad-pressed? 0 circle))
@@ -1993,7 +2007,7 @@
;; override the post handler for progress-normal
(set! (-> progress-normal post)
(set! (-> progress-normal post)
(lambda :behavior progress ()
(when (progress-scrolling?)
(seek! (-> *progress-scroll* transition) 1.0 (* (/ 1.75 512) (-> self transition-speed) (-> *display* time-adjust-ratio)))
@@ -2156,7 +2170,7 @@
))
;; override the enter handler for progress-going-out
(set! (-> progress-going-out enter)
(set! (-> progress-going-out enter)
(lambda :behavior progress ()
(sound-play "menu-close")
(hide-progress-icons)