mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-01-30 12:32:43 +00:00
overlays: move debug overlay to native overlay
This commit is contained in:
parent
d08c7a9b96
commit
3f2c75d920
@ -487,6 +487,7 @@ target_sources(rpcs3_emu PRIVATE
|
||||
RSX/Overlays/overlay_animation.cpp
|
||||
RSX/Overlays/overlay_controls.cpp
|
||||
RSX/Overlays/overlay_cursor.cpp
|
||||
RSX/Overlays/overlay_debug_overlay.cpp
|
||||
RSX/Overlays/overlay_edit_text.cpp
|
||||
RSX/Overlays/overlay_fonts.cpp
|
||||
RSX/Overlays/overlay_list_view.cpp
|
||||
|
@ -1,252 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <charconv>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
#include "util/types.hpp"
|
||||
|
||||
/**
|
||||
* FONT GLYPHS GO HERE
|
||||
* Any font in hex format should work here.
|
||||
* For this case, We're using ANSI 128 characters, but more types can be supported
|
||||
*
|
||||
* This example is the GNU unifont glyph set
|
||||
*/
|
||||
|
||||
constexpr std::array<std::string_view, 128> GNU_UNIFONT_GLYPHS =
|
||||
{
|
||||
"0000 : AAAA00018000000180004A51EA505A51C99E0001800000018000000180005555",
|
||||
"0001 : AAAA00018000000180003993C252325F8A527193800000018000000180005555",
|
||||
"0002 : AAAA00018000000180003BA5C124311989247125800000018000000180005555",
|
||||
"0003 : AAAA00018000000180007BA5C1247919C1247925800000018000000180005555",
|
||||
"0004 : AAAA000180000001800079BFC2487A49C2487989800000018000000180005555",
|
||||
"0005 : AAAA00018000000180007A4DC2527B53C2D67A4F800000018000000180005555",
|
||||
"0006 : AAAA000180000001800031A5CA287A31CA2849A5800000018000000180005555",
|
||||
"0007 : AAAA000180000001800073D1CA1073D1CA1073DF800000018000000180005555",
|
||||
"0008 : AAAA00018000000180001E3991401E3191081E71800000018000000180005555",
|
||||
"0009 : AAAA000180000001800022F9A2203E21A2202221800000018000000180005555",
|
||||
"000A : AAAA000180000001800020F9A08020F9A0803E81800000018000000180005555",
|
||||
"000B : AAAA000180000001800022F9A220222194200821800000018000000180005555",
|
||||
"000C : AAAA00018000000180003EF9A0803EF9A0802081800000018000000180005555",
|
||||
"000D : AAAA00018000000180001EF1A08820F1A0901E89800000018000000180005555",
|
||||
"000E : AAAA00018000000180001E71A0881C8982883C71800000018000000180005555",
|
||||
"000F : AAAA00018000000180001EF9A0201C2182203CF9800000018000000180005555",
|
||||
"0010 : AAAA0001800000018000391DA510251DA51039DD800000018000000180005555",
|
||||
"0011 : AAAA00018000000180007189CA184A09CA08719D800000018000000180005555",
|
||||
"0012 : AAAA00018000000180007199CA044A09CA10719D800000018000000180005555",
|
||||
"0013 : AAAA00018000000180007199CA044A19CA047199800000018000000180005555",
|
||||
"0014 : AAAA00018000000180007185CA0C4A15CA1C7185800000018000000180005555",
|
||||
"0015 : AAAA00018000000180004993EA546A59DBD44A53800000018000000180005555",
|
||||
"0016 : AAAA00018000000180003453C29A311789127113800000018000000180005555",
|
||||
"0017 : AAAA00018000000180007BB9C1247939C1247939800000018000000180005555",
|
||||
"0018 : AAAA00018000000180003325C4B447ADC4A434A5800000018000000180005555",
|
||||
"0019 : AAAA00018000000180003E89A0D83EA9A0883E89800000018000000180005555",
|
||||
"001A : AAAA00018000000180003A5DC252325D8A52719D800000018000000180005555",
|
||||
"001B : AAAA000180000001800079CFC2107991C0507B8F800000018000000180005555",
|
||||
"001C : AAAA00018000000180001E7190801E61901010E1800000018000000180005555",
|
||||
"001D : AAAA00018000000180000E719080166192100EE1800000018000000180005555",
|
||||
"001E : AAAA00018000000180001C7192801C61941012E1800000018000000180005555",
|
||||
"001F : AAAA000180000001800012719280126192100CE1800000018000000180005555",
|
||||
"0020 : 00000000000000000000000000000000",
|
||||
"0021 : 00000000080808080808080008080000",
|
||||
"0022 : 00002222222200000000000000000000",
|
||||
"0023 : 000000001212127E24247E4848480000",
|
||||
"0024 : 00000000083E4948380E09493E080000",
|
||||
"0025 : 00000000314A4A340808162929460000",
|
||||
"0026 : 000000001C2222141829454246390000",
|
||||
"0027 : 00000808080800000000000000000000",
|
||||
"0028 : 00000004080810101010101008080400",
|
||||
"0029 : 00000020101008080808080810102000",
|
||||
"002A : 00000000000008492A1C2A4908000000",
|
||||
"002B : 0000000000000808087F080808000000",
|
||||
"002C : 00000000000000000000000018080810",
|
||||
"002D : 0000000000000000003C000000000000",
|
||||
"002E : 00000000000000000000000018180000",
|
||||
"002F : 00000000020204080810102040400000",
|
||||
"0030 : 00000000182442464A52624224180000",
|
||||
"0031 : 000000000818280808080808083E0000",
|
||||
"0032 : 000000003C4242020C102040407E0000",
|
||||
"0033 : 000000003C4242021C020242423C0000",
|
||||
"0034 : 00000000040C142444447E0404040000",
|
||||
"0035 : 000000007E4040407C020202423C0000",
|
||||
"0036 : 000000001C2040407C424242423C0000",
|
||||
"0037 : 000000007E0202040404080808080000",
|
||||
"0038 : 000000003C4242423C424242423C0000",
|
||||
"0039 : 000000003C4242423E02020204380000",
|
||||
"003A : 00000000000018180000001818000000",
|
||||
"003B : 00000000000018180000001808081000",
|
||||
"003C : 00000000000204081020100804020000",
|
||||
"003D : 000000000000007E0000007E00000000",
|
||||
"003E : 00000000004020100804081020400000",
|
||||
"003F : 000000003C4242020408080008080000",
|
||||
"0040 : 000000001C224A565252524E201E0000",
|
||||
"0041 : 0000000018242442427E424242420000",
|
||||
"0042 : 000000007C4242427C424242427C0000",
|
||||
"0043 : 000000003C42424040404042423C0000",
|
||||
"0044 : 00000000784442424242424244780000",
|
||||
"0045 : 000000007E4040407C404040407E0000",
|
||||
"0046 : 000000007E4040407C40404040400000",
|
||||
"0047 : 000000003C424240404E4242463A0000",
|
||||
"0048 : 00000000424242427E42424242420000",
|
||||
"0049 : 000000003E08080808080808083E0000",
|
||||
"004A : 000000001F0404040404044444380000",
|
||||
"004B : 00000000424448506060504844420000",
|
||||
"004C : 000000004040404040404040407E0000",
|
||||
"004D : 00000000424266665A5A424242420000",
|
||||
"004E : 0000000042626252524A4A4646420000",
|
||||
"004F : 000000003C42424242424242423C0000",
|
||||
"0050 : 000000007C4242427C40404040400000",
|
||||
"0051 : 000000003C4242424242425A663C0300",
|
||||
"0052 : 000000007C4242427C48444442420000",
|
||||
"0053 : 000000003C424240300C0242423C0000",
|
||||
"0054 : 000000007F0808080808080808080000",
|
||||
"0055 : 000000004242424242424242423C0000",
|
||||
"0056 : 00000000414141222222141408080000",
|
||||
"0057 : 00000000424242425A5A666642420000",
|
||||
"0058 : 00000000424224241818242442420000",
|
||||
"0059 : 00000000414122221408080808080000",
|
||||
"005A : 000000007E02020408102040407E0000",
|
||||
"005B : 0000000E080808080808080808080E00",
|
||||
"005C : 00000000404020101008080402020000",
|
||||
"005D : 00000070101010101010101010107000",
|
||||
"005E : 00001824420000000000000000000000",
|
||||
"005F : 00000000000000000000000000007F00",
|
||||
"0060 : 00201008000000000000000000000000",
|
||||
"0061 : 0000000000003C42023E4242463A0000",
|
||||
"0062 : 0000004040405C6242424242625C0000",
|
||||
"0063 : 0000000000003C4240404040423C0000",
|
||||
"0064 : 0000000202023A4642424242463A0000",
|
||||
"0065 : 0000000000003C42427E4040423C0000",
|
||||
"0066 : 0000000C1010107C1010101010100000",
|
||||
"0067 : 0000000000023A44444438203C42423C",
|
||||
"0068 : 0000004040405C624242424242420000",
|
||||
"0069 : 000000080800180808080808083E0000",
|
||||
"006A : 0000000404000C040404040404044830",
|
||||
"006B : 00000040404044485060504844420000",
|
||||
"006C : 000000180808080808080808083E0000",
|
||||
"006D : 00000000000076494949494949490000",
|
||||
"006E : 0000000000005C624242424242420000",
|
||||
"006F : 0000000000003C4242424242423C0000",
|
||||
"0070 : 0000000000005C6242424242625C4040",
|
||||
"0071 : 0000000000003A4642424242463A0202",
|
||||
"0072 : 0000000000005C624240404040400000",
|
||||
"0073 : 0000000000003C4240300C02423C0000",
|
||||
"0074 : 000000001010107C10101010100C0000",
|
||||
"0075 : 000000000000424242424242463A0000",
|
||||
"0076 : 00000000000042424224242418180000",
|
||||
"0077 : 00000000000041494949494949360000",
|
||||
"0078 : 00000000000042422418182442420000",
|
||||
"0079 : 0000000000004242424242261A02023C",
|
||||
"007A : 0000000000007E0204081020407E0000",
|
||||
"007B : 0000000C101008081010080810100C00",
|
||||
"007C : 00000808080808080808080808080808",
|
||||
"007D : 00000030080810100808101008083000",
|
||||
"007E : 00000031494600000000000000000000",
|
||||
"007F : AAAA000180000001800073D1CA104BD1CA1073DF800000018000000180005555"
|
||||
};
|
||||
|
||||
class GlyphManager
|
||||
{
|
||||
private:
|
||||
|
||||
struct glyph
|
||||
{
|
||||
u8 character;
|
||||
u32 glyph_point_offset;
|
||||
u32 points_count;
|
||||
std::array<u8, 16> plot;
|
||||
};
|
||||
|
||||
std::vector<glyph> glyph_map;
|
||||
|
||||
void decode_glyph_map(const std::array<std::string_view, 128>& font_glyphs)
|
||||
{
|
||||
glyph_map.reserve(font_glyphs.size());
|
||||
|
||||
for (const auto &font_glyph : font_glyphs)
|
||||
{
|
||||
glyph this_glyph{};
|
||||
|
||||
const auto index = font_glyph.substr(0, 4);
|
||||
std::from_chars(index.data(), index.data() + index.size(), this_glyph.character, 16);
|
||||
|
||||
const auto glyph_data = font_glyph.substr(7);
|
||||
if (glyph_data.length() == 32)
|
||||
{
|
||||
for (usz n = 0; n < this_glyph.plot.size(); ++n)
|
||||
{
|
||||
const auto line = glyph_data.substr(n * 2, 2);
|
||||
std::from_chars(line.data(), line.data() + line.size(), this_glyph.plot[n], 16);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO: Support 16-wide characters
|
||||
}
|
||||
|
||||
glyph_map.push_back(this_glyph);
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
struct glyph_point
|
||||
{
|
||||
float x;
|
||||
float y;
|
||||
|
||||
explicit glyph_point(float _x, float _y) : x(_x), y(_y)
|
||||
{}
|
||||
};
|
||||
|
||||
GlyphManager()
|
||||
{
|
||||
decode_glyph_map(GNU_UNIFONT_GLYPHS);
|
||||
}
|
||||
|
||||
std::vector<glyph_point> generate_point_map()
|
||||
{
|
||||
std::vector<glyph_point> result;
|
||||
|
||||
for (auto &entry : glyph_map)
|
||||
{
|
||||
entry.glyph_point_offset = ::size32(result);
|
||||
|
||||
for (usz j = 0; j < entry.plot.size(); ++j)
|
||||
{
|
||||
const auto &line = entry.plot[j];
|
||||
if (line == 0)
|
||||
continue;
|
||||
|
||||
for (int i = 0; i < 8; ++i)
|
||||
{
|
||||
if (line & (1 << i))
|
||||
{
|
||||
// Font is inverted, so we correct it for conventional renderers
|
||||
const auto x = static_cast<float>(7 - i);
|
||||
const auto y = static_cast<float>(15 - j);
|
||||
result.emplace_back(x, y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
entry.points_count = ::size32(result) - entry.glyph_point_offset;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
std::unordered_map<u8, std::pair<u32, u32>> get_glyph_offsets() const
|
||||
{
|
||||
std::unordered_map<u8, std::pair<u32, u32>> result = {};
|
||||
|
||||
for (const auto &entry : glyph_map)
|
||||
{
|
||||
result[entry.character] = std::make_pair(entry.glyph_point_offset, entry.points_count);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
};
|
@ -505,7 +505,6 @@ void GLGSRender::on_exit()
|
||||
}
|
||||
|
||||
m_null_textures.clear();
|
||||
m_text_printer.close();
|
||||
m_gl_texture_cache.destroy();
|
||||
m_ui_renderer.destroy();
|
||||
m_video_output_pass.destroy();
|
||||
|
@ -5,7 +5,6 @@
|
||||
#include "GLTextureCache.h"
|
||||
#include "GLRenderTargets.h"
|
||||
#include "GLProgramBuffer.h"
|
||||
#include "GLTextOut.h"
|
||||
#include "GLOverlays.h"
|
||||
#include "GLShaderInterpreter.h"
|
||||
|
||||
@ -114,7 +113,6 @@ class GLGSRender : public GSRender, public ::rsx::reports::ZCULL_control
|
||||
|
||||
bool manually_flush_ring_buffers = false;
|
||||
|
||||
gl::text_writer m_text_printer;
|
||||
gl::ui_overlay_renderer m_ui_renderer;
|
||||
gl::video_out_calibration_pass m_video_output_pass;
|
||||
|
||||
|
@ -2,6 +2,7 @@
|
||||
#include "GLGSRender.h"
|
||||
#include "Emu/Cell/Modules/cellVideoOut.h"
|
||||
#include "Emu/RSX/Overlays/overlay_manager.h"
|
||||
#include "Emu/RSX/Overlays/overlay_debug_overlay.h"
|
||||
#include "util/video_provider.h"
|
||||
|
||||
LOG_CHANNEL(screenshot_log, "SCREENSHOT");
|
||||
@ -323,36 +324,8 @@ void GLGSRender::flip(const rsx::display_flip_info_t& info)
|
||||
}
|
||||
}
|
||||
|
||||
if (g_cfg.video.overlay && gl::get_driver_caps().ARB_shader_draw_parameters_supported)
|
||||
if (g_cfg.video.overlay)
|
||||
{
|
||||
if (!m_text_printer.is_enabled())
|
||||
{
|
||||
m_text_printer.init();
|
||||
m_text_printer.set_enabled(true);
|
||||
}
|
||||
|
||||
// Disable depth test
|
||||
gl_state.depth_func(GL_ALWAYS);
|
||||
|
||||
gl::screen.bind();
|
||||
glViewport(0, 0, width, height);
|
||||
|
||||
m_text_printer.set_scale(m_frame->client_device_pixel_ratio());
|
||||
|
||||
int y_loc = 0;
|
||||
const auto println = [&](const std::string& text)
|
||||
{
|
||||
m_text_printer.print_text(cmd, 4, y_loc, width, height, text);
|
||||
y_loc += 16;
|
||||
};
|
||||
|
||||
println(fmt::format("RSX Load: %3d%%", get_load()));
|
||||
println(fmt::format("draw calls: %16d", info.stats.draw_calls));
|
||||
println(fmt::format("draw call setup: %11dus", info.stats.setup_time));
|
||||
println(fmt::format("vertex upload time: %8dus", info.stats.vertex_upload_time));
|
||||
println(fmt::format("textures upload time: %6dus", info.stats.textures_upload_time));
|
||||
println(fmt::format("draw call execution: %7dus", info.stats.draw_exec_time));
|
||||
|
||||
const auto num_dirty_textures = m_gl_texture_cache.get_unreleased_textures_count();
|
||||
const auto texture_memory_size = m_gl_texture_cache.get_texture_memory_in_use() / (1024 * 1024);
|
||||
const auto num_flushes = m_gl_texture_cache.get_num_flush_requests();
|
||||
@ -365,17 +338,29 @@ void GLGSRender::flip(const rsx::display_flip_info_t& info)
|
||||
const auto num_texture_upload_miss = m_gl_texture_cache.get_texture_upload_misses_this_frame();
|
||||
const auto texture_upload_miss_ratio = m_gl_texture_cache.get_texture_upload_miss_percentage();
|
||||
const auto texture_copies_ellided = m_gl_texture_cache.get_texture_copies_ellided_this_frame();
|
||||
|
||||
println(fmt::format("Unreleased textures: %7d", num_dirty_textures));
|
||||
println(fmt::format("Texture memory: %12dM", texture_memory_size));
|
||||
println(fmt::format("Flush requests: %12d = %2d (%3d%%) hard faults, %2d unavoidable, %2d misprediction(s), %2d speculation(s)", num_flushes, num_misses, cache_miss_ratio, num_unavoidable, num_mispredict, num_speculate));
|
||||
println(fmt::format("Texture uploads: %11u (%u from CPU - %02u%%, %u copies avoided)", num_texture_upload, num_texture_upload_miss, texture_upload_miss_ratio, texture_copies_ellided));
|
||||
|
||||
const auto vertex_cache_hit_count = (info.stats.vertex_cache_request_count - info.stats.vertex_cache_miss_count);
|
||||
const auto vertex_cache_hit_ratio = info.stats.vertex_cache_request_count
|
||||
? (vertex_cache_hit_count * 100) / info.stats.vertex_cache_request_count
|
||||
: 0;
|
||||
println(fmt::format("Vertex cache hits: %9u/%u (%u%%)", vertex_cache_hit_count, info.stats.vertex_cache_request_count, vertex_cache_hit_ratio));
|
||||
|
||||
rsx::overlays::set_debug_overlay_text(fmt::format(
|
||||
"RSX Load: %3d%%\n"
|
||||
"draw calls: %16d\n"
|
||||
"draw call setup: %11dus\n"
|
||||
"vertex upload time: %8dus\n"
|
||||
"textures upload time: %6dus\n"
|
||||
"draw call execution: %7dus\n"
|
||||
"Unreleased textures: %7d\n"
|
||||
"Texture memory: %12dM\n"
|
||||
"Flush requests: %12d = %2d (%3d%%) hard faults, %2d unavoidable, %2d misprediction(s), %2d speculation(s)\n"
|
||||
"Texture uploads: %11u (%u from CPU - %02u%%, %u copies avoided)\n"
|
||||
"Vertex cache hits: %9u/%u (%u%%)",
|
||||
get_load(), info.stats.draw_calls, info.stats.setup_time, info.stats.vertex_upload_time,
|
||||
info.stats.textures_upload_time, info.stats.draw_exec_time, num_dirty_textures, texture_memory_size,
|
||||
num_flushes, num_misses, cache_miss_ratio, num_unavoidable, num_mispredict, num_speculate,
|
||||
num_texture_upload, num_texture_upload_miss, texture_upload_miss_ratio, texture_copies_ellided,
|
||||
vertex_cache_hit_count, info.stats.vertex_cache_request_count, vertex_cache_hit_ratio)
|
||||
);
|
||||
}
|
||||
|
||||
if (gl::debug::g_vis_texture)
|
||||
|
@ -1,214 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "util/types.hpp"
|
||||
#include "GLHelpers.h"
|
||||
#include "glutils/vao.hpp"
|
||||
#include "../Common/TextGlyphs.h"
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace gl
|
||||
{
|
||||
class text_writer
|
||||
{
|
||||
private:
|
||||
|
||||
gl::glsl::program m_program;
|
||||
gl::glsl::shader m_vs;
|
||||
gl::glsl::shader m_fs;
|
||||
|
||||
gl::vao m_vao;
|
||||
gl::buffer m_text_buffer;
|
||||
std::unordered_map<u8, std::pair<u32, u32>> m_offsets;
|
||||
|
||||
bool initialized = false;
|
||||
bool enabled = false;
|
||||
|
||||
f32 m_scale = 1.0f;
|
||||
|
||||
void init_program()
|
||||
{
|
||||
std::string vs =
|
||||
{
|
||||
"#version 420\n"
|
||||
"#extension GL_ARB_shader_draw_parameters: enable\n"
|
||||
"layout(location=0) in vec2 pos;\n"
|
||||
"uniform vec2 offsets[255];\n"
|
||||
"uniform vec2 scale;\n"
|
||||
"\n"
|
||||
"void main()\n"
|
||||
"{\n"
|
||||
" vec2 offset = offsets[gl_DrawIDARB];\n"
|
||||
" gl_Position = vec4(pos, 0., 1.);\n"
|
||||
" gl_Position.xy = gl_Position.xy * scale + offset;\n"
|
||||
"}\n"
|
||||
};
|
||||
|
||||
std::string fs =
|
||||
{
|
||||
"#version 420\n"
|
||||
"layout(location=0) out vec4 col0;\n"
|
||||
"uniform vec4 draw_color;\n"
|
||||
"\n"
|
||||
"void main()\n"
|
||||
"{\n"
|
||||
" col0 = draw_color;\n"
|
||||
"}\n"
|
||||
};
|
||||
|
||||
m_fs.create(::glsl::program_domain::glsl_fragment_program, fs);
|
||||
m_fs.compile();
|
||||
|
||||
m_vs.create(::glsl::program_domain::glsl_vertex_program, vs);
|
||||
m_vs.compile();
|
||||
|
||||
m_program.create();
|
||||
m_program.attach(m_vs);
|
||||
m_program.attach(m_fs);
|
||||
m_program.link();
|
||||
}
|
||||
|
||||
void load_program(gl::command_context& cmd, float scale_x, float scale_y, float *offsets, usz nb_offsets, color4f color)
|
||||
{
|
||||
float scale[] = { scale_x, scale_y };
|
||||
|
||||
cmd->use_program(m_program.id());
|
||||
|
||||
m_program.uniforms["draw_color"] = color;
|
||||
glProgramUniform2fv(m_program.id(), m_program.uniforms["offsets"].location(), static_cast<GLsizei>(nb_offsets), offsets);
|
||||
glProgramUniform2fv(m_program.id(), m_program.uniforms["scale"].location(), 1, scale);
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
text_writer() = default;
|
||||
~text_writer() = default;
|
||||
|
||||
void init()
|
||||
{
|
||||
GlyphManager glyph_source;
|
||||
auto points = glyph_source.generate_point_map();
|
||||
|
||||
const usz buffer_size = points.size() * sizeof(GlyphManager::glyph_point);
|
||||
|
||||
m_text_buffer.create(gl::buffer::target::array, buffer_size, points.data(), gl::buffer::memory_type::host_visible);
|
||||
m_offsets = glyph_source.get_glyph_offsets();
|
||||
|
||||
//Init VAO
|
||||
int old_vao;
|
||||
glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &old_vao);
|
||||
|
||||
m_vao.create();
|
||||
m_vao.bind();
|
||||
|
||||
//This is saved as part of the bound VAO's state
|
||||
m_vao.array_buffer = m_text_buffer;
|
||||
glEnableVertexAttribArray(0);
|
||||
glVertexAttribPointer(0, 2, GL_FLOAT, false, sizeof(GlyphManager::glyph_point), 0);
|
||||
|
||||
glBindVertexArray(old_vao);
|
||||
|
||||
init_program();
|
||||
initialized = true;
|
||||
}
|
||||
|
||||
void set_enabled(bool state)
|
||||
{
|
||||
enabled = state;
|
||||
}
|
||||
|
||||
bool is_enabled()
|
||||
{
|
||||
return enabled;
|
||||
}
|
||||
|
||||
void print_text(gl::command_context& cmd, int x, int y, int target_w, int target_h, const std::string &text, color4f color = { 0.3f, 1.f, 0.3f, 1.f })
|
||||
{
|
||||
if (!enabled) return;
|
||||
|
||||
ensure(initialized);
|
||||
|
||||
std::vector<GLint> offsets;
|
||||
std::vector<GLsizei> counts;
|
||||
std::vector<float> shader_offsets;
|
||||
char *s = const_cast<char *>(text.c_str());
|
||||
|
||||
//Y is in raster coordinates: convert to bottom-left origin
|
||||
y = (static_cast<int>(target_h / m_scale) - y - 16);
|
||||
|
||||
//Compress [0, w] and [0, h] into range [-1, 1]
|
||||
float scale_x = m_scale * 2.f / target_w;
|
||||
float scale_y = m_scale * 2.f / target_h;
|
||||
|
||||
float base_offset = 0.f;
|
||||
shader_offsets.reserve(text.length() * 2);
|
||||
|
||||
while (u8 offset = static_cast<u8>(*s))
|
||||
{
|
||||
bool to_draw = false; //Can be false for space or unsupported characters
|
||||
|
||||
auto o = m_offsets.find(offset);
|
||||
if (o != m_offsets.end())
|
||||
{
|
||||
if (o->second.second > 0)
|
||||
{
|
||||
to_draw = true;
|
||||
offsets.push_back(o->second.first);
|
||||
counts.push_back(o->second.second);
|
||||
}
|
||||
}
|
||||
|
||||
if (to_draw)
|
||||
{
|
||||
//Generate a scale_offset pair for this entry
|
||||
float offset_x = scale_x * (x + base_offset);
|
||||
offset_x -= 1.f;
|
||||
|
||||
float offset_y = scale_y * y;
|
||||
offset_y -= 1.f;
|
||||
|
||||
shader_offsets.push_back(offset_x);
|
||||
shader_offsets.push_back(offset_y);
|
||||
}
|
||||
|
||||
base_offset += 9.f;
|
||||
s++;
|
||||
}
|
||||
|
||||
//TODO: Add drop shadow if deemed necessary for visibility
|
||||
|
||||
int old_vao;
|
||||
glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &old_vao);
|
||||
|
||||
load_program(cmd, scale_x, scale_y, shader_offsets.data(), counts.size(), color);
|
||||
cmd->clip_planes(GL_NONE);
|
||||
|
||||
m_vao.bind();
|
||||
|
||||
glMultiDrawArrays(GL_POINTS, offsets.data(), counts.data(), static_cast<GLsizei>(counts.size()));
|
||||
glBindVertexArray(old_vao);
|
||||
}
|
||||
|
||||
void close()
|
||||
{
|
||||
if (initialized)
|
||||
{
|
||||
m_text_buffer.remove();
|
||||
m_vao.remove();
|
||||
|
||||
m_program.remove();
|
||||
m_fs.remove();
|
||||
m_vs.remove();
|
||||
|
||||
initialized = false;
|
||||
}
|
||||
}
|
||||
|
||||
void set_scale(double scale)
|
||||
{
|
||||
// Restrict scale to 2. The dots are gonna be too sparse otherwise.
|
||||
m_scale = std::min(static_cast<f32>(scale), 2.0f);
|
||||
}
|
||||
};
|
||||
}
|
@ -25,7 +25,6 @@ public:
|
||||
virtual void flip(draw_context_t ctx, bool skip_frame = false) = 0;
|
||||
virtual int client_width() = 0;
|
||||
virtual int client_height() = 0;
|
||||
virtual double client_device_pixel_ratio() const = 0;
|
||||
|
||||
virtual display_handle_t handle() const = 0;
|
||||
|
||||
|
81
rpcs3/Emu/RSX/Overlays/overlay_debug_overlay.cpp
Normal file
81
rpcs3/Emu/RSX/Overlays/overlay_debug_overlay.cpp
Normal file
@ -0,0 +1,81 @@
|
||||
#include "stdafx.h"
|
||||
#include "overlay_manager.h"
|
||||
#include "overlay_debug_overlay.h"
|
||||
#include "Emu/system_config.h"
|
||||
|
||||
namespace rsx
|
||||
{
|
||||
namespace overlays
|
||||
{
|
||||
debug_overlay::debug_overlay()
|
||||
{
|
||||
text_display.set_size(1260, 40);
|
||||
text_display.set_pos(10, 10);
|
||||
text_display.set_font("n023055ms.ttf", 10);
|
||||
text_display.align_text(overlay_element::text_align::left);
|
||||
text_display.set_wrap_text(true);
|
||||
text_display.fore_color = { 0.3f, 1.f, 0.3f, 1.f };
|
||||
text_display.back_color.a = 0.f;
|
||||
}
|
||||
|
||||
compiled_resource debug_overlay::get_compiled()
|
||||
{
|
||||
if (!visible)
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
if (const auto [dirty, text] = text_guard.get_text(); dirty)
|
||||
{
|
||||
text_display.set_text(text);
|
||||
}
|
||||
|
||||
compiled_resource result;
|
||||
result.add(text_display.get_compiled());
|
||||
return result;
|
||||
}
|
||||
|
||||
void debug_overlay::set_text(std::string&& text)
|
||||
{
|
||||
text_guard.set_text(std::move(text));
|
||||
visible = true;
|
||||
}
|
||||
|
||||
extern void reset_debug_overlay()
|
||||
{
|
||||
if (!g_cfg.misc.use_native_interface)
|
||||
return;
|
||||
|
||||
if (auto manager = g_fxo->try_get<rsx::overlays::display_manager>())
|
||||
{
|
||||
auto overlay = manager->get<rsx::overlays::debug_overlay>();
|
||||
|
||||
if (g_cfg.video.overlay)
|
||||
{
|
||||
if (!overlay)
|
||||
{
|
||||
overlay = manager->create<rsx::overlays::debug_overlay>();
|
||||
}
|
||||
}
|
||||
else if (overlay)
|
||||
{
|
||||
manager->remove<rsx::overlays::debug_overlay>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extern void set_debug_overlay_text(std::string&& text)
|
||||
{
|
||||
if (!g_cfg.misc.use_native_interface || !g_cfg.video.overlay)
|
||||
return;
|
||||
|
||||
if (auto manager = g_fxo->try_get<rsx::overlays::display_manager>())
|
||||
{
|
||||
if (auto overlay = manager->get<rsx::overlays::debug_overlay>())
|
||||
{
|
||||
overlay->set_text(std::move(text));
|
||||
}
|
||||
}
|
||||
}
|
||||
} // namespace overlays
|
||||
} // namespace rsx
|
25
rpcs3/Emu/RSX/Overlays/overlay_debug_overlay.h
Normal file
25
rpcs3/Emu/RSX/Overlays/overlay_debug_overlay.h
Normal file
@ -0,0 +1,25 @@
|
||||
#pragma once
|
||||
|
||||
#include "overlays.h"
|
||||
|
||||
namespace rsx
|
||||
{
|
||||
namespace overlays
|
||||
{
|
||||
class debug_overlay : public user_interface
|
||||
{
|
||||
label text_display;
|
||||
text_guard_t text_guard{};
|
||||
|
||||
public:
|
||||
debug_overlay();
|
||||
|
||||
compiled_resource get_compiled() override;
|
||||
|
||||
void set_text(std::string&& text);
|
||||
};
|
||||
|
||||
void reset_debug_overlay();
|
||||
void set_debug_overlay_text(std::string&& text);
|
||||
}
|
||||
}
|
@ -32,32 +32,6 @@ namespace rsx
|
||||
|
||||
animation_color_interpolate fade_animation;
|
||||
|
||||
struct text_guard_t
|
||||
{
|
||||
std::mutex mutex;
|
||||
std::string text;
|
||||
bool dirty{false};
|
||||
|
||||
void set_text(std::string t)
|
||||
{
|
||||
std::lock_guard lock(mutex);
|
||||
text = std::move(t);
|
||||
dirty = true;
|
||||
}
|
||||
|
||||
std::pair<bool, std::string> get_text()
|
||||
{
|
||||
if (dirty)
|
||||
{
|
||||
std::lock_guard lock(mutex);
|
||||
dirty = false;
|
||||
return { true, std::move(text) };
|
||||
}
|
||||
|
||||
return { false, {} };
|
||||
}
|
||||
};
|
||||
|
||||
text_guard_t text_guard{};
|
||||
std::array<text_guard_t, 2> bar_text_guard{};
|
||||
|
||||
|
@ -878,21 +878,19 @@ namespace rsx
|
||||
if (!g_cfg.misc.use_native_interface)
|
||||
return;
|
||||
|
||||
if (auto& manager = g_fxo->get<rsx::overlays::display_manager>(); g_fxo->is_init<rsx::overlays::display_manager>())
|
||||
if (auto manager = g_fxo->try_get<rsx::overlays::display_manager>())
|
||||
{
|
||||
auto& perf_settings = g_cfg.video.perf_overlay;
|
||||
auto perf_overlay = manager.get<rsx::overlays::perf_metrics_overlay>();
|
||||
auto perf_overlay = manager->get<rsx::overlays::perf_metrics_overlay>();
|
||||
|
||||
if (perf_settings.perf_overlay_enabled)
|
||||
{
|
||||
const bool existed = !!perf_overlay;
|
||||
|
||||
if (!existed)
|
||||
if (!perf_overlay)
|
||||
{
|
||||
perf_overlay = manager.create<rsx::overlays::perf_metrics_overlay>();
|
||||
perf_overlay = manager->create<rsx::overlays::perf_metrics_overlay>();
|
||||
}
|
||||
|
||||
std::lock_guard lock(manager);
|
||||
std::lock_guard lock(*manager);
|
||||
|
||||
perf_overlay->set_detail_level(perf_settings.level);
|
||||
perf_overlay->set_position(perf_settings.position);
|
||||
@ -912,7 +910,7 @@ namespace rsx
|
||||
}
|
||||
else if (perf_overlay)
|
||||
{
|
||||
manager.remove<rsx::overlays::perf_metrics_overlay>();
|
||||
manager->remove<rsx::overlays::perf_metrics_overlay>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -133,5 +133,31 @@ namespace rsx
|
||||
|
||||
s32 run_input_loop(std::function<bool()> check_state = nullptr);
|
||||
};
|
||||
|
||||
struct text_guard_t
|
||||
{
|
||||
std::mutex mutex;
|
||||
std::string text;
|
||||
bool dirty{false};
|
||||
|
||||
void set_text(std::string t)
|
||||
{
|
||||
std::lock_guard lock(mutex);
|
||||
text = std::move(t);
|
||||
dirty = true;
|
||||
}
|
||||
|
||||
std::pair<bool, std::string> get_text()
|
||||
{
|
||||
if (dirty)
|
||||
{
|
||||
std::lock_guard lock(mutex);
|
||||
dirty = false;
|
||||
return { true, std::move(text) };
|
||||
}
|
||||
|
||||
return { false, {} };
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -21,6 +21,7 @@
|
||||
#include "Emu/Cell/Modules/cellGcmSys.h"
|
||||
#include "util/serialization_ext.hpp"
|
||||
#include "Overlays/overlay_perf_metrics.h"
|
||||
#include "Overlays/overlay_debug_overlay.h"
|
||||
#include "Overlays/overlay_message.h"
|
||||
#include "Program/GLSLCommon.h"
|
||||
#include "Utilities/date_time.h"
|
||||
@ -903,6 +904,7 @@ namespace rsx
|
||||
if (!serialized) method_registers.init();
|
||||
|
||||
rsx::overlays::reset_performance_overlay();
|
||||
rsx::overlays::reset_debug_overlay();
|
||||
|
||||
if (!is_initialized)
|
||||
{
|
||||
|
@ -965,9 +965,6 @@ VKGSRender::~VKGSRender()
|
||||
|
||||
m_stencil_mirror_sampler.reset();
|
||||
|
||||
// Overlay text handler
|
||||
m_text_writer.reset();
|
||||
|
||||
// Pipeline descriptors
|
||||
m_descriptor_pool.destroy();
|
||||
|
||||
|
@ -14,7 +14,6 @@
|
||||
#include "VKTextureCache.h"
|
||||
#include "VKRenderTargets.h"
|
||||
#include "VKFormats.h"
|
||||
#include "VKTextOut.h"
|
||||
#include "VKOverlays.h"
|
||||
#include "VKProgramBuffer.h"
|
||||
#include "VKFramebuffer.h"
|
||||
@ -72,7 +71,6 @@ private:
|
||||
std::unique_ptr<vk::buffer> null_buffer;
|
||||
std::unique_ptr<vk::buffer_view> null_buffer_view;
|
||||
|
||||
std::unique_ptr<vk::text_writer> m_text_writer;
|
||||
std::unique_ptr<vk::upscaler> m_upscaler;
|
||||
output_scaling_mode m_output_scaling{output_scaling_mode::bilinear};
|
||||
|
||||
|
@ -3,6 +3,7 @@
|
||||
#include "vkutils/buffer_object.h"
|
||||
#include "Emu/RSX/Overlays/overlay_manager.h"
|
||||
#include "Emu/RSX/Overlays/overlays.h"
|
||||
#include "Emu/RSX/Overlays/overlay_debug_overlay.h"
|
||||
#include "Emu/Cell/Modules/cellVideoOut.h"
|
||||
|
||||
#include "upscalers/bilinear_pass.hpp"
|
||||
@ -763,32 +764,6 @@ void VKGSRender::flip(const rsx::display_flip_info_t& info)
|
||||
|
||||
if (g_cfg.video.overlay)
|
||||
{
|
||||
// TODO: Move this to native overlay! It is both faster and easier to manage
|
||||
if (!m_text_writer)
|
||||
{
|
||||
auto key = vk::get_renderpass_key(m_swapchain->get_surface_format());
|
||||
m_text_writer = std::make_unique<vk::text_writer>();
|
||||
m_text_writer->init(*m_device, vk::get_renderpass(*m_device, key));
|
||||
}
|
||||
|
||||
m_text_writer->set_scale(m_frame->client_device_pixel_ratio());
|
||||
|
||||
int y_loc = 0;
|
||||
const auto println = [&](const std::string& text)
|
||||
{
|
||||
m_text_writer->print_text(*m_current_command_buffer, *direct_fbo, 4, y_loc, direct_fbo->width(), direct_fbo->height(), text);
|
||||
y_loc += 16;
|
||||
};
|
||||
|
||||
println(fmt::format("RSX Load: %3d%%", get_load()));
|
||||
println(fmt::format("draw calls: %17d", info.stats.draw_calls));
|
||||
println(fmt::format("submits: %20d", info.stats.submit_count));
|
||||
println(fmt::format("draw call setup: %12dus", info.stats.setup_time));
|
||||
println(fmt::format("vertex upload time: %9dus", info.stats.vertex_upload_time));
|
||||
println(fmt::format("texture upload time: %8dus", info.stats.textures_upload_time));
|
||||
println(fmt::format("draw call execution: %8dus", info.stats.draw_exec_time));
|
||||
println(fmt::format("submit and flip: %12dus", info.stats.flip_time));
|
||||
|
||||
const auto num_dirty_textures = m_texture_cache.get_unreleased_textures_count();
|
||||
const auto texture_memory_size = m_texture_cache.get_texture_memory_in_use() / (1024 * 1024);
|
||||
const auto tmp_texture_memory_size = m_texture_cache.get_temporary_memory_in_use() / (1024 * 1024);
|
||||
@ -802,18 +777,33 @@ void VKGSRender::flip(const rsx::display_flip_info_t& info)
|
||||
const auto num_texture_upload_miss = m_texture_cache.get_texture_upload_misses_this_frame();
|
||||
const auto texture_upload_miss_ratio = m_texture_cache.get_texture_upload_miss_percentage();
|
||||
const auto texture_copies_ellided = m_texture_cache.get_texture_copies_ellided_this_frame();
|
||||
|
||||
println(fmt::format("Unreleased textures: %8d", num_dirty_textures));
|
||||
println(fmt::format("Texture cache memory: %7dM", texture_memory_size));
|
||||
println(fmt::format("Temporary texture memory: %3dM", tmp_texture_memory_size));
|
||||
println(fmt::format("Flush requests: %13d = %2d (%3d%%) hard faults, %2d unavoidable, %2d misprediction(s), %2d speculation(s)", num_flushes, num_misses, cache_miss_ratio, num_unavoidable, num_mispredict, num_speculate));
|
||||
println(fmt::format("Texture uploads: %12u (%u from CPU - %02u%%, %u copies avoided)", num_texture_upload, num_texture_upload_miss, texture_upload_miss_ratio, texture_copies_ellided));
|
||||
|
||||
const auto vertex_cache_hit_count = (info.stats.vertex_cache_request_count - info.stats.vertex_cache_miss_count);
|
||||
const auto vertex_cache_hit_ratio = info.stats.vertex_cache_request_count
|
||||
? (vertex_cache_hit_count * 100) / info.stats.vertex_cache_request_count
|
||||
: 0;
|
||||
println(fmt::format("Vertex cache hits: %10u/%u (%u%%)", vertex_cache_hit_count, info.stats.vertex_cache_request_count, vertex_cache_hit_ratio));
|
||||
|
||||
rsx::overlays::set_debug_overlay_text(fmt::format(
|
||||
"RSX Load: %3d%%\n"
|
||||
"draw calls: %17d\n"
|
||||
"submits: %20d\n"
|
||||
"draw call setup: %12dus\n"
|
||||
"vertex upload time: %9dus\n"
|
||||
"texture upload time: %8dus\n"
|
||||
"draw call execution: %8dus\n"
|
||||
"submit and flip: %12dus\n"
|
||||
"Unreleased textures: %8d\n"
|
||||
"Texture cache memory: %7dM\n"
|
||||
"Temporary texture memory: %3dM\n"
|
||||
"Flush requests: %13d = %2d (%3d%%) hard faults, %2d unavoidable, %2d misprediction(s), %2d speculation(s)\n"
|
||||
"Texture uploads: %12u (%u from CPU - %02u%%, %u copies avoided)\n"
|
||||
"Vertex cache hits: %10u/%u (%u%%)",
|
||||
get_load(), info.stats.draw_calls, info.stats.submit_count, info.stats.setup_time, info.stats.vertex_upload_time,
|
||||
info.stats.textures_upload_time, info.stats.draw_exec_time, info.stats.flip_time,
|
||||
num_dirty_textures, texture_memory_size, tmp_texture_memory_size,
|
||||
num_flushes, num_misses, cache_miss_ratio, num_unavoidable, num_mispredict, num_speculate,
|
||||
num_texture_upload, num_texture_upload_miss, texture_upload_miss_ratio, texture_copies_ellided,
|
||||
vertex_cache_hit_count, info.stats.vertex_cache_request_count, vertex_cache_hit_ratio)
|
||||
);
|
||||
}
|
||||
|
||||
direct_fbo->release();
|
||||
|
@ -1,362 +0,0 @@
|
||||
#pragma once
|
||||
#include "VKVertexProgram.h"
|
||||
#include "VKFragmentProgram.h"
|
||||
#include "VKRenderPass.h"
|
||||
#include "VKPipelineCompiler.h"
|
||||
|
||||
#include "vkutils/framebuffer_object.hpp"
|
||||
|
||||
#include "../Common/TextGlyphs.h"
|
||||
#include <unordered_map>
|
||||
|
||||
namespace vk
|
||||
{
|
||||
class text_writer
|
||||
{
|
||||
private:
|
||||
std::unique_ptr<vk::buffer> m_vertex_buffer;
|
||||
std::unique_ptr<vk::buffer> m_uniforms_buffer;
|
||||
|
||||
std::unique_ptr<vk::glsl::program> m_program;
|
||||
vk::glsl::shader m_vertex_shader;
|
||||
vk::glsl::shader m_fragment_shader;
|
||||
|
||||
vk::descriptor_pool m_descriptor_pool;
|
||||
vk::descriptor_set m_descriptor_set;
|
||||
VkDescriptorSetLayout m_descriptor_layout = nullptr;
|
||||
VkPipelineLayout m_pipeline_layout = nullptr;
|
||||
u32 m_used_descriptors = 0;
|
||||
|
||||
VkRenderPass m_render_pass;
|
||||
VkDevice device = nullptr;
|
||||
|
||||
u32 m_uniform_buffer_offset = 0;
|
||||
u32 m_uniform_buffer_size = 0;
|
||||
|
||||
f32 m_scale = 1.0f;
|
||||
|
||||
bool initialized = false;
|
||||
std::unordered_map<u8, std::pair<u32, u32>> m_offsets;
|
||||
|
||||
void init_descriptor_set(vk::render_device &dev)
|
||||
{
|
||||
rsx::simple_array<VkDescriptorPoolSize> descriptor_pools =
|
||||
{
|
||||
{ VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1 },
|
||||
};
|
||||
|
||||
// Reserve descriptor pools
|
||||
m_descriptor_pool.create(dev, descriptor_pools);
|
||||
|
||||
// Scale and offset data plus output color
|
||||
rsx::simple_array<VkDescriptorSetLayoutBinding> bindings =
|
||||
{
|
||||
{
|
||||
.binding = 0,
|
||||
.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
|
||||
.descriptorCount = 1,
|
||||
.stageFlags = VK_SHADER_STAGE_VERTEX_BIT,
|
||||
.pImmutableSamplers = nullptr
|
||||
}
|
||||
};
|
||||
m_descriptor_layout = vk::descriptors::create_layout(bindings);
|
||||
|
||||
VkPipelineLayoutCreateInfo layout_info = {};
|
||||
layout_info.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
|
||||
layout_info.setLayoutCount = 1;
|
||||
layout_info.pSetLayouts = &m_descriptor_layout;
|
||||
|
||||
CHECK_RESULT(vkCreatePipelineLayout(dev, &layout_info, nullptr, &m_pipeline_layout));
|
||||
}
|
||||
|
||||
void init_program()
|
||||
{
|
||||
std::string vs =
|
||||
{
|
||||
"#version 450\n"
|
||||
"#extension GL_ARB_separate_shader_objects : enable\n"
|
||||
"layout(location=0) in vec2 pos;\n"
|
||||
"layout(std140, set=0, binding=0) uniform scale_offset_buffer\n"
|
||||
"{\n"
|
||||
" vec4 offsets[510];\n"
|
||||
" vec4 scale;\n"
|
||||
" vec4 text_color;\n"
|
||||
"};\n"
|
||||
"\n"
|
||||
"layout(location=1) out vec4 draw_color;\n"
|
||||
"\n"
|
||||
"void main()\n"
|
||||
"{\n"
|
||||
" vec2 offset = offsets[gl_InstanceIndex].xy;\n"
|
||||
" gl_Position = vec4(pos, 0., 1.);\n"
|
||||
" gl_Position.xy = gl_Position.xy * scale.xy + offset;\n"
|
||||
" draw_color = text_color;\n"
|
||||
"}\n"
|
||||
};
|
||||
|
||||
std::string fs =
|
||||
{
|
||||
"#version 420\n"
|
||||
"#extension GL_ARB_separate_shader_objects : enable\n"
|
||||
"layout(location=1) in vec4 draw_color;\n"
|
||||
"layout(location=0) out vec4 col0;\n"
|
||||
"\n"
|
||||
"void main()\n"
|
||||
"{\n"
|
||||
" col0 = draw_color;\n"
|
||||
"}\n"
|
||||
};
|
||||
|
||||
m_vertex_shader.create(::glsl::program_domain::glsl_vertex_program, vs);
|
||||
m_vertex_shader.compile();
|
||||
|
||||
m_fragment_shader.create(::glsl::program_domain::glsl_fragment_program, fs);
|
||||
m_fragment_shader.compile();
|
||||
|
||||
VkPipelineShaderStageCreateInfo shader_stages[2] = {};
|
||||
shader_stages[0].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
|
||||
shader_stages[0].stage = VK_SHADER_STAGE_VERTEX_BIT;
|
||||
shader_stages[0].module = m_vertex_shader.get_handle();
|
||||
shader_stages[0].pName = "main";
|
||||
|
||||
shader_stages[1].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
|
||||
shader_stages[1].stage = VK_SHADER_STAGE_FRAGMENT_BIT;
|
||||
shader_stages[1].module = m_fragment_shader.get_handle();
|
||||
shader_stages[1].pName = "main";
|
||||
|
||||
std::vector<VkDynamicState> dynamic_state_descriptors;
|
||||
VkPipelineDynamicStateCreateInfo dynamic_state_info = {};
|
||||
dynamic_state_info.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO;
|
||||
dynamic_state_descriptors.push_back(VK_DYNAMIC_STATE_VIEWPORT);
|
||||
dynamic_state_descriptors.push_back(VK_DYNAMIC_STATE_SCISSOR);
|
||||
dynamic_state_info.pDynamicStates = dynamic_state_descriptors.data();
|
||||
dynamic_state_info.dynamicStateCount = ::size32(dynamic_state_descriptors);
|
||||
|
||||
VkVertexInputAttributeDescription vdesc;
|
||||
VkVertexInputBindingDescription vbind;
|
||||
|
||||
vdesc.binding = 0;
|
||||
vdesc.format = VK_FORMAT_R32G32_SFLOAT;
|
||||
vdesc.location = 0;
|
||||
vdesc.offset = 0;
|
||||
|
||||
vbind.binding = 0;
|
||||
vbind.inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
|
||||
vbind.stride = 8;
|
||||
|
||||
VkPipelineVertexInputStateCreateInfo vi = {};
|
||||
vi.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
|
||||
vi.vertexAttributeDescriptionCount = 1;
|
||||
vi.vertexBindingDescriptionCount = 1;
|
||||
vi.pVertexAttributeDescriptions = &vdesc;
|
||||
vi.pVertexBindingDescriptions = &vbind;
|
||||
|
||||
VkPipelineViewportStateCreateInfo vp = {};
|
||||
vp.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
|
||||
vp.scissorCount = 1;
|
||||
vp.viewportCount = 1;
|
||||
|
||||
VkPipelineMultisampleStateCreateInfo ms = {};
|
||||
ms.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
|
||||
ms.pSampleMask = NULL;
|
||||
ms.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
|
||||
|
||||
VkPipelineInputAssemblyStateCreateInfo ia = {};
|
||||
ia.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
|
||||
ia.topology = VK_PRIMITIVE_TOPOLOGY_POINT_LIST;
|
||||
|
||||
VkPipelineRasterizationStateCreateInfo rs = {};
|
||||
rs.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
|
||||
rs.lineWidth = 1.f;
|
||||
|
||||
VkPipelineColorBlendAttachmentState att = {};
|
||||
att.colorWriteMask = 0xf;
|
||||
|
||||
VkPipelineColorBlendStateCreateInfo cs = {};
|
||||
cs.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
|
||||
cs.attachmentCount = 1;
|
||||
cs.pAttachments = &att;
|
||||
|
||||
VkPipelineDepthStencilStateCreateInfo ds = {};
|
||||
ds.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO;
|
||||
|
||||
VkGraphicsPipelineCreateInfo info = {};
|
||||
info.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
|
||||
info.pVertexInputState = &vi;
|
||||
info.pInputAssemblyState = &ia;
|
||||
info.pRasterizationState = &rs;
|
||||
info.pColorBlendState = &cs;
|
||||
info.pMultisampleState = &ms;
|
||||
info.pViewportState = &vp;
|
||||
info.pDepthStencilState = &ds;
|
||||
info.stageCount = 2;
|
||||
info.pStages = shader_stages;
|
||||
info.pDynamicState = &dynamic_state_info;
|
||||
info.layout = m_pipeline_layout;
|
||||
info.basePipelineIndex = -1;
|
||||
info.basePipelineHandle = VK_NULL_HANDLE;
|
||||
info.renderPass = m_render_pass;
|
||||
|
||||
auto compiler = vk::get_pipe_compiler();
|
||||
m_program = compiler->compile(info, m_pipeline_layout, vk::pipe_compiler::COMPILE_INLINE);
|
||||
}
|
||||
|
||||
void load_program(vk::command_buffer &cmd, float scale_x, float scale_y, const float *offsets, usz nb_offsets, std::array<float, 4> color)
|
||||
{
|
||||
ensure(m_used_descriptors < 120);
|
||||
|
||||
m_descriptor_set = m_descriptor_pool.allocate(m_descriptor_layout);
|
||||
|
||||
float scale[] = { scale_x, scale_y };
|
||||
float colors[] = { color[0], color[1], color[2], color[3] };
|
||||
float* dst = static_cast<float*>(m_uniforms_buffer->map(m_uniform_buffer_offset, 8192));
|
||||
|
||||
//std140 spec demands that arrays be multiples of 16 bytes
|
||||
for (usz i = 0; i < nb_offsets; ++i)
|
||||
{
|
||||
dst[i * 4] = offsets[i * 2];
|
||||
dst[i * 4 + 1] = offsets[i * 2 + 1];
|
||||
}
|
||||
|
||||
memcpy(&dst[510*4], scale, 8);
|
||||
memcpy(&dst[511*4], colors, 16);
|
||||
|
||||
m_uniforms_buffer->unmap();
|
||||
|
||||
m_program->bind_uniform({ m_uniforms_buffer->value, m_uniform_buffer_offset, 8192 }, 0, m_descriptor_set);
|
||||
m_uniform_buffer_offset = (m_uniform_buffer_offset + 8192) % m_uniform_buffer_size;
|
||||
|
||||
vkCmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, m_program->pipeline);
|
||||
m_descriptor_set.bind(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipeline_layout);
|
||||
|
||||
VkDeviceSize zero = 0;
|
||||
vkCmdBindVertexBuffers(cmd, 0, 1, &m_vertex_buffer->value, &zero);
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
text_writer() = default;
|
||||
~text_writer()
|
||||
{
|
||||
if (initialized)
|
||||
{
|
||||
m_vertex_shader.destroy();
|
||||
m_fragment_shader.destroy();
|
||||
|
||||
vkDestroyDescriptorSetLayout(device, m_descriptor_layout, nullptr);
|
||||
vkDestroyPipelineLayout(device, m_pipeline_layout, nullptr);
|
||||
m_descriptor_pool.destroy();
|
||||
}
|
||||
}
|
||||
|
||||
void init(vk::render_device &dev, VkRenderPass render_pass)
|
||||
{
|
||||
ensure(render_pass != VK_NULL_HANDLE);
|
||||
|
||||
//At worst case, 1 char = 16*16*8 bytes (average about 24*8), so ~256K for 128 chars. Allocating 512k for verts
|
||||
//uniform params are 8k in size, allocating for 120 lines (max lines at 4k, one column per row. Can be expanded
|
||||
m_vertex_buffer = std::make_unique<vk::buffer>(dev, 524288, dev.get_memory_mapping().host_visible_coherent,
|
||||
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, 0, VMM_ALLOCATION_POOL_UNDEFINED);
|
||||
m_uniforms_buffer = std::make_unique<vk::buffer>(dev, 983040, dev.get_memory_mapping().host_visible_coherent,
|
||||
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, 0, VMM_ALLOCATION_POOL_UNDEFINED);
|
||||
|
||||
m_render_pass = render_pass;
|
||||
m_uniform_buffer_size = 983040;
|
||||
|
||||
init_descriptor_set(dev);
|
||||
init_program();
|
||||
|
||||
GlyphManager glyph_source;
|
||||
auto points = glyph_source.generate_point_map();
|
||||
const usz buffer_size = points.size() * sizeof(GlyphManager::glyph_point);
|
||||
|
||||
u8* dst = static_cast<u8*>(m_vertex_buffer->map(0, buffer_size));
|
||||
memcpy(dst, points.data(), buffer_size);
|
||||
m_vertex_buffer->unmap();
|
||||
|
||||
m_offsets = glyph_source.get_glyph_offsets();
|
||||
|
||||
device = dev;
|
||||
initialized = true;
|
||||
}
|
||||
|
||||
void print_text(vk::command_buffer &cmd, vk::framebuffer &target, int x, int y, int target_w, int target_h, const std::string &text, std::array<float, 4> color = { 0.3f, 1.f, 0.3f, 1.f })
|
||||
{
|
||||
std::vector<u32> offsets;
|
||||
std::vector<u32> counts;
|
||||
std::vector<float> shader_offsets;
|
||||
char *s = const_cast<char *>(text.c_str());
|
||||
|
||||
//Y is in raster coordinates: convert to bottom-left origin
|
||||
y = (static_cast<int>(target_h / m_scale) - y - 16);
|
||||
|
||||
//Compress [0, w] and [0, h] into range [-1, 1]
|
||||
//Flip Y scaling
|
||||
float scale_x = m_scale * +2.f / target_w;
|
||||
float scale_y = m_scale * -2.f / target_h;
|
||||
|
||||
float base_offset = 0.f;
|
||||
shader_offsets.reserve(text.length() * 2);
|
||||
|
||||
while (*s)
|
||||
{
|
||||
u8 offset = static_cast<u8>(*s);
|
||||
bool to_draw = false; //Can be false for space or unsupported characters
|
||||
|
||||
auto o = m_offsets.find(offset);
|
||||
if (o != m_offsets.end())
|
||||
{
|
||||
if (o->second.second > 0)
|
||||
{
|
||||
to_draw = true;
|
||||
offsets.push_back(o->second.first);
|
||||
counts.push_back(o->second.second);
|
||||
}
|
||||
}
|
||||
|
||||
if (to_draw)
|
||||
{
|
||||
//Generate a scale_offset pair for this entry
|
||||
float offset_x = scale_x * (x + base_offset);
|
||||
offset_x -= 1.f;
|
||||
|
||||
float offset_y = scale_y * y;
|
||||
offset_y += 1.f;
|
||||
|
||||
shader_offsets.push_back(offset_x);
|
||||
shader_offsets.push_back(offset_y);
|
||||
}
|
||||
|
||||
base_offset += 9.f;
|
||||
s++;
|
||||
}
|
||||
|
||||
VkViewport vp{};
|
||||
vp.width = static_cast<f32>(target_w);
|
||||
vp.height = static_cast<f32>(target_h);
|
||||
vp.minDepth = 0.f;
|
||||
vp.maxDepth = 1.f;
|
||||
vkCmdSetViewport(cmd, 0, 1, &vp);
|
||||
|
||||
VkRect2D vs = { {0, 0}, {0u+target_w, 0u+target_h} };
|
||||
vkCmdSetScissor(cmd, 0, 1, &vs);
|
||||
|
||||
//TODO: Add drop shadow if deemed necessary for visibility
|
||||
load_program(cmd, scale_x, scale_y, shader_offsets.data(), counts.size(), color);
|
||||
|
||||
const coordu viewport = { positionu{0u, 0u}, sizeu{target.width(), target.height() } };
|
||||
vk::begin_renderpass(cmd, m_render_pass, target.value, viewport);
|
||||
|
||||
for (uint i = 0; i < counts.size(); ++i)
|
||||
{
|
||||
vkCmdDraw(cmd, counts[i], 1, offsets[i], i);
|
||||
}
|
||||
}
|
||||
|
||||
void set_scale(double scale)
|
||||
{
|
||||
// Restrict scale to 2. The dots are gonna be too sparse otherwise.
|
||||
m_scale = std::min(static_cast<f32>(scale), 2.0f);
|
||||
}
|
||||
};
|
||||
}
|
@ -54,7 +54,6 @@
|
||||
<ClInclude Include="Emu\RSX\GL\GLCompute.h" />
|
||||
<ClInclude Include="Emu\RSX\GL\GLOverlays.h" />
|
||||
<ClInclude Include="Emu\RSX\GL\GLPipelineCompiler.h" />
|
||||
<ClInclude Include="Emu\RSX\GL\GLTextOut.h" />
|
||||
<ClInclude Include="Emu\RSX\GL\GLCommonDecompiler.h" />
|
||||
<ClInclude Include="Emu\RSX\GL\GLFragmentProgram.h" />
|
||||
<ClInclude Include="Emu\RSX\GL\GLGSRender.h" />
|
||||
|
@ -58,7 +58,6 @@
|
||||
<ClInclude Include="Emu\RSX\GL\GLTextureCache.h" />
|
||||
<ClInclude Include="Emu\RSX\GL\GLRenderTargets.h" />
|
||||
<ClInclude Include="Emu\RSX\GL\GLShaderInterpreter.h" />
|
||||
<ClInclude Include="Emu\RSX\GL\GLTextOut.h" />
|
||||
<ClInclude Include="Emu\RSX\GL\GLOverlays.h" />
|
||||
<ClInclude Include="Emu\RSX\GL\GLCompute.h" />
|
||||
<ClInclude Include="Emu\RSX\GL\GLPipelineCompiler.h" />
|
||||
|
@ -36,7 +36,6 @@
|
||||
<ClInclude Include="Emu\RSX\VK\VKResolveHelper.h" />
|
||||
<ClInclude Include="Emu\RSX\VK\VKResourceManager.h" />
|
||||
<ClInclude Include="Emu\RSX\VK\VKShaderInterpreter.h" />
|
||||
<ClInclude Include="Emu\RSX\VK\VKTextOut.h" />
|
||||
<ClInclude Include="Emu\RSX\VK\VKTextureCache.h" />
|
||||
<ClInclude Include="Emu\RSX\VK\vkutils\buffer_object.h" />
|
||||
<ClInclude Include="Emu\RSX\VK\vkutils\chip_class.h" />
|
||||
|
@ -89,7 +89,6 @@
|
||||
<ClInclude Include="Emu\RSX\VK\VKResolveHelper.h" />
|
||||
<ClInclude Include="Emu\RSX\VK\VKResourceManager.h" />
|
||||
<ClInclude Include="Emu\RSX\VK\VKShaderInterpreter.h" />
|
||||
<ClInclude Include="Emu\RSX\VK\VKTextOut.h" />
|
||||
<ClInclude Include="Emu\RSX\VK\VKTextureCache.h" />
|
||||
<ClInclude Include="Emu\RSX\VK\VKVertexProgram.h" />
|
||||
<ClInclude Include="Emu\RSX\VK\VulkanAPI.h" />
|
||||
|
@ -102,6 +102,7 @@
|
||||
<ClCompile Include="Emu\RSX\Overlays\overlay_animated_icon.cpp" />
|
||||
<ClCompile Include="Emu\RSX\Overlays\overlay_controls.cpp" />
|
||||
<ClCompile Include="Emu\RSX\Overlays\overlay_cursor.cpp" />
|
||||
<ClCompile Include="Emu\RSX\Overlays\overlay_debug_overlay.cpp" />
|
||||
<ClCompile Include="Emu\RSX\Overlays\overlay_manager.cpp" />
|
||||
<ClCompile Include="Emu\RSX\Overlays\overlay_media_list_dialog.cpp" />
|
||||
<ClCompile Include="Emu\RSX\Overlays\overlay_osk_panel.cpp" />
|
||||
@ -580,6 +581,7 @@
|
||||
<ClInclude Include="Emu\RSX\Overlays\HomeMenu\overlay_home_menu_settings.h" />
|
||||
<ClInclude Include="Emu\RSX\Overlays\overlay_animated_icon.h" />
|
||||
<ClInclude Include="Emu\RSX\Overlays\overlay_cursor.h" />
|
||||
<ClInclude Include="Emu\RSX\Overlays\overlay_debug_overlay.h" />
|
||||
<ClInclude Include="Emu\RSX\Overlays\overlay_edit_text.hpp" />
|
||||
<ClInclude Include="Emu\RSX\Overlays\overlay_list_view.hpp" />
|
||||
<ClInclude Include="Emu\RSX\Overlays\overlay_loading_icon.hpp" />
|
||||
@ -832,7 +834,6 @@
|
||||
<ClInclude Include="Emu\RSX\Capture\rsx_trace.h" />
|
||||
<ClInclude Include="Emu\RSX\Program\GLSLCommon.h" />
|
||||
<ClInclude Include="Emu\RSX\Common\surface_utils.h" />
|
||||
<ClInclude Include="Emu\RSX\Common\TextGlyphs.h" />
|
||||
<ClInclude Include="Emu\RSX\Common\texture_cache.h" />
|
||||
<ClInclude Include="Emu\RSX\Common\texture_cache_checker.h" />
|
||||
<ClInclude Include="Emu\RSX\Common\texture_cache_predictor.h" />
|
||||
|
@ -1177,6 +1177,9 @@
|
||||
<ClCompile Include="Crypto\unzip.cpp">
|
||||
<Filter>Crypto</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Emu\RSX\Overlays\overlay_debug_overlay.cpp">
|
||||
<Filter>Emu\GPU\RSX\Overlays</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="Crypto\aes.h">
|
||||
@ -1773,9 +1776,6 @@
|
||||
<ClInclude Include="Emu\RSX\gcm_printing.h">
|
||||
<Filter>Emu\GPU\RSX</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Emu\RSX\Common\TextGlyphs.h">
|
||||
<Filter>Emu\GPU\RSX\Common</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\Utilities\mutex.h">
|
||||
<Filter>Utilities</Filter>
|
||||
</ClInclude>
|
||||
@ -2398,6 +2398,9 @@
|
||||
<ClInclude Include="util\serialization_ext.hpp">
|
||||
<Filter>Emu</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Emu\RSX\Overlays\overlay_debug_overlay.h">
|
||||
<Filter>Emu\GPU\RSX\Overlays</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="Emu\RSX\Program\GLSLSnippets\GPUDeswizzle.glsl">
|
||||
|
@ -50,6 +50,7 @@ namespace audio
|
||||
namespace rsx::overlays
|
||||
{
|
||||
extern void reset_performance_overlay();
|
||||
extern void reset_debug_overlay();
|
||||
}
|
||||
|
||||
/** Emu.Init() wrapper for user management */
|
||||
@ -91,6 +92,7 @@ void main_application::OnEmuSettingsChange()
|
||||
audio::configure_audio();
|
||||
audio::configure_rsxaudio();
|
||||
rsx::overlays::reset_performance_overlay();
|
||||
rsx::overlays::reset_debug_overlay();
|
||||
}
|
||||
|
||||
/** RPCS3 emulator has functions it desires to call from the GUI at times. Initialize them in here. */
|
||||
|
@ -756,11 +756,6 @@ int gs_frame::client_height()
|
||||
return height() * devicePixelRatio();
|
||||
}
|
||||
|
||||
double gs_frame::client_device_pixel_ratio() const
|
||||
{
|
||||
return devicePixelRatio();
|
||||
}
|
||||
|
||||
void gs_frame::flip(draw_context_t, bool /*skip_frame*/)
|
||||
{
|
||||
static Timer fps_t;
|
||||
|
@ -89,7 +89,6 @@ protected:
|
||||
void flip(draw_context_t context, bool skip_frame = false) override;
|
||||
int client_width() override;
|
||||
int client_height() override;
|
||||
double client_device_pixel_ratio() const override;
|
||||
|
||||
bool event(QEvent* ev) override;
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user