From 396b7c2978498712f6e6eea7f353408f3c33c147 Mon Sep 17 00:00:00 2001 From: Stenzek Date: Sat, 19 Jan 2019 23:54:35 +1000 Subject: [PATCH 01/15] OGL: Invalidate tracked state when calling ResetAPIState() Due to the current design, any of the GL state can be mutated after calling this function, so we can't assume that the tracked state will match if we call SetPipeline() after ResetAPIState(). --- Source/Core/VideoBackends/OGL/Render.cpp | 12 +++++----- Source/Core/VideoBackends/OGL/Render.h | 6 ++--- Source/Core/VideoCommon/RenderState.cpp | 28 ++++++++++++++++++++++++ Source/Core/VideoCommon/RenderState.h | 4 ++++ 4 files changed, 42 insertions(+), 8 deletions(-) diff --git a/Source/Core/VideoBackends/OGL/Render.cpp b/Source/Core/VideoBackends/OGL/Render.cpp index 186b6a7da5..76483b3d5b 100644 --- a/Source/Core/VideoBackends/OGL/Render.cpp +++ b/Source/Core/VideoBackends/OGL/Render.cpp @@ -357,7 +357,10 @@ Renderer::Renderer(std::unique_ptr main_gl_context) : ::Renderer(static_cast(std::max(main_gl_context->GetBackBufferWidth(), 1u)), static_cast(std::max(main_gl_context->GetBackBufferHeight(), 1u)), AbstractTextureFormat::RGBA8), - m_main_gl_context(std::move(main_gl_context)) + m_main_gl_context(std::move(main_gl_context)), + m_current_rasterization_state(RenderState::GetInvalidRasterizationState()), + m_current_depth_state(RenderState::GetInvalidDepthState()), + m_current_blend_state(RenderState::GetInvalidBlendingState()) { bool bSuccess = true; @@ -1585,6 +1588,9 @@ void Renderer::ResetAPIState() } glDepthMask(GL_FALSE); glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); + m_current_rasterization_state = RenderState::GetInvalidRasterizationState(); + m_current_depth_state = RenderState::GetInvalidDepthState(); + m_current_blend_state = RenderState::GetInvalidBlendingState(); } void Renderer::RestoreAPIState() @@ -1603,10 +1609,6 @@ void Renderer::RestoreAPIState() } BPFunctions::SetScissor(); BPFunctions::SetViewport(); - - ApplyRasterizationState(m_current_rasterization_state, true); - ApplyDepthState(m_current_depth_state, true); - ApplyBlendingState(m_current_blend_state, true); } void Renderer::ApplyRasterizationState(const RasterizationState state, bool force) diff --git a/Source/Core/VideoBackends/OGL/Render.h b/Source/Core/VideoBackends/OGL/Render.h index f520c6faa4..78f410bb52 100644 --- a/Source/Core/VideoBackends/OGL/Render.h +++ b/Source/Core/VideoBackends/OGL/Render.h @@ -168,8 +168,8 @@ private: std::unique_ptr m_main_gl_context; std::array m_bound_textures{}; const OGLPipeline* m_graphics_pipeline = nullptr; - RasterizationState m_current_rasterization_state = {}; - DepthState m_current_depth_state = {}; - BlendingState m_current_blend_state = {}; + RasterizationState m_current_rasterization_state; + DepthState m_current_depth_state; + BlendingState m_current_blend_state; }; } // namespace OGL diff --git a/Source/Core/VideoCommon/RenderState.cpp b/Source/Core/VideoCommon/RenderState.cpp index 5cad8c2584..b61b031b04 100644 --- a/Source/Core/VideoCommon/RenderState.cpp +++ b/Source/Core/VideoCommon/RenderState.cpp @@ -199,6 +199,13 @@ SamplerState& SamplerState::operator=(const SamplerState& rhs) namespace RenderState { +RasterizationState GetInvalidRasterizationState() +{ + RasterizationState state; + state.hex = UINT32_C(0xFFFFFFFF); + return state; +} + RasterizationState GetNoCullRasterizationState() { RasterizationState state = {}; @@ -206,6 +213,13 @@ RasterizationState GetNoCullRasterizationState() return state; } +DepthState GetInvalidDepthState() +{ + DepthState state; + state.hex = UINT32_C(0xFFFFFFFF); + return state; +} + DepthState GetNoDepthTestingDepthStencilState() { DepthState state = {}; @@ -215,6 +229,13 @@ DepthState GetNoDepthTestingDepthStencilState() return state; } +BlendingState GetInvalidBlendingState() +{ + BlendingState state; + state.hex = UINT32_C(0xFFFFFFFF); + return state; +} + BlendingState GetNoBlendingBlendState() { BlendingState state = {}; @@ -230,6 +251,13 @@ BlendingState GetNoBlendingBlendState() return state; } +SamplerState GetInvalidSamplerState() +{ + SamplerState state; + state.hex = UINT64_C(0xFFFFFFFFFFFFFFFF); + return state; +} + SamplerState GetPointSamplerState() { SamplerState state = {}; diff --git a/Source/Core/VideoCommon/RenderState.h b/Source/Core/VideoCommon/RenderState.h index d72c2d3984..5cd0ba7470 100644 --- a/Source/Core/VideoCommon/RenderState.h +++ b/Source/Core/VideoCommon/RenderState.h @@ -113,9 +113,13 @@ union SamplerState namespace RenderState { +RasterizationState GetInvalidRasterizationState(); RasterizationState GetNoCullRasterizationState(); +DepthState GetInvalidDepthState(); DepthState GetNoDepthTestingDepthStencilState(); +BlendingState GetInvalidBlendingState(); BlendingState GetNoBlendingBlendState(); +SamplerState GetInvalidSamplerState(); SamplerState GetPointSamplerState(); SamplerState GetLinearSamplerState(); } From d1868d9475db2ec99314a2f7f192a63fc40bf962 Mon Sep 17 00:00:00 2001 From: Stenzek Date: Wed, 10 Oct 2018 00:57:52 +1100 Subject: [PATCH 02/15] RenderBase: Implement imgui rendering --- Source/Core/VideoBackends/D3D/Render.cpp | 1 + Source/Core/VideoBackends/OGL/Render.cpp | 1 + Source/Core/VideoBackends/Vulkan/Renderer.cpp | 6 +- Source/Core/VideoCommon/RenderBase.cpp | 256 +++++++++++++++++- Source/Core/VideoCommon/RenderBase.h | 19 ++ Source/Core/VideoCommon/VideoCommon.vcxproj | 5 +- 6 files changed, 284 insertions(+), 4 deletions(-) diff --git a/Source/Core/VideoBackends/D3D/Render.cpp b/Source/Core/VideoBackends/D3D/Render.cpp index 93098f53fe..43dd44f60f 100644 --- a/Source/Core/VideoBackends/D3D/Render.cpp +++ b/Source/Core/VideoBackends/D3D/Render.cpp @@ -599,6 +599,7 @@ void Renderer::SwapImpl(AbstractTexture* texture, const EFBRectangle& xfb_region Renderer::DrawDebugText(); OSD::DrawMessages(); + DrawImGui(); g_texture_cache->Cleanup(frameCount); diff --git a/Source/Core/VideoBackends/OGL/Render.cpp b/Source/Core/VideoBackends/OGL/Render.cpp index 76483b3d5b..e967ae6a75 100644 --- a/Source/Core/VideoBackends/OGL/Render.cpp +++ b/Source/Core/VideoBackends/OGL/Render.cpp @@ -1455,6 +1455,7 @@ void Renderer::SwapImpl(AbstractTexture* texture, const EFBRectangle& xfb_region glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); DrawDebugText(); OSD::DrawMessages(); + DrawImGui(); // Swap the back and front buffers, presenting the image. m_main_gl_context->Swap(); diff --git a/Source/Core/VideoBackends/Vulkan/Renderer.cpp b/Source/Core/VideoBackends/Vulkan/Renderer.cpp index 718bdec8d7..509269368d 100644 --- a/Source/Core/VideoBackends/Vulkan/Renderer.cpp +++ b/Source/Core/VideoBackends/Vulkan/Renderer.cpp @@ -702,11 +702,13 @@ void Renderer::DrawScreen(VKTexture* xfb_texture, const EFBRectangle& xfb_region xfb_texture->GetRawTexIdentifier()); // Draw OSD - Util::SetViewportAndScissor(g_command_buffer_mgr->GetCurrentCommandBuffer(), 0, 0, - backbuffer->GetWidth(), backbuffer->GetHeight()); + SetViewport(0.0f, 0.0f, static_cast(backbuffer->GetWidth()), + static_cast(backbuffer->GetHeight()), 0.0f, 1.0f); DrawDebugText(); OSD::DoCallbacks(OSD::CallbackType::OnFrame); OSD::DrawMessages(); + StateTracker::GetInstance()->SetPendingRebind(); + DrawImGui(); // End drawing to backbuffer StateTracker::GetInstance()->EndRenderPass(); diff --git a/Source/Core/VideoCommon/RenderBase.cpp b/Source/Core/VideoCommon/RenderBase.cpp index 3c8c5d5a82..d30a7ccac3 100644 --- a/Source/Core/VideoCommon/RenderBase.cpp +++ b/Source/Core/VideoCommon/RenderBase.cpp @@ -21,6 +21,8 @@ #include #include +#include "imgui.h" + #include "Common/Assert.h" #include "Common/CommonTypes.h" #include "Common/Config/Config.h" @@ -97,7 +99,7 @@ Renderer::~Renderer() = default; bool Renderer::Initialize() { - return true; + return InitializeImGui(); } void Renderer::Shutdown() @@ -105,6 +107,7 @@ void Renderer::Shutdown() // First stop any framedumping, which might need to dump the last xfb frame. This process // can require additional graphics sub-systems so it needs to be done first ShutdownFrameDumping(); + ShutdownImGui(); } void Renderer::RenderToXFB(u32 xfbAddr, const EFBRectangle& sourceRc, u32 fbStride, u32 fbHeight, @@ -638,6 +641,251 @@ void Renderer::RecordVideoMemory() texMem); } +static std::string GenerateImGuiVertexShader() +{ + const APIType api_type = g_ActiveConfig.backend_info.api_type; + std::stringstream ss; + + // Uniform buffer contains the viewport size, and we transform in the vertex shader. + if (api_type == APIType::D3D) + ss << "cbuffer PSBlock : register(b0) {\n"; + else if (api_type == APIType::OpenGL) + ss << "UBO_BINDING(std140, 1) uniform PSBlock {\n"; + else if (api_type == APIType::Vulkan) + ss << "UBO_BINDING(std140, 1) uniform PSBlock {\n"; + ss << "float2 u_rcp_viewport_size_mul2;\n"; + ss << "};\n"; + + if (api_type == APIType::D3D) + { + ss << "void main(in float2 rawpos : POSITION,\n" + << " in float2 rawtex0 : TEXCOORD,\n" + << " in float4 rawcolor0 : COLOR,\n" + << " out float2 frag_uv : TEXCOORD,\n" + << " out float4 frag_color : COLOR,\n" + << " out float4 out_pos : SV_Position)\n"; + } + else + { + ss << "ATTRIBUTE_LOCATION(" << SHADER_POSITION_ATTRIB << ") in float2 rawpos;\n" + << "ATTRIBUTE_LOCATION(" << SHADER_TEXTURE0_ATTRIB << ") in float2 rawtex0;\n" + << "ATTRIBUTE_LOCATION(" << SHADER_COLOR0_ATTRIB << ") in float4 rawcolor0;\n" + << "VARYING_LOCATION(0) out float2 frag_uv;\n" + << "VARYING_LOCATION(1) out float4 frag_color;\n" + << "void main()\n"; + } + + ss << "{\n" + << " frag_uv = rawtex0;\n" + << " frag_color = rawcolor0;\n"; + + ss << " " << (api_type == APIType::D3D ? "out_pos" : "gl_Position") + << "= float4(rawpos.x * u_rcp_viewport_size_mul2.x - 1.0, 1.0 - rawpos.y * " + "u_rcp_viewport_size_mul2.y, 0.0, 1.0);\n"; + + // Clip-space is flipped in Vulkan + if (api_type == APIType::Vulkan) + ss << " gl_Position.y = -gl_Position.y;\n"; + + ss << "}\n"; + return ss.str(); +} + +static std::string GenerateImGuiPixelShader() +{ + const APIType api_type = g_ActiveConfig.backend_info.api_type; + + std::stringstream ss; + if (api_type == APIType::D3D) + { + ss << "Texture2DArray tex0 : register(t0);\n" + << "SamplerState samp0 : register(s0);\n" + << "void main(in float2 frag_uv : TEXCOORD,\n" + << " in float4 frag_color : COLOR,\n" + << " out float4 ocol0 : SV_Target)\n"; + } + else + { + ss << "SAMPLER_BINDING(0) uniform sampler2DArray samp0;\n" + << "VARYING_LOCATION(0) in float2 frag_uv; \n" + << "VARYING_LOCATION(1) in float4 frag_color;\n" + << "FRAGMENT_OUTPUT_LOCATION(0) out float4 ocol0;\n" + << "void main()\n"; + } + + ss << "{\n"; + + if (api_type == APIType::D3D) + ss << " ocol0 = tex0.Sample(samp0, float3(frag_uv, 0.0)) * frag_color;\n"; + else + ss << " ocol0 = texture(samp0, float3(frag_uv, 0.0)) * frag_color;\n"; + + ss << "}\n"; + + return ss.str(); +} + +bool Renderer::InitializeImGui() +{ + if (!ImGui::CreateContext()) + { + PanicAlert("Creating ImGui context failed"); + return false; + } + + // Don't create an ini file. TODO: Do we want this in the future? + ImGui::GetIO().IniFilename = nullptr; + + PortableVertexDeclaration vdecl = {}; + vdecl.position = {VAR_FLOAT, 2, offsetof(ImDrawVert, pos), true, false}; + vdecl.texcoords[0] = {VAR_FLOAT, 2, offsetof(ImDrawVert, uv), true, false}; + vdecl.colors[0] = {VAR_UNSIGNED_BYTE, 4, offsetof(ImDrawVert, col), true, false}; + vdecl.stride = sizeof(ImDrawVert); + m_imgui_vertex_format = g_vertex_manager->CreateNativeVertexFormat(vdecl); + if (!m_imgui_vertex_format) + { + PanicAlert("Failed to create imgui vertex format"); + return false; + } + + const std::string vertex_shader_source = GenerateImGuiVertexShader(); + const std::string pixel_shader_source = GenerateImGuiPixelShader(); + std::unique_ptr vertex_shader = CreateShaderFromSource( + ShaderStage::Vertex, vertex_shader_source.c_str(), vertex_shader_source.size()); + std::unique_ptr pixel_shader = CreateShaderFromSource( + ShaderStage::Pixel, pixel_shader_source.c_str(), pixel_shader_source.size()); + if (!vertex_shader || !pixel_shader) + { + PanicAlert("Failed to compile imgui shaders"); + return false; + } + + AbstractPipelineConfig pconfig = {}; + pconfig.vertex_format = m_imgui_vertex_format.get(); + pconfig.vertex_shader = vertex_shader.get(); + pconfig.pixel_shader = pixel_shader.get(); + pconfig.rasterization_state.hex = RenderState::GetNoCullRasterizationState().hex; + pconfig.rasterization_state.primitive = PrimitiveType::Triangles; + pconfig.depth_state.hex = RenderState::GetNoDepthTestingDepthStencilState().hex; + pconfig.blending_state.hex = RenderState::GetNoBlendingBlendState().hex; + pconfig.blending_state.blendenable = true; + pconfig.blending_state.srcfactor = BlendMode::SRCALPHA; + pconfig.blending_state.dstfactor = BlendMode::INVSRCALPHA; + pconfig.blending_state.srcfactoralpha = BlendMode::ZERO; + pconfig.blending_state.dstfactoralpha = BlendMode::ONE; + pconfig.framebuffer_state.color_texture_format = m_backbuffer_format; + pconfig.framebuffer_state.depth_texture_format = AbstractTextureFormat::Undefined; + pconfig.framebuffer_state.samples = 1; + pconfig.framebuffer_state.per_sample_shading = false; + pconfig.usage = AbstractPipelineUsage::Utility; + m_imgui_pipeline = g_renderer->CreatePipeline(pconfig); + if (!m_imgui_pipeline) + { + PanicAlert("Failed to create imgui pipeline"); + return false; + } + + // Font texture(s). + { + ImGuiIO& io = ImGui::GetIO(); + u8* font_tex_pixels; + int font_tex_width, font_tex_height; + io.Fonts->GetTexDataAsRGBA32(&font_tex_pixels, &font_tex_width, &font_tex_height); + + TextureConfig font_tex_config(font_tex_width, font_tex_height, 1, 1, 1, + AbstractTextureFormat::RGBA8, false); + std::unique_ptr font_tex = CreateTexture(font_tex_config); + if (!font_tex) + { + PanicAlert("Failed to create imgui texture"); + return false; + } + font_tex->Load(0, font_tex_width, font_tex_height, font_tex_width, font_tex_pixels, + sizeof(u32) * font_tex_width * font_tex_height); + + io.Fonts->TexID = font_tex.get(); + + m_imgui_textures.push_back(std::move(font_tex)); + } + + m_imgui_last_frame_time = Common::Timer::GetTimeUs(); + BeginImGuiFrame(); + return true; +} + +void Renderer::ShutdownImGui() +{ + ImGui::EndFrame(); + ImGui::DestroyContext(); + m_imgui_pipeline.reset(); + m_imgui_vertex_format.reset(); + m_imgui_textures.clear(); +} + +void Renderer::BeginImGuiFrame() +{ + const u64 current_time_us = Common::Timer::GetTimeUs(); + const u64 time_diff_us = current_time_us - m_imgui_last_frame_time; + const float time_diff_secs = static_cast(time_diff_us / 1000000.0); + m_imgui_last_frame_time = current_time_us; + + // Update I/O with window dimensions. + ImGuiIO& io = ImGui::GetIO(); + io.DisplaySize = + ImVec2(static_cast(m_backbuffer_width), static_cast(m_backbuffer_height)); + io.DeltaTime = time_diff_secs; + + ImGui::NewFrame(); +} + +void Renderer::DrawImGui() +{ + ImDrawData* draw_data = ImGui::GetDrawData(); + if (!draw_data) + return; + + // Uniform buffer for draws. + struct ImGuiUbo + { + float u_rcp_viewport_size_mul2[2]; + float padding[2]; + }; + ImGuiUbo ubo = {{1.0f / m_backbuffer_width * 2.0f, 1.0f / m_backbuffer_height * 2.0f}}; + + // Set up common state for drawing. + g_vertex_manager->UploadUtilityUniforms(&ubo, sizeof(ubo)); + SetSamplerState(0, RenderState::GetPointSamplerState()); + + for (int i = 0; i < draw_data->CmdListsCount; i++) + { + const ImDrawList* cmdlist = draw_data->CmdLists[i]; + if (cmdlist->VtxBuffer.empty() || cmdlist->IdxBuffer.empty()) + return; + + u32 base_vertex, base_index; + g_vertex_manager->UploadUtilityVertices(cmdlist->VtxBuffer.Data, sizeof(ImDrawVert), + cmdlist->VtxBuffer.Size, cmdlist->IdxBuffer.Data, + cmdlist->IdxBuffer.Size, &base_vertex, &base_index); + + for (const ImDrawCmd& cmd : cmdlist->CmdBuffer) + { + if (cmd.UserCallback) + { + cmd.UserCallback(cmdlist, &cmd); + continue; + } + + SetPipeline(m_imgui_pipeline.get()); + SetScissorRect(MathUtil::Rectangle( + static_cast(cmd.ClipRect.x), static_cast(cmd.ClipRect.y), + static_cast(cmd.ClipRect.z), static_cast(cmd.ClipRect.w))); + SetTexture(0, reinterpret_cast(cmd.TextureId)); + DrawIndexed(base_index, cmd.ElemCount, base_vertex); + base_index += cmd.ElemCount; + } + } +} + void Renderer::Swap(u32 xfbAddr, u32 fbWidth, u32 fbStride, u32 fbHeight, const EFBRectangle& rc, u64 ticks) { @@ -705,6 +953,10 @@ void Renderer::Swap(u32 xfbAddr, u32 fbWidth, u32 fbStride, u32 fbHeight, const // with the loader, and it has not been unmapped yet. Force a pipeline flush to avoid this. g_vertex_manager->Flush(); + // Draw any imgui overlays we have. Note that "draw" here means "create commands", the actual + // draw calls don't get issued until DrawImGui is called, which happens in SwapImpl. + ImGui::Render(); + // TODO: merge more generic parts into VideoCommon { std::lock_guard guard(m_swap_mutex); @@ -745,6 +997,8 @@ void Renderer::Swap(u32 xfbAddr, u32 fbWidth, u32 fbStride, u32 fbHeight, const // rate and not waiting for vblank. Otherwise, we'd end up with a huge list of pending copies. g_texture_cache->FlushEFBCopies(); + BeginImGuiFrame(); + Core::Callback_VideoCopiedToXFB(true); } else diff --git a/Source/Core/VideoCommon/RenderBase.h b/Source/Core/VideoCommon/RenderBase.h index 4e9c60efae..b232d2c61f 100644 --- a/Source/Core/VideoCommon/RenderBase.h +++ b/Source/Core/VideoCommon/RenderBase.h @@ -40,6 +40,7 @@ class AbstractPipeline; class AbstractShader; class AbstractTexture; class AbstractStagingTexture; +class NativeVertexFormat; class PostProcessingShaderImplementation; struct TextureConfig; struct ComputePipelineConfig; @@ -166,6 +167,9 @@ public: void SaveScreenshot(const std::string& filename, bool wait_for_completion); void DrawDebugText(); + // ImGui initialization depends on being able to create textures and pipelines, so do it last. + bool InitializeImGui(); + virtual void RenderText(const std::string& text, int left, int top, u32 color) = 0; virtual void ClearScreen(const EFBRectangle& rc, bool colorEnable, bool alphaEnable, bool zEnable, @@ -208,6 +212,15 @@ protected: void CheckFifoRecording(); void RecordVideoMemory(); + // Renders ImGui windows to the currently-bound framebuffer. + void DrawImGui(); + + // Destroys all ImGui GPU resources, must do before shutdown. + void ShutdownImGui(); + + // Sets up ImGui state for the next frame. + void BeginImGuiFrame(); + // TODO: Remove the width/height parameters once we make the EFB an abstract framebuffer. const AbstractFramebuffer* m_current_framebuffer = nullptr; u32 m_current_framebuffer_width = 1; @@ -241,6 +254,12 @@ protected: u32 m_last_host_config_bits = 0; u32 m_last_efb_multisamples = 1; + // ImGui resources. + std::unique_ptr m_imgui_vertex_format; + std::vector> m_imgui_textures; + std::unique_ptr m_imgui_pipeline; + u64 m_imgui_last_frame_time; + private: void RunFrameDumps(); std::tuple CalculateOutputDimensions(int width, int height); diff --git a/Source/Core/VideoCommon/VideoCommon.vcxproj b/Source/Core/VideoCommon/VideoCommon.vcxproj index 00ceae25c7..e2a8d60b1b 100644 --- a/Source/Core/VideoCommon/VideoCommon.vcxproj +++ b/Source/Core/VideoCommon/VideoCommon.vcxproj @@ -183,8 +183,11 @@ {2e6c348c-c75c-4d94-8d1e-9c1fcbf3efe4} + + {4c3b2264-ea73-4a7b-9cfe-65b0fd635ebb} + - + \ No newline at end of file From 600d1fc0bc884644127057fa8cce5d31cbaef143 Mon Sep 17 00:00:00 2001 From: Stenzek Date: Wed, 10 Oct 2018 01:26:31 +1100 Subject: [PATCH 03/15] Renderer: Use imgui for drawing debug text and OSD --- Source/Android/jni/MainAndroid.cpp | 4 +- Source/Core/DolphinQt/HotkeyScheduler.cpp | 90 ++++++--- Source/Core/VideoBackends/D3D/Render.cpp | 4 - Source/Core/VideoBackends/OGL/Render.cpp | 7 - .../VideoBackends/Software/SWRenderer.cpp | 5 - Source/Core/VideoBackends/Vulkan/Renderer.cpp | 3 - Source/Core/VideoCommon/OnScreenDisplay.cpp | 100 ++++++---- Source/Core/VideoCommon/OnScreenDisplay.h | 22 --- Source/Core/VideoCommon/RenderBase.cpp | 177 +++++------------- Source/Core/VideoCommon/RenderBase.h | 16 -- Source/Core/VideoCommon/Statistics.cpp | 153 ++++++++------- Source/Core/VideoCommon/Statistics.h | 5 +- Source/Core/VideoCommon/VideoBackendBase.cpp | 6 - 13 files changed, 268 insertions(+), 324 deletions(-) diff --git a/Source/Android/jni/MainAndroid.cpp b/Source/Android/jni/MainAndroid.cpp index 686053496e..441080e57a 100644 --- a/Source/Android/jni/MainAndroid.cpp +++ b/Source/Android/jni/MainAndroid.cpp @@ -595,9 +595,6 @@ static void Run(const std::vector& paths, bool first_open, ASSERT(!paths.empty()); __android_log_print(ANDROID_LOG_INFO, DOLPHIN_TAG, "Running : %s", paths[0].c_str()); - // Install our callbacks - OSD::AddCallback(OSD::CallbackType::Shutdown, ButtonManager::Shutdown); - RegisterMsgAlertHandler(&MsgAlert); Common::AndroidSetReportHandler(&ReportSend); DolphinAnalytics::AndroidSetGetValFunc(&GetAnalyticValue); @@ -639,6 +636,7 @@ static void Run(const std::vector& paths, bool first_open, } Core::Shutdown(); + ButtonManager::Shutdown(); UICommon::Shutdown(); guard.unlock(); diff --git a/Source/Core/DolphinQt/HotkeyScheduler.cpp b/Source/Core/DolphinQt/HotkeyScheduler.cpp index cd5c51822f..7cab2eb8a7 100644 --- a/Source/Core/DolphinQt/HotkeyScheduler.cpp +++ b/Source/Core/DolphinQt/HotkeyScheduler.cpp @@ -5,6 +5,7 @@ #include "DolphinQt/HotkeyScheduler.h" #include +#include #include #include @@ -26,6 +27,7 @@ #include "InputCommon/ControllerInterface/ControllerInterface.h" +#include "VideoCommon/OnScreenDisplay.h" #include "VideoCommon/RenderBase.h" #include "VideoCommon/VertexShaderManager.h" #include "VideoCommon/VideoConfig.h" @@ -286,43 +288,62 @@ void HotkeyScheduler::Run() else if (IsHotkey(HK_NEXT_GAME_WIIMOTE_PROFILE_4)) m_profile_cycler.NextWiimoteProfileForGame(3); - const auto show_msg = [](OSDMessage message) { - if (g_renderer) - g_renderer->ShowOSDMessage(message); + auto ShowVolume = []() { + OSD::AddMessage(std::string("Volume: ") + + (SConfig::GetInstance().m_IsMuted ? + "Muted" : + std::to_string(SConfig::GetInstance().m_Volume)) + + "%"); }; // Volume if (IsHotkey(HK_VOLUME_DOWN)) { - show_msg(OSDMessage::VolumeChanged); settings.DecreaseVolume(3); + ShowVolume(); } if (IsHotkey(HK_VOLUME_UP)) { - show_msg(OSDMessage::VolumeChanged); settings.IncreaseVolume(3); + ShowVolume(); } if (IsHotkey(HK_VOLUME_TOGGLE_MUTE)) { - show_msg(OSDMessage::VolumeChanged); AudioCommon::ToggleMuteVolume(); + ShowVolume(); } // Graphics const auto efb_scale = Config::Get(Config::GFX_EFB_SCALE); + auto ShowEFBScale = []() { + switch (Config::Get(Config::GFX_EFB_SCALE)) + { + case EFB_SCALE_AUTO_INTEGRAL: + OSD::AddMessage("Internal Resolution: Auto (integral)"); + break; + case 1: + OSD::AddMessage("Internal Resolution: Native"); + break; + default: + OSD::AddMessage("Internal Resolution: %dx", g_Config.iEFBScale); + break; + } + }; if (IsHotkey(HK_INCREASE_IR)) { - show_msg(OSDMessage::IRChanged); Config::SetCurrent(Config::GFX_EFB_SCALE, efb_scale + 1); + ShowEFBScale(); } if (IsHotkey(HK_DECREASE_IR)) { - show_msg(OSDMessage::IRChanged); if (efb_scale > EFB_SCALE_AUTO_INTEGRAL) + { Config::SetCurrent(Config::GFX_EFB_SCALE, efb_scale - 1); + ShowEFBScale(); + } } if (IsHotkey(HK_TOGGLE_CROP)) @@ -330,34 +351,55 @@ void HotkeyScheduler::Run() if (IsHotkey(HK_TOGGLE_AR)) { - show_msg(OSDMessage::ARToggled); const int aspect_ratio = (static_cast(Config::Get(Config::GFX_ASPECT_RATIO)) + 1) & 3; Config::SetCurrent(Config::GFX_ASPECT_RATIO, static_cast(aspect_ratio)); + switch (static_cast(aspect_ratio)) + { + case AspectMode::Stretch: + OSD::AddMessage("Stretch"); + break; + case AspectMode::Analog: + OSD::AddMessage("Force 4:3"); + break; + case AspectMode::AnalogWide: + OSD::AddMessage("Force 16:9"); + break; + case AspectMode::Auto: + default: + OSD::AddMessage("Auto"); + break; + } } if (IsHotkey(HK_TOGGLE_EFBCOPIES)) { - show_msg(OSDMessage::EFBCopyToggled); - Config::SetCurrent(Config::GFX_HACK_SKIP_EFB_COPY_TO_RAM, - !Config::Get(Config::GFX_HACK_SKIP_EFB_COPY_TO_RAM)); + const bool new_value = !Config::Get(Config::GFX_HACK_SKIP_EFB_COPY_TO_RAM); + Config::SetCurrent(Config::GFX_HACK_SKIP_EFB_COPY_TO_RAM, new_value); + OSD::AddMessage(StringFromFormat("Copy EFB: %s", new_value ? "to Texture" : "to RAM")); } + auto ShowXFBCopies = []() { + OSD::AddMessage(StringFromFormat( + "Copy XFB: %s%s", Config::Get(Config::GFX_HACK_IMMEDIATE_XFB) ? " (Immediate)" : "", + Config::Get(Config::GFX_HACK_SKIP_XFB_COPY_TO_RAM) ? "to Texture" : "to RAM")); + }; + if (IsHotkey(HK_TOGGLE_XFBCOPIES)) { - show_msg(OSDMessage::XFBChanged); Config::SetCurrent(Config::GFX_HACK_SKIP_XFB_COPY_TO_RAM, !Config::Get(Config::GFX_HACK_SKIP_XFB_COPY_TO_RAM)); + ShowXFBCopies(); } if (IsHotkey(HK_TOGGLE_IMMEDIATE_XFB)) { - show_msg(OSDMessage::XFBChanged); - Config::SetCurrent(Config::GFX_HACK_IMMEDIATE_XFB, !Config::Get(Config::GFX_HACK_IMMEDIATE_XFB)); + ShowXFBCopies(); } if (IsHotkey(HK_TOGGLE_FOG)) { - show_msg(OSDMessage::FogToggled); - Config::SetCurrent(Config::GFX_DISABLE_FOG, !Config::Get(Config::GFX_DISABLE_FOG)); + const bool new_value = !Config::Get(Config::GFX_DISABLE_FOG); + Config::SetCurrent(Config::GFX_DISABLE_FOG, new_value); + OSD::AddMessage(StringFromFormat("Fog: %s", new_value ? "Enabled" : "Disabled")); } if (IsHotkey(HK_TOGGLE_DUMPTEXTURES)) @@ -368,22 +410,28 @@ void HotkeyScheduler::Run() Core::SetIsThrottlerTempDisabled(IsHotkey(HK_TOGGLE_THROTTLE, true)); + auto ShowEmulationSpeed = []() { + OSD::AddMessage( + SConfig::GetInstance().m_EmulationSpeed <= 0 ? + "Speed Limit: Unlimited" : + StringFromFormat("Speed Limit: %li%%", + std::lround(SConfig::GetInstance().m_EmulationSpeed * 100.f))); + }; + if (IsHotkey(HK_DECREASE_EMULATION_SPEED)) { - show_msg(OSDMessage::SpeedChanged); - auto speed = SConfig::GetInstance().m_EmulationSpeed - 0.1; speed = (speed <= 0 || (speed >= 0.95 && speed <= 1.05)) ? 1.0 : speed; SConfig::GetInstance().m_EmulationSpeed = speed; + ShowEmulationSpeed(); } if (IsHotkey(HK_INCREASE_EMULATION_SPEED)) { - show_msg(OSDMessage::SpeedChanged); - auto speed = SConfig::GetInstance().m_EmulationSpeed + 0.1; speed = (speed >= 0.95 && speed <= 1.05) ? 1.0 : speed; SConfig::GetInstance().m_EmulationSpeed = speed; + ShowEmulationSpeed(); } // Slot Saving / Loading diff --git a/Source/Core/VideoBackends/D3D/Render.cpp b/Source/Core/VideoBackends/D3D/Render.cpp index 43dd44f60f..87190a6d2b 100644 --- a/Source/Core/VideoBackends/D3D/Render.cpp +++ b/Source/Core/VideoBackends/D3D/Render.cpp @@ -595,10 +595,6 @@ void Renderer::SwapImpl(AbstractTexture* texture, const EFBRectangle& xfb_region D3D11_VIEWPORT vp = CD3D11_VIEWPORT(0.0f, 0.0f, static_cast(m_backbuffer_width), static_cast(m_backbuffer_height)); D3D::context->RSSetViewports(1, &vp); - - Renderer::DrawDebugText(); - - OSD::DrawMessages(); DrawImGui(); g_texture_cache->Cleanup(frameCount); diff --git a/Source/Core/VideoBackends/OGL/Render.cpp b/Source/Core/VideoBackends/OGL/Render.cpp index e967ae6a75..c857cce083 100644 --- a/Source/Core/VideoBackends/OGL/Render.cpp +++ b/Source/Core/VideoBackends/OGL/Render.cpp @@ -1424,9 +1424,6 @@ void Renderer::SwapImpl(AbstractTexture* texture, const EFBRectangle& xfb_region ResetAPIState(); - // Do our OSD callbacks - OSD::DoCallbacks(OSD::CallbackType::OnFrame); - // Check if we need to render to a new surface. CheckForSurfaceChange(); CheckForSurfaceResize(); @@ -1451,10 +1448,6 @@ void Renderer::SwapImpl(AbstractTexture* texture, const EFBRectangle& xfb_region // Render OSD messages. glViewport(0, 0, m_backbuffer_width, m_backbuffer_height); - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - DrawDebugText(); - OSD::DrawMessages(); DrawImGui(); // Swap the back and front buffers, presenting the image. diff --git a/Source/Core/VideoBackends/Software/SWRenderer.cpp b/Source/Core/VideoBackends/Software/SWRenderer.cpp index 0b64022725..f8032f7e5d 100644 --- a/Source/Core/VideoBackends/Software/SWRenderer.cpp +++ b/Source/Core/VideoBackends/Software/SWRenderer.cpp @@ -97,13 +97,8 @@ std::unique_ptr SWRenderer::CreatePipeline(const AbstractPipel // Called on the GPU thread void SWRenderer::SwapImpl(AbstractTexture* texture, const EFBRectangle& xfb_region, u64 ticks) { - OSD::DoCallbacks(OSD::CallbackType::OnFrame); - if (!IsHeadless()) - { - DrawDebugText(); m_window->ShowImage(texture, xfb_region); - } UpdateActiveConfig(); } diff --git a/Source/Core/VideoBackends/Vulkan/Renderer.cpp b/Source/Core/VideoBackends/Vulkan/Renderer.cpp index 509269368d..5ae6093f24 100644 --- a/Source/Core/VideoBackends/Vulkan/Renderer.cpp +++ b/Source/Core/VideoBackends/Vulkan/Renderer.cpp @@ -704,9 +704,6 @@ void Renderer::DrawScreen(VKTexture* xfb_texture, const EFBRectangle& xfb_region // Draw OSD SetViewport(0.0f, 0.0f, static_cast(backbuffer->GetWidth()), static_cast(backbuffer->GetHeight()), 0.0f, 1.0f); - DrawDebugText(); - OSD::DoCallbacks(OSD::CallbackType::OnFrame); - OSD::DrawMessages(); StateTracker::GetInstance()->SetPendingRebind(); DrawImGui(); diff --git a/Source/Core/VideoCommon/OnScreenDisplay.cpp b/Source/Core/VideoCommon/OnScreenDisplay.cpp index 62997cd150..d6f9b38a3e 100644 --- a/Source/Core/VideoCommon/OnScreenDisplay.cpp +++ b/Source/Core/VideoCommon/OnScreenDisplay.cpp @@ -5,22 +5,79 @@ #include #include #include +#include #include +#include "imgui.h" + #include "Common/CommonTypes.h" #include "Common/Timer.h" #include "Core/ConfigManager.h" #include "VideoCommon/OnScreenDisplay.h" -#include "VideoCommon/RenderBase.h" namespace OSD { -static std::multimap s_callbacks; +constexpr float LEFT_MARGIN = 10.0f; // Pixels to the left of OSD messages. +constexpr float TOP_MARGIN = 10.0f; // Pixels above the first OSD message. +constexpr float WINDOW_PADDING = 4.0f; // Pixels between subsequent OSD messages. + +struct Message +{ + Message() {} + Message(const std::string& text_, u32 timestamp_, u32 color_) + : text(text_), timestamp(timestamp_), color(color_) + { + } + std::string text; + u32 timestamp; + u32 color; +}; static std::multimap s_messages; static std::mutex s_messages_mutex; +static ImVec4 RGBAToImVec4(const u32 rgba) +{ + return ImVec4(static_cast((rgba >> 16) & 0xFF) / 255.0f, + static_cast((rgba >> 8) & 0xFF) / 255.0f, + static_cast((rgba >> 0) & 0xFF) / 255.0f, + static_cast((rgba >> 24) & 0xFF) / 255.0f); +} + +static float DrawMessage(int index, const Message& msg, const ImVec2& position, int time_left) +{ + // We have to provide a window name, and these shouldn't be duplicated. + // So instead, we generate a name based on the number of messages drawn. + const std::string window_name = StringFromFormat("osd_%d", index); + + // The size must be reset, otherwise the length of old messages could influence new ones. + ImGui::SetNextWindowPos(position); + ImGui::SetNextWindowSize(ImVec2(0.0f, 0.0f)); + + // Gradually fade old messages away. + const float alpha = std::min(1.0f, std::max(0.0f, time_left / 1024.0f)); + ImGui::PushStyleVar(ImGuiStyleVar_Alpha, alpha); + + float window_height = 0.0f; + if (ImGui::Begin(window_name.c_str(), nullptr, + ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoInputs | + ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoSavedSettings | + ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoNav | + ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoFocusOnAppearing)) + { + // Use %s in case message contains %. + ImGui::TextColored(RGBAToImVec4(msg.color), "%s", msg.text.c_str()); + window_height = + ImGui::GetWindowSize().y + (WINDOW_PADDING * ImGui::GetIO().DisplayFramebufferScale.y); + } + + ImGui::End(); + ImGui::PopStyleVar(); + + return window_height; +} + void AddTypedMessage(MessageType type, const std::string& message, u32 ms, u32 rgba) { std::lock_guard lock(s_messages_mutex); @@ -35,14 +92,6 @@ void AddMessage(const std::string& message, u32 ms, u32 rgba) Message(message, Common::Timer::GetTimeMs() + ms, rgba)); } -void DrawMessage(const Message& msg, int top, int left, int time_left) -{ - float alpha = std::min(1.0f, std::max(0.0f, time_left / 1024.0f)); - u32 color = (msg.m_rgba & 0xFFFFFF) | ((u32)((msg.m_rgba >> 24) * alpha) << 24); - - g_renderer->RenderText(msg.m_str, left, top, color); -} - void DrawMessages() { if (!SConfig::GetInstance().bOnScreenDisplayMessages) @@ -51,21 +100,22 @@ void DrawMessages() { std::lock_guard lock(s_messages_mutex); - u32 now = Common::Timer::GetTimeMs(); - int left = 20, top = 35; + const u32 now = Common::Timer::GetTimeMs(); + float current_x = LEFT_MARGIN * ImGui::GetIO().DisplayFramebufferScale.x; + float current_y = TOP_MARGIN * ImGui::GetIO().DisplayFramebufferScale.y; + int index = 0; auto it = s_messages.begin(); while (it != s_messages.end()) { const Message& msg = it->second; - int time_left = (int)(msg.m_timestamp - now); - DrawMessage(msg, top, left, time_left); + const int time_left = static_cast(msg.timestamp - now); + current_y += DrawMessage(index++, msg, ImVec2(current_x, current_y), time_left); if (time_left <= 0) it = s_messages.erase(it); else ++it; - top += 15; } } } @@ -75,24 +125,4 @@ void ClearMessages() std::lock_guard lock(s_messages_mutex); s_messages.clear(); } - -// On-Screen Display Callbacks -void AddCallback(CallbackType type, Callback cb) -{ - s_callbacks.emplace(type, cb); } - -void DoCallbacks(CallbackType type) -{ - auto it_bounds = s_callbacks.equal_range(type); - for (auto it = it_bounds.first; it != it_bounds.second; ++it) - { - it->second(); - } - - // Wipe all callbacks on shutdown - if (type == CallbackType::Shutdown) - s_callbacks.clear(); -} - -} // namespace diff --git a/Source/Core/VideoCommon/OnScreenDisplay.h b/Source/Core/VideoCommon/OnScreenDisplay.h index a05f4058ef..51358aff19 100644 --- a/Source/Core/VideoCommon/OnScreenDisplay.h +++ b/Source/Core/VideoCommon/OnScreenDisplay.h @@ -11,15 +11,6 @@ namespace OSD { -struct Message -{ - Message() {} - Message(const std::string& s, u32 ts, u32 rgba) : m_str(s), m_timestamp(ts), m_rgba(rgba) {} - std::string m_str; - u32 m_timestamp; - u32 m_rgba; -}; - enum class MessageType { NetPlayPing, @@ -49,20 +40,7 @@ constexpr u32 VERY_LONG = 10000; void AddMessage(const std::string& message, u32 ms = Duration::SHORT, u32 rgba = Color::YELLOW); void AddTypedMessage(MessageType type, const std::string& message, u32 ms = Duration::SHORT, u32 rgba = Color::YELLOW); -void DrawMessage(const Message& msg, int top, int left, int time_left); // draw one message void DrawMessages(); // draw the current messages on the screen. Only call once // per frame. void ClearMessages(); - -// On-screen callbacks -enum class CallbackType -{ - Initialization, - OnFrame, - Shutdown -}; -using Callback = std::function; - -void AddCallback(CallbackType type, Callback cb); -void DoCallbacks(CallbackType type); } // namespace OSD diff --git a/Source/Core/VideoCommon/RenderBase.cpp b/Source/Core/VideoCommon/RenderBase.cpp index d30a7ccac3..76f3d29864 100644 --- a/Source/Core/VideoCommon/RenderBase.cpp +++ b/Source/Core/VideoCommon/RenderBase.cpp @@ -65,6 +65,7 @@ #include "VideoCommon/Statistics.h" #include "VideoCommon/TextureCacheBase.h" #include "VideoCommon/TextureDecoder.h" +#include "VideoCommon/VertexLoaderManager.h" #include "VideoCommon/VertexManagerBase.h" #include "VideoCommon/VertexShaderManager.h" #include "VideoCommon/VideoConfig.h" @@ -261,139 +262,64 @@ bool Renderer::CheckForHostConfigChanges() // Create On-Screen-Messages void Renderer::DrawDebugText() { - std::string final_yellow, final_cyan; + const auto& config = SConfig::GetInstance(); - if (g_ActiveConfig.bShowFPS || SConfig::GetInstance().m_ShowFrameCount) + if (g_ActiveConfig.bShowFPS) { - if (g_ActiveConfig.bShowFPS) - final_cyan += StringFromFormat("FPS: %.2f", m_fps_counter.GetFPS()); + // Position in the top-right corner of the screen. + ImGui::SetNextWindowPos(ImVec2(ImGui::GetIO().DisplaySize.x - (10.0f * m_backbuffer_scale), + 10.0f * m_backbuffer_scale), + ImGuiCond_Always, ImVec2(1.0f, 0.0f)); + ImGui::SetNextWindowSize(ImVec2(100.0f * m_backbuffer_scale, 30.0f * m_backbuffer_scale)); - if (g_ActiveConfig.bShowFPS && SConfig::GetInstance().m_ShowFrameCount) - final_cyan += " - "; - if (SConfig::GetInstance().m_ShowFrameCount) + if (ImGui::Begin("FPS", nullptr, + ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoInputs | + ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoSavedSettings | + ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoNav | + ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoFocusOnAppearing)) { - final_cyan += StringFromFormat("Frame: %" PRIu64, Movie::GetCurrentFrame()); + ImGui::TextColored(ImVec4(0.0f, 1.0f, 1.0f, 1.0f), "FPS: %.2f", m_fps_counter.GetFPS()); + } + ImGui::End(); + } + + const bool show_movie_window = + config.m_ShowFrameCount | config.m_ShowLag | config.m_ShowInputDisplay | config.m_ShowRTC; + if (show_movie_window) + { + // Position under the FPS display. + ImGui::SetNextWindowPos(ImVec2(ImGui::GetIO().DisplaySize.x - (10.0f * m_backbuffer_scale), + 50.0f * m_backbuffer_scale), + ImGuiCond_FirstUseEver, ImVec2(1.0f, 0.0f)); + ImGui::SetNextWindowSizeConstraints( + ImVec2(150.0f * m_backbuffer_scale, 20.0f * m_backbuffer_scale), + ImGui::GetIO().DisplaySize); + if (ImGui::Begin("Movie", nullptr, ImGuiWindowFlags_NoFocusOnAppearing)) + { + if (config.m_ShowFrameCount) + { + ImGui::Text("Frame: %" PRIu64, Movie::GetCurrentFrame()); + } if (Movie::IsPlayingInput()) - final_cyan += StringFromFormat("\nInput: %" PRIu64 " / %" PRIu64, - Movie::GetCurrentInputCount(), Movie::GetTotalInputCount()); + { + ImGui::Text("Input: %" PRIu64 " / %" PRIu64, Movie::GetCurrentInputCount(), + Movie::GetTotalInputCount()); + } + if (SConfig::GetInstance().m_ShowLag) + ImGui::Text("Lag: %" PRIu64 "\n", Movie::GetCurrentLagCount()); + if (SConfig::GetInstance().m_ShowInputDisplay) + ImGui::TextUnformatted(Movie::GetInputDisplay().c_str()); + if (SConfig::GetInstance().m_ShowRTC) + ImGui::TextUnformatted(Movie::GetRTCDisplay().c_str()); } - - final_cyan += "\n"; - final_yellow += "\n"; + ImGui::End(); } - if (SConfig::GetInstance().m_ShowLag) - { - final_cyan += StringFromFormat("Lag: %" PRIu64 "\n", Movie::GetCurrentLagCount()); - final_yellow += "\n"; - } - - if (SConfig::GetInstance().m_ShowInputDisplay) - { - final_cyan += Movie::GetInputDisplay(); - final_yellow += "\n"; - } - - if (SConfig::GetInstance().m_ShowRTC) - { - final_cyan += Movie::GetRTCDisplay(); - final_yellow += "\n"; - } - - // OSD Menu messages - if (m_osd_message > 0) - { - m_osd_time = Common::Timer::GetTimeMs() + 3000; - m_osd_message = -m_osd_message; - } - - if (static_cast(m_osd_time) > Common::Timer::GetTimeMs()) - { - std::string res_text; - switch (g_ActiveConfig.iEFBScale) - { - case EFB_SCALE_AUTO_INTEGRAL: - res_text = "Auto (integral)"; - break; - case 1: - res_text = "Native"; - break; - default: - res_text = StringFromFormat("%dx", g_ActiveConfig.iEFBScale); - break; - } - const char* ar_text = ""; - switch (g_ActiveConfig.aspect_mode) - { - case AspectMode::Stretch: - ar_text = "Stretch"; - break; - case AspectMode::Analog: - ar_text = "Force 4:3"; - break; - case AspectMode::AnalogWide: - ar_text = "Force 16:9"; - break; - case AspectMode::Auto: - default: - ar_text = "Auto"; - break; - } - const std::string audio_text = SConfig::GetInstance().m_IsMuted ? - "Muted" : - std::to_string(SConfig::GetInstance().m_Volume) + "%"; - - const char* const efbcopy_text = g_ActiveConfig.bSkipEFBCopyToRam ? "to Texture" : "to RAM"; - const char* const xfbcopy_text = g_ActiveConfig.bSkipXFBCopyToRam ? "to Texture" : "to RAM"; - - // The rows - const std::string lines[] = { - std::string("Internal Resolution: ") + res_text, - std::string("Aspect Ratio: ") + ar_text + (g_ActiveConfig.bCrop ? " (crop)" : ""), - std::string("Copy EFB: ") + efbcopy_text, - std::string("Fog: ") + (g_ActiveConfig.bDisableFog ? "Disabled" : "Enabled"), - SConfig::GetInstance().m_EmulationSpeed <= 0 ? - "Speed Limit: Unlimited" : - StringFromFormat("Speed Limit: %li%%", - std::lround(SConfig::GetInstance().m_EmulationSpeed * 100.f)), - std::string("Copy XFB: ") + xfbcopy_text + - (g_ActiveConfig.bImmediateXFB ? " (Immediate)" : ""), - "Volume: " + audio_text, - }; - - enum - { - lines_count = sizeof(lines) / sizeof(*lines) - }; - - // The latest changed setting in yellow - for (int i = 0; i != lines_count; ++i) - { - if (m_osd_message == -i - 1) - final_yellow += lines[i]; - final_yellow += '\n'; - } - - // The other settings in cyan - for (int i = 0; i != lines_count; ++i) - { - if (m_osd_message != -i - 1) - final_cyan += lines[i]; - final_cyan += '\n'; - } - } - - final_cyan += Common::Profiler::ToString(); - if (g_ActiveConfig.bOverlayStats) - final_cyan += Statistics::ToString(); + Statistics::Display(); if (g_ActiveConfig.bOverlayProjStats) - final_cyan += Statistics::ToStringProj(); - - // and then the text - RenderText(final_cyan, 20, 20, 0xFF00FFFF); - RenderText(final_yellow, 20, 20, 0xFFFFFF00); + Statistics::DisplayProj(); } float Renderer::CalculateDrawAspectRatio() const @@ -955,6 +881,8 @@ void Renderer::Swap(u32 xfbAddr, u32 fbWidth, u32 fbStride, u32 fbHeight, const // Draw any imgui overlays we have. Note that "draw" here means "create commands", the actual // draw calls don't get issued until DrawImGui is called, which happens in SwapImpl. + DrawDebugText(); + OSD::DrawMessages(); ImGui::Render(); // TODO: merge more generic parts into VideoCommon @@ -1332,8 +1260,3 @@ std::unique_ptr Renderer::CreateAsyncShaderCom { return std::make_unique(); } - -void Renderer::ShowOSDMessage(OSDMessage message) -{ - m_osd_message = static_cast(message); -} diff --git a/Source/Core/VideoCommon/RenderBase.h b/Source/Core/VideoCommon/RenderBase.h index b232d2c61f..b31384794c 100644 --- a/Source/Core/VideoCommon/RenderBase.h +++ b/Source/Core/VideoCommon/RenderBase.h @@ -57,17 +57,6 @@ struct EfbPokeData extern int frameCount; -enum class OSDMessage : s32 -{ - IRChanged = 1, - ARToggled = 2, - EFBCopyToggled = 3, - FogToggled = 4, - SpeedChanged = 5, - XFBChanged = 6, - VolumeChanged = 7, -}; - // Renderer really isn't a very good name for this class - it's more like "Misc". // The long term goal is to get rid of this class and replace it with others that make // more sense. @@ -201,8 +190,6 @@ public: virtual std::unique_ptr CreateAsyncShaderCompiler(); - void ShowOSDMessage(OSDMessage message); - protected: std::tuple CalculateTargetScale(int x, int y) const; bool CalculateTargetSize(); @@ -303,9 +290,6 @@ private: u32 m_last_xfb_width = MAX_XFB_WIDTH; u32 m_last_xfb_height = MAX_XFB_HEIGHT; - s32 m_osd_message = 0; - s32 m_osd_time = 0; - // NOTE: The methods below are called on the framedumping thread. bool StartFrameDumpToAVI(const FrameDumpConfig& config); void DumpFrameToAVI(const FrameDumpConfig& config); diff --git a/Source/Core/VideoCommon/Statistics.cpp b/Source/Core/VideoCommon/Statistics.cpp index 0a4a9236b0..af122bfcdb 100644 --- a/Source/Core/VideoCommon/Statistics.cpp +++ b/Source/Core/VideoCommon/Statistics.cpp @@ -6,6 +6,8 @@ #include #include +#include "imgui.h" + #include "Common/StringUtil.h" #include "VideoCommon/Statistics.h" #include "VideoCommon/VertexLoaderManager.h" @@ -26,91 +28,98 @@ void Statistics::SwapDL() std::swap(stats.thisFrame.numBPLoadsInDL, stats.thisFrame.numBPLoads); } -std::string Statistics::ToString() +void Statistics::Display() { - std::string str; + const float scale = ImGui::GetIO().DisplayFramebufferScale.x; + ImGui::SetNextWindowPos(ImVec2(10.0f * scale, 10.0f * scale), ImGuiCond_FirstUseEver); + ImGui::SetNextWindowSizeConstraints(ImVec2(275.0f * scale, 400.0f * scale), + ImGui::GetIO().DisplaySize); + if (!ImGui::Begin("Statistics", nullptr, ImGuiWindowFlags_NoNavInputs)) + { + ImGui::End(); + return; + } + + ImGui::Columns(2, "Statistics", true); + +#define DRAW_STAT(name, format, ...) \ + ImGui::Text(name); \ + ImGui::NextColumn(); \ + ImGui::Text(format, __VA_ARGS__); \ + ImGui::NextColumn(); if (g_ActiveConfig.backend_info.api_type == APIType::Nothing) { - str += StringFromFormat("Objects: %i\n", stats.thisFrame.numDrawnObjects); - str += StringFromFormat("Vertices Loaded: %i\n", stats.thisFrame.numVerticesLoaded); - str += StringFromFormat("Triangles Input: %i\n", stats.thisFrame.numTrianglesIn); - str += StringFromFormat("Triangles Rejected: %i\n", stats.thisFrame.numTrianglesRejected); - str += StringFromFormat("Triangles Culled: %i\n", stats.thisFrame.numTrianglesCulled); - str += StringFromFormat("Triangles Clipped: %i\n", stats.thisFrame.numTrianglesClipped); - str += StringFromFormat("Triangles Drawn: %i\n", stats.thisFrame.numTrianglesDrawn); - str += StringFromFormat("Rasterized Pix: %i\n", stats.thisFrame.rasterizedPixels); - str += StringFromFormat("TEV Pix In: %i\n", stats.thisFrame.tevPixelsIn); - str += StringFromFormat("TEV Pix Out: %i\n", stats.thisFrame.tevPixelsOut); + DRAW_STAT("Objects", "%d", stats.thisFrame.numDrawnObjects); + DRAW_STAT("Vertices Loaded", "%d", stats.thisFrame.numVerticesLoaded); + DRAW_STAT("Triangles Input", "%d", stats.thisFrame.numTrianglesIn); + DRAW_STAT("Triangles Rejected", "%d", stats.thisFrame.numTrianglesRejected); + DRAW_STAT("Triangles Culled", "%d", stats.thisFrame.numTrianglesCulled); + DRAW_STAT("Triangles Clipped", "%d", stats.thisFrame.numTrianglesClipped); + DRAW_STAT("Triangles Drawn", "%d", stats.thisFrame.numTrianglesDrawn); + DRAW_STAT("Rasterized Pix", "%d", stats.thisFrame.rasterizedPixels); + DRAW_STAT("TEV Pix In", "%d", stats.thisFrame.tevPixelsIn); + DRAW_STAT("TEV Pix Out", "%d", stats.thisFrame.tevPixelsOut); } - str += StringFromFormat("Textures created: %i\n", stats.numTexturesCreated); - str += StringFromFormat("Textures uploaded: %i\n", stats.numTexturesUploaded); - str += StringFromFormat("Textures alive: %i\n", stats.numTexturesAlive); - str += StringFromFormat("pshaders created: %i\n", stats.numPixelShadersCreated); - str += StringFromFormat("pshaders alive: %i\n", stats.numPixelShadersAlive); - str += StringFromFormat("vshaders created: %i\n", stats.numVertexShadersCreated); - str += StringFromFormat("vshaders alive: %i\n", stats.numVertexShadersAlive); - str += StringFromFormat("shaders changes: %i\n", stats.thisFrame.numShaderChanges); - str += StringFromFormat("dlists called: %i\n", stats.thisFrame.numDListsCalled); - str += StringFromFormat("Primitive joins: %i\n", stats.thisFrame.numPrimitiveJoins); - str += StringFromFormat("Draw calls: %i\n", stats.thisFrame.numDrawCalls); - str += StringFromFormat("Primitives: %i\n", stats.thisFrame.numPrims); - str += StringFromFormat("Primitives (DL): %i\n", stats.thisFrame.numDLPrims); - str += StringFromFormat("XF loads: %i\n", stats.thisFrame.numXFLoads); - str += StringFromFormat("XF loads (DL): %i\n", stats.thisFrame.numXFLoadsInDL); - str += StringFromFormat("CP loads: %i\n", stats.thisFrame.numCPLoads); - str += StringFromFormat("CP loads (DL): %i\n", stats.thisFrame.numCPLoadsInDL); - str += StringFromFormat("BP loads: %i\n", stats.thisFrame.numBPLoads); - str += StringFromFormat("BP loads (DL): %i\n", stats.thisFrame.numBPLoadsInDL); - str += StringFromFormat("Vertex streamed: %i kB\n", stats.thisFrame.bytesVertexStreamed / 1024); - str += StringFromFormat("Index streamed: %i kB\n", stats.thisFrame.bytesIndexStreamed / 1024); - str += StringFromFormat("Uniform streamed: %i kB\n", stats.thisFrame.bytesUniformStreamed / 1024); - str += StringFromFormat("Vertex Loaders: %i\n", stats.numVertexLoaders); + DRAW_STAT("Textures created", "%d", stats.numTexturesCreated); + DRAW_STAT("Textures uploaded", "%d", stats.numTexturesUploaded); + DRAW_STAT("Textures alive", "%d", stats.numTexturesAlive); + DRAW_STAT("pshaders created", "%d", stats.numPixelShadersCreated); + DRAW_STAT("pshaders alive", "%d", stats.numPixelShadersAlive); + DRAW_STAT("vshaders created", "%d", stats.numVertexShadersCreated); + DRAW_STAT("vshaders alive", "%d", stats.numVertexShadersAlive); + DRAW_STAT("shaders changes", "%d", stats.thisFrame.numShaderChanges); + DRAW_STAT("dlists called", "%d", stats.thisFrame.numDListsCalled); + DRAW_STAT("Primitive joins", "%d", stats.thisFrame.numPrimitiveJoins); + DRAW_STAT("Draw calls", "%d", stats.thisFrame.numDrawCalls); + DRAW_STAT("Primitives", "%d", stats.thisFrame.numPrims); + DRAW_STAT("Primitives (DL)", "%d", stats.thisFrame.numDLPrims); + DRAW_STAT("XF loads", "%d", stats.thisFrame.numXFLoads); + DRAW_STAT("XF loads (DL)", "%d", stats.thisFrame.numXFLoadsInDL); + DRAW_STAT("CP loads", "%d", stats.thisFrame.numCPLoads); + DRAW_STAT("CP loads (DL)", "%d", stats.thisFrame.numCPLoadsInDL); + DRAW_STAT("BP loads", "%d", stats.thisFrame.numBPLoads); + DRAW_STAT("BP loads (DL)", "%d", stats.thisFrame.numBPLoadsInDL); + DRAW_STAT("Vertex streamed", "%i kB", stats.thisFrame.bytesVertexStreamed / 1024); + DRAW_STAT("Index streamed", "%i kB", stats.thisFrame.bytesIndexStreamed / 1024); + DRAW_STAT("Uniform streamed", "%i kB", stats.thisFrame.bytesUniformStreamed / 1024); + DRAW_STAT("Vertex Loaders", "%d", stats.numVertexLoaders); - std::string vertex_list = VertexLoaderManager::VertexLoadersToString(); +#undef DRAW_STAT - // TODO : at some point text1 just becomes too huge and overflows, we can't even read the added - // stuff - // since it gets added at the far bottom of the screen anyway (actually outside the rendering - // window) - // we should really reset the list instead of using substr - if (vertex_list.size() + str.size() > 8170) - vertex_list = vertex_list.substr(0, 8170 - str.size()); + ImGui::Columns(1); - str += vertex_list; - - return str; + ImGui::End(); } // Is this really needed? -std::string Statistics::ToStringProj() +void Statistics::DisplayProj() { - std::string projections; + if (!ImGui::Begin("Projection Statistics", nullptr, ImGuiWindowFlags_NoNavInputs)) + { + ImGui::End(); + return; + } - projections += "Projection #: X for Raw 6=0 (X for Raw 6!=0)\n\n"; - projections += StringFromFormat("Projection 0: %f (%f) Raw 0: %f\n", stats.gproj_0, - stats.g2proj_0, stats.proj_0); - projections += StringFromFormat("Projection 1: %f (%f)\n", stats.gproj_1, stats.g2proj_1); - projections += StringFromFormat("Projection 2: %f (%f) Raw 1: %f\n", stats.gproj_2, - stats.g2proj_2, stats.proj_1); - projections += StringFromFormat("Projection 3: %f (%f)\n\n", stats.gproj_3, stats.g2proj_3); - projections += StringFromFormat("Projection 4: %f (%f)\n", stats.gproj_4, stats.g2proj_4); - projections += StringFromFormat("Projection 5: %f (%f) Raw 2: %f\n", stats.gproj_5, - stats.g2proj_5, stats.proj_2); - projections += StringFromFormat("Projection 6: %f (%f) Raw 3: %f\n", stats.gproj_6, - stats.g2proj_6, stats.proj_3); - projections += StringFromFormat("Projection 7: %f (%f)\n\n", stats.gproj_7, stats.g2proj_7); - projections += StringFromFormat("Projection 8: %f (%f)\n", stats.gproj_8, stats.g2proj_8); - projections += StringFromFormat("Projection 9: %f (%f)\n", stats.gproj_9, stats.g2proj_9); - projections += StringFromFormat("Projection 10: %f (%f) Raw 4: %f\n\n", stats.gproj_10, - stats.g2proj_10, stats.proj_4); - projections += StringFromFormat("Projection 11: %f (%f) Raw 5: %f\n\n", stats.gproj_11, - stats.g2proj_11, stats.proj_5); - projections += StringFromFormat("Projection 12: %f (%f)\n", stats.gproj_12, stats.g2proj_12); - projections += StringFromFormat("Projection 13: %f (%f)\n", stats.gproj_13, stats.g2proj_13); - projections += StringFromFormat("Projection 14: %f (%f)\n", stats.gproj_14, stats.g2proj_14); - projections += StringFromFormat("Projection 15: %f (%f)\n", stats.gproj_15, stats.g2proj_15); + ImGui::Text("Projection #: X for Raw 6=0 (X for Raw 6!=0)"); + ImGui::NewLine(); + ImGui::Text("Projection 0: %f (%f) Raw 0: %f", stats.gproj_0, stats.g2proj_0, stats.proj_0); + ImGui::Text("Projection 1: %f (%f)", stats.gproj_1, stats.g2proj_1); + ImGui::Text("Projection 2: %f (%f) Raw 1: %f", stats.gproj_2, stats.g2proj_2, stats.proj_1); + ImGui::Text("Projection 3: %f (%f)", stats.gproj_3, stats.g2proj_3); + ImGui::Text("Projection 4: %f (%f)", stats.gproj_4, stats.g2proj_4); + ImGui::Text("Projection 5: %f (%f) Raw 2: %f", stats.gproj_5, stats.g2proj_5, stats.proj_2); + ImGui::Text("Projection 6: %f (%f) Raw 3: %f", stats.gproj_6, stats.g2proj_6, stats.proj_3); + ImGui::Text("Projection 7: %f (%f)", stats.gproj_7, stats.g2proj_7); + ImGui::Text("Projection 8: %f (%f)", stats.gproj_8, stats.g2proj_8); + ImGui::Text("Projection 9: %f (%f)", stats.gproj_9, stats.g2proj_9); + ImGui::Text("Projection 10: %f (%f) Raw 4: %f", stats.gproj_10, stats.g2proj_10, stats.proj_4); + ImGui::Text("Projection 11: %f (%f) Raw 5: %f", stats.gproj_11, stats.g2proj_11, stats.proj_5); + ImGui::Text("Projection 12: %f (%f)", stats.gproj_12, stats.g2proj_12); + ImGui::Text("Projection 13: %f (%f)", stats.gproj_13, stats.g2proj_13); + ImGui::Text("Projection 14: %f (%f)", stats.gproj_14, stats.g2proj_14); + ImGui::Text("Projection 15: %f (%f)", stats.gproj_15, stats.g2proj_15); - return projections; + ImGui::End(); } diff --git a/Source/Core/VideoCommon/Statistics.h b/Source/Core/VideoCommon/Statistics.h index 74ee317b82..c743bf7f08 100644 --- a/Source/Core/VideoCommon/Statistics.h +++ b/Source/Core/VideoCommon/Statistics.h @@ -65,9 +65,8 @@ struct Statistics ThisFrame thisFrame; void ResetFrame(); static void SwapDL(); - - static std::string ToString(); - static std::string ToStringProj(); + static void Display(); + static void DisplayProj(); }; extern Statistics stats; diff --git a/Source/Core/VideoCommon/VideoBackendBase.cpp b/Source/Core/VideoCommon/VideoBackendBase.cpp index fd6bbdfa2b..aa8b3d110f 100644 --- a/Source/Core/VideoCommon/VideoBackendBase.cpp +++ b/Source/Core/VideoCommon/VideoBackendBase.cpp @@ -278,9 +278,6 @@ void VideoBackendBase::InitializeShared() memset(&g_preprocess_cp_state, 0, sizeof(g_preprocess_cp_state)); memset(texMem, 0, TMEM_SIZE); - // Do our OSD callbacks - OSD::DoCallbacks(OSD::CallbackType::Initialization); - // do not initialize again for the config window m_initialized = true; @@ -303,9 +300,6 @@ void VideoBackendBase::InitializeShared() void VideoBackendBase::ShutdownShared() { - // Do our OSD callbacks - OSD::DoCallbacks(OSD::CallbackType::Shutdown); - m_initialized = false; VertexLoaderManager::Clear(); From 63dd91628de0c9e8c7a25c403b7900675c515d36 Mon Sep 17 00:00:00 2001 From: Stenzek Date: Wed, 10 Oct 2018 01:34:26 +1100 Subject: [PATCH 04/15] Remove old RasterFont classes --- Source/Core/VideoBackends/D3D/D3DUtil.cpp | 390 ---------------- Source/Core/VideoBackends/D3D/D3DUtil.h | 2 - Source/Core/VideoBackends/D3D/Render.cpp | 7 - Source/Core/VideoBackends/D3D/Render.h | 2 - Source/Core/VideoBackends/Null/Render.cpp | 5 - Source/Core/VideoBackends/Null/Render.h | 1 - Source/Core/VideoBackends/OGL/CMakeLists.txt | 1 - Source/Core/VideoBackends/OGL/OGL.vcxproj | 2 - .../VideoBackends/OGL/OGL.vcxproj.filters | 9 - .../Core/VideoBackends/OGL/PostProcessing.cpp | 5 - Source/Core/VideoBackends/OGL/RasterFont.cpp | 291 ------------ Source/Core/VideoBackends/OGL/RasterFont.h | 30 -- Source/Core/VideoBackends/OGL/Render.cpp | 20 - Source/Core/VideoBackends/OGL/Render.h | 2 - .../VideoBackends/Software/SWOGLWindow.cpp | 11 - .../Core/VideoBackends/Software/SWOGLWindow.h | 11 - .../VideoBackends/Software/SWRenderer.cpp | 5 - .../Core/VideoBackends/Software/SWRenderer.h | 1 - .../Core/VideoBackends/Vulkan/CMakeLists.txt | 1 - .../VideoBackends/Vulkan/PostProcessing.cpp | 9 +- .../VideoBackends/Vulkan/PostProcessing.h | 3 +- .../Core/VideoBackends/Vulkan/RasterFont.cpp | 421 ------------------ Source/Core/VideoBackends/Vulkan/RasterFont.h | 41 -- Source/Core/VideoBackends/Vulkan/Renderer.cpp | 22 +- Source/Core/VideoBackends/Vulkan/Renderer.h | 3 - .../Core/VideoBackends/Vulkan/Vulkan.vcxproj | 2 - Source/Core/VideoCommon/CMakeLists.txt | 1 + Source/Core/VideoCommon/RenderBase.h | 2 - 28 files changed, 4 insertions(+), 1296 deletions(-) delete mode 100644 Source/Core/VideoBackends/OGL/RasterFont.cpp delete mode 100644 Source/Core/VideoBackends/OGL/RasterFont.h delete mode 100644 Source/Core/VideoBackends/Vulkan/RasterFont.cpp delete mode 100644 Source/Core/VideoBackends/Vulkan/RasterFont.h diff --git a/Source/Core/VideoBackends/D3D/D3DUtil.cpp b/Source/Core/VideoBackends/D3D/D3DUtil.cpp index 5663a8f3ae..0ad02c1ca4 100644 --- a/Source/Core/VideoBackends/D3D/D3DUtil.cpp +++ b/Source/Core/VideoBackends/D3D/D3DUtil.cpp @@ -98,390 +98,7 @@ private: std::list observers; }; -class CD3DFont -{ -public: - CD3DFont(); - // 2D text drawing function - // Initializing and destroying device-dependent objects - int Init(); - int Shutdown(); - int DrawTextScaled(float x, float y, float size, float spacing, u32 dwColor, - const std::string& text); - -private: - ID3D11ShaderResourceView* m_pTexture; - ID3D11Buffer* m_pVB; - ID3D11InputLayout* m_InputLayout; - ID3D11PixelShader* m_pshader; - ID3D11VertexShader* m_vshader; - ID3D11BlendState* m_blendstate; - ID3D11RasterizerState* m_raststate; - const int m_dwTexWidth; - const int m_dwTexHeight; - unsigned int m_LineHeight; - float m_fTexCoords[128 - 32][4]; -}; - -static CD3DFont font; static UtilVertexBuffer* util_vbuf = nullptr; - -#define MAX_NUM_VERTICES 50 * 6 -struct FONT2DVERTEX -{ - float x, y, z; - float col[4]; - float tu, tv; -}; - -inline FONT2DVERTEX InitFont2DVertex(float x, float y, u32 color, float tu, float tv) -{ - FONT2DVERTEX v; - v.x = x; - v.y = y; - v.z = 0; - v.tu = tu; - v.tv = tv; - v.col[0] = ((float)((color >> 16) & 0xFF)) / 255.f; - v.col[1] = ((float)((color >> 8) & 0xFF)) / 255.f; - v.col[2] = ((float)((color >> 0) & 0xFF)) / 255.f; - v.col[3] = ((float)((color >> 24) & 0xFF)) / 255.f; - return v; -} - -CD3DFont::CD3DFont() : m_dwTexWidth(512), m_dwTexHeight(512) -{ - m_pTexture = nullptr; - m_pVB = nullptr; - m_InputLayout = nullptr; - m_pshader = nullptr; - m_vshader = nullptr; -} - -const char fontpixshader[] = {"Texture2D tex2D;\n" - "SamplerState linearSampler\n" - "{\n" - " Filter = MIN_MAG_MIP_LINEAR;\n" - " AddressU = D3D11_TEXTURE_ADDRESS_BORDER;\n" - " AddressV = D3D11_TEXTURE_ADDRESS_BORDER;\n" - " BorderColor = float4(0.f, 0.f, 0.f, 0.f);\n" - "};\n" - "struct PS_INPUT\n" - "{\n" - " float4 pos : SV_POSITION;\n" - " float4 col : COLOR;\n" - " float2 tex : TEXCOORD;\n" - "};\n" - "float4 main( PS_INPUT input ) : SV_Target\n" - "{\n" - " return tex2D.Sample( linearSampler, input.tex ) * input.col;\n" - "};\n"}; - -const char fontvertshader[] = {"struct VS_INPUT\n" - "{\n" - " float4 pos : POSITION;\n" - " float4 col : COLOR;\n" - " float2 tex : TEXCOORD;\n" - "};\n" - "struct PS_INPUT\n" - "{\n" - " float4 pos : SV_POSITION;\n" - " float4 col : COLOR;\n" - " float2 tex : TEXCOORD;\n" - "};\n" - "PS_INPUT main( VS_INPUT input )\n" - "{\n" - " PS_INPUT output;\n" - " output.pos = input.pos;\n" - " output.col = input.col;\n" - " output.tex = input.tex;\n" - " return output;\n" - "};\n"}; - -int CD3DFont::Init() -{ - // Create vertex buffer for the letters - HRESULT hr; - - // Prepare to create a bitmap - unsigned int* pBitmapBits; - BITMAPINFO bmi; - ZeroMemory(&bmi.bmiHeader, sizeof(BITMAPINFOHEADER)); - bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); - bmi.bmiHeader.biWidth = (int)m_dwTexWidth; - bmi.bmiHeader.biHeight = -(int)m_dwTexHeight; - bmi.bmiHeader.biPlanes = 1; - bmi.bmiHeader.biCompression = BI_RGB; - bmi.bmiHeader.biBitCount = 32; - - // Create a DC and a bitmap for the font - HDC hDC = CreateCompatibleDC(nullptr); - HBITMAP hbmBitmap = CreateDIBSection(hDC, &bmi, DIB_RGB_COLORS, (void**)&pBitmapBits, nullptr, 0); - SetMapMode(hDC, MM_TEXT); - - // create a GDI font - HFONT hFont = - CreateFont(24, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, - CLIP_DEFAULT_PRECIS, PROOF_QUALITY, VARIABLE_PITCH, _T("Tahoma")); - if (nullptr == hFont) - return E_FAIL; - - HGDIOBJ hOldbmBitmap = SelectObject(hDC, hbmBitmap); - HGDIOBJ hOldFont = SelectObject(hDC, hFont); - - // Set text properties - SetTextColor(hDC, 0xFFFFFF); - SetBkColor(hDC, 0); - SetTextAlign(hDC, TA_TOP); - - TEXTMETRICW tm; - GetTextMetricsW(hDC, &tm); - m_LineHeight = tm.tmHeight; - - // Loop through all printable characters and output them to the bitmap - // Meanwhile, keep track of the corresponding tex coords for each character. - int x = 0, y = 0; - char str[2] = "\0"; - for (int c = 0; c < 127 - 32; c++) - { - str[0] = c + 32; - SIZE size; - GetTextExtentPoint32A(hDC, str, 1, &size); - if ((int)(x + size.cx + 1) > m_dwTexWidth) - { - x = 0; - y += m_LineHeight; - } - - ExtTextOutA(hDC, x + 1, y + 0, ETO_OPAQUE | ETO_CLIPPED, nullptr, str, 1, nullptr); - m_fTexCoords[c][0] = ((float)(x + 0)) / m_dwTexWidth; - m_fTexCoords[c][1] = ((float)(y + 0)) / m_dwTexHeight; - m_fTexCoords[c][2] = ((float)(x + 0 + size.cx)) / m_dwTexWidth; - m_fTexCoords[c][3] = ((float)(y + 0 + size.cy)) / m_dwTexHeight; - - x += size.cx + 3; // 3 to work around annoying ij conflict (part of the j ends up with the i) - } - - // Create a new texture for the font - // possible optimization: store the converted data in a buffer and fill the texture on creation. - // That way, we can use a static texture - ID3D11Texture2D* buftex; - D3D11_TEXTURE2D_DESC texdesc = CD3D11_TEXTURE2D_DESC( - DXGI_FORMAT_R8G8B8A8_UNORM, m_dwTexWidth, m_dwTexHeight, 1, 1, D3D11_BIND_SHADER_RESOURCE, - D3D11_USAGE_DYNAMIC, D3D11_CPU_ACCESS_WRITE); - hr = device->CreateTexture2D(&texdesc, nullptr, &buftex); - if (FAILED(hr)) - { - PanicAlert("Failed to create font texture"); - return hr; - } - D3D::SetDebugObjectName(buftex, "texture of a CD3DFont object"); - - // Lock the surface and write the alpha values for the set pixels - D3D11_MAPPED_SUBRESOURCE texmap; - hr = context->Map(buftex, 0, D3D11_MAP_WRITE_DISCARD, 0, &texmap); - if (FAILED(hr)) - PanicAlert("Failed to map a texture at %s %d\n", __FILE__, __LINE__); - - for (y = 0; y < m_dwTexHeight; y++) - { - u32* pDst32 = (u32*)((u8*)texmap.pData + y * texmap.RowPitch); - for (x = 0; x < m_dwTexWidth; x++) - { - const u8 bAlpha = (pBitmapBits[m_dwTexWidth * y + x] & 0xff); - *pDst32++ = (((bAlpha << 4) | bAlpha) << 24) | 0xFFFFFF; - } - } - - // Done updating texture, so clean up used objects - context->Unmap(buftex, 0); - hr = D3D::device->CreateShaderResourceView(buftex, nullptr, &m_pTexture); - if (FAILED(hr)) - PanicAlert("Failed to create shader resource view at %s %d\n", __FILE__, __LINE__); - SAFE_RELEASE(buftex); - - SelectObject(hDC, hOldbmBitmap); - DeleteObject(hbmBitmap); - - SelectObject(hDC, hOldFont); - DeleteObject(hFont); - - // setup device objects for drawing - m_pshader = D3D::CompileAndCreatePixelShader(fontpixshader); - if (m_pshader == nullptr) - PanicAlert("Failed to create pixel shader, %s %d\n", __FILE__, __LINE__); - D3D::SetDebugObjectName(m_pshader, "pixel shader of a CD3DFont object"); - - D3DBlob* vsbytecode; - D3D::CompileVertexShader(fontvertshader, &vsbytecode); - if (vsbytecode == nullptr) - PanicAlert("Failed to compile vertex shader, %s %d\n", __FILE__, __LINE__); - m_vshader = D3D::CreateVertexShaderFromByteCode(vsbytecode); - if (m_vshader == nullptr) - PanicAlert("Failed to create vertex shader, %s %d\n", __FILE__, __LINE__); - D3D::SetDebugObjectName(m_vshader, "vertex shader of a CD3DFont object"); - - const D3D11_INPUT_ELEMENT_DESC desc[] = { - {"POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0}, - {"COLOR", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0}, - {"TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 28, D3D11_INPUT_PER_VERTEX_DATA, 0}, - }; - hr = D3D::device->CreateInputLayout(desc, 3, vsbytecode->Data(), vsbytecode->Size(), - &m_InputLayout); - if (FAILED(hr)) - PanicAlert("Failed to create input layout, %s %d\n", __FILE__, __LINE__); - SAFE_RELEASE(vsbytecode); - - D3D11_BLEND_DESC blenddesc; - blenddesc.AlphaToCoverageEnable = FALSE; - blenddesc.IndependentBlendEnable = FALSE; - blenddesc.RenderTarget[0].BlendEnable = TRUE; - blenddesc.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL; - blenddesc.RenderTarget[0].SrcBlend = D3D11_BLEND_SRC_ALPHA; - blenddesc.RenderTarget[0].DestBlend = D3D11_BLEND_INV_SRC_ALPHA; - blenddesc.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD; - blenddesc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_SRC_ALPHA; - blenddesc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_INV_SRC_ALPHA; - blenddesc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD; - hr = D3D::device->CreateBlendState(&blenddesc, &m_blendstate); - CHECK(hr == S_OK, "Create font blend state"); - D3D::SetDebugObjectName(m_blendstate, "blend state of a CD3DFont object"); - - D3D11_RASTERIZER_DESC rastdesc = CD3D11_RASTERIZER_DESC(D3D11_FILL_SOLID, D3D11_CULL_NONE, false, - 0, 0.f, 0.f, false, false, false, false); - hr = D3D::device->CreateRasterizerState(&rastdesc, &m_raststate); - CHECK(hr == S_OK, "Create font rasterizer state"); - D3D::SetDebugObjectName(m_raststate, "rasterizer state of a CD3DFont object"); - - D3D11_BUFFER_DESC vbdesc = - CD3D11_BUFFER_DESC(MAX_NUM_VERTICES * sizeof(FONT2DVERTEX), D3D11_BIND_VERTEX_BUFFER, - D3D11_USAGE_DYNAMIC, D3D11_CPU_ACCESS_WRITE); - if (FAILED(hr = device->CreateBuffer(&vbdesc, nullptr, &m_pVB))) - { - PanicAlert("Failed to create font vertex buffer at %s, line %d\n", __FILE__, __LINE__); - return hr; - } - D3D::SetDebugObjectName(m_pVB, "vertex buffer of a CD3DFont object"); - return S_OK; -} - -int CD3DFont::Shutdown() -{ - SAFE_RELEASE(m_pVB); - SAFE_RELEASE(m_pTexture); - SAFE_RELEASE(m_InputLayout); - SAFE_RELEASE(m_pshader); - SAFE_RELEASE(m_vshader); - - SAFE_RELEASE(m_blendstate); - SAFE_RELEASE(m_raststate); - - return S_OK; -} - -int CD3DFont::DrawTextScaled(float x, float y, float size, float spacing, u32 dwColor, - const std::string& text) -{ - if (!m_pVB) - return 0; - - UINT stride = sizeof(FONT2DVERTEX); - UINT bufoffset = 0; - - float scalex = 1.0f / g_renderer->GetBackbufferWidth() * 2.f; - float scaley = 1.0f / g_renderer->GetBackbufferHeight() * 2.f; - float sizeratio = size / m_LineHeight; - - // translate starting positions - float sx = x * scalex - 1.f; - float sy = 1.f - y * scaley; - - // Fill vertex buffer - FONT2DVERTEX* pVertices; - int dwNumTriangles = 0L; - - D3D11_MAPPED_SUBRESOURCE vbmap; - HRESULT hr = context->Map(m_pVB, 0, D3D11_MAP_WRITE_DISCARD, 0, &vbmap); - if (FAILED(hr)) - PanicAlert("Mapping vertex buffer failed, %s %d\n", __FILE__, __LINE__); - pVertices = (D3D::FONT2DVERTEX*)vbmap.pData; - - // set general pipeline state - D3D::stateman->SetBlendState(m_blendstate); - D3D::stateman->SetRasterizerState(m_raststate); - - D3D::stateman->SetPixelShader(m_pshader); - D3D::stateman->SetVertexShader(m_vshader); - D3D::stateman->SetGeometryShader(nullptr); - - D3D::stateman->SetInputLayout(m_InputLayout); - D3D::stateman->SetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); - D3D::stateman->SetTexture(0, m_pTexture); - - float fStartX = sx; - for (char c : text) - { - if (c == '\n') - { - sx = fStartX; - sy -= scaley * size; - } - if (!std::isprint(c)) - continue; - - c -= 32; - float tx1 = m_fTexCoords[c][0]; - float ty1 = m_fTexCoords[c][1]; - float tx2 = m_fTexCoords[c][2]; - float ty2 = m_fTexCoords[c][3]; - - float w = (float)(tx2 - tx1) * m_dwTexWidth * scalex * sizeratio; - float h = (float)(ty1 - ty2) * m_dwTexHeight * scaley * sizeratio; - - FONT2DVERTEX v[6]; - v[0] = InitFont2DVertex(sx, sy + h, dwColor, tx1, ty2); - v[1] = InitFont2DVertex(sx, sy, dwColor, tx1, ty1); - v[2] = InitFont2DVertex(sx + w, sy + h, dwColor, tx2, ty2); - v[3] = InitFont2DVertex(sx + w, sy, dwColor, tx2, ty1); - v[4] = v[2]; - v[5] = v[1]; - - memcpy(pVertices, v, 6 * sizeof(FONT2DVERTEX)); - - pVertices += 6; - dwNumTriangles += 2; - - if (dwNumTriangles * 3 > (MAX_NUM_VERTICES - 6)) - { - context->Unmap(m_pVB, 0); - - D3D::stateman->SetVertexBuffer(m_pVB, stride, bufoffset); - - D3D::stateman->Apply(); - D3D::context->Draw(3 * dwNumTriangles, 0); - - dwNumTriangles = 0; - D3D11_MAPPED_SUBRESOURCE _vbmap; - hr = context->Map(m_pVB, 0, D3D11_MAP_WRITE_DISCARD, 0, &_vbmap); - if (FAILED(hr)) - PanicAlert("Mapping vertex buffer failed, %s %d\n", __FILE__, __LINE__); - pVertices = (D3D::FONT2DVERTEX*)_vbmap.pData; - } - sx += w + spacing * scalex * size; - } - - // Unlock and render the vertex buffer - context->Unmap(m_pVB, 0); - if (dwNumTriangles > 0) - { - D3D::stateman->SetVertexBuffer(m_pVB, stride, bufoffset); - - D3D::stateman->Apply(); - D3D::context->Draw(3 * dwNumTriangles, 0); - } - return S_OK; -} - static ID3D11SamplerState* linear_copy_sampler = nullptr; static ID3D11SamplerState* point_copy_sampler = nullptr; @@ -560,13 +177,10 @@ void InitUtils() util_vbuf->AddWrapObserver(&stq_observer); util_vbuf->AddWrapObserver(&cq_observer); util_vbuf->AddWrapObserver(&clearq_observer); - - font.Init(); } void ShutdownUtils() { - font.Shutdown(); SAFE_RELEASE(point_copy_sampler); SAFE_RELEASE(linear_copy_sampler); SAFE_DELETE(util_vbuf); @@ -788,10 +402,6 @@ void DrawEFBPokeQuads(EFBAccessType type, const EfbPokeData* points, size_t num_ stateman->SetGeometryShader(GeometryShaderCache::GetClearGeometryShader()); } -void DrawTextScaled(float x, float y, float size, float spacing, u32 color, const std::string& text) -{ - font.DrawTextScaled(x, y, size, spacing, color, text); -} } // namespace D3D } // namespace DX11 diff --git a/Source/Core/VideoBackends/D3D/D3DUtil.h b/Source/Core/VideoBackends/D3D/D3DUtil.h index ade53946b1..cfbe2e4889 100644 --- a/Source/Core/VideoBackends/D3D/D3DUtil.h +++ b/Source/Core/VideoBackends/D3D/D3DUtil.h @@ -28,7 +28,5 @@ void drawClearQuad(u32 Color, float z); void drawColorQuad(u32 Color, float z, float x1, float y1, float x2, float y2); void DrawEFBPokeQuads(EFBAccessType type, const EfbPokeData* points, size_t num_points); -void DrawTextScaled(float x, float y, float size, float spacing, u32 color, - const std::string& text); } } diff --git a/Source/Core/VideoBackends/D3D/Render.cpp b/Source/Core/VideoBackends/D3D/Render.cpp index 87190a6d2b..aff6fe6bc0 100644 --- a/Source/Core/VideoBackends/D3D/Render.cpp +++ b/Source/Core/VideoBackends/D3D/Render.cpp @@ -237,13 +237,6 @@ Renderer::CreateFramebuffer(const AbstractTexture* color_attachment, static_cast(depth_attachment)); } -void Renderer::RenderText(const std::string& text, int left, int top, u32 color) -{ - D3D::DrawTextScaled(static_cast(left + 1), static_cast(top + 1), 20.f, 0.0f, - color & 0xFF000000, text); - D3D::DrawTextScaled(static_cast(left), static_cast(top), 20.f, 0.0f, color, text); -} - std::unique_ptr Renderer::CreateShaderFromSource(ShaderStage stage, const char* source, size_t length) { diff --git a/Source/Core/VideoBackends/D3D/Render.h b/Source/Core/VideoBackends/D3D/Render.h index 4750a0e69a..68f7f2b669 100644 --- a/Source/Core/VideoBackends/D3D/Render.h +++ b/Source/Core/VideoBackends/D3D/Render.h @@ -55,8 +55,6 @@ public: void SetFullscreen(bool enable_fullscreen) override; bool IsFullscreen() const override; - void RenderText(const std::string& text, int left, int top, u32 color) override; - u32 AccessEFB(EFBAccessType type, u32 x, u32 y, u32 poke_data) override; void PokeEFB(EFBAccessType type, const EfbPokeData* points, size_t num_points) override; diff --git a/Source/Core/VideoBackends/Null/Render.cpp b/Source/Core/VideoBackends/Null/Render.cpp index 0fe6f1186e..f905d95a0f 100644 --- a/Source/Core/VideoBackends/Null/Render.cpp +++ b/Source/Core/VideoBackends/Null/Render.cpp @@ -82,11 +82,6 @@ Renderer::CreateFramebuffer(const AbstractTexture* color_attachment, static_cast(depth_attachment)); } -void Renderer::RenderText(const std::string& text, int left, int top, u32 color) -{ - NOTICE_LOG(VIDEO, "RenderText: %s", text.c_str()); -} - TargetRectangle Renderer::ConvertEFBRectangle(const EFBRectangle& rc) { TargetRectangle result; diff --git a/Source/Core/VideoBackends/Null/Render.h b/Source/Core/VideoBackends/Null/Render.h index 10f15f0304..6567b239fb 100644 --- a/Source/Core/VideoBackends/Null/Render.h +++ b/Source/Core/VideoBackends/Null/Render.h @@ -29,7 +29,6 @@ public: size_t length) override; std::unique_ptr CreatePipeline(const AbstractPipelineConfig& config) override; - void RenderText(const std::string& pstr, int left, int top, u32 color) override; u32 AccessEFB(EFBAccessType type, u32 x, u32 y, u32 poke_data) override { return 0; } void PokeEFB(EFBAccessType type, const EfbPokeData* points, size_t num_points) override {} u16 BBoxRead(int index) override { return 0; } diff --git a/Source/Core/VideoBackends/OGL/CMakeLists.txt b/Source/Core/VideoBackends/OGL/CMakeLists.txt index 0fc4f1b4ed..c786ba671f 100644 --- a/Source/Core/VideoBackends/OGL/CMakeLists.txt +++ b/Source/Core/VideoBackends/OGL/CMakeLists.txt @@ -9,7 +9,6 @@ add_library(videoogl PerfQuery.cpp PostProcessing.cpp ProgramShaderCache.cpp - RasterFont.cpp Render.cpp SamplerCache.cpp StreamBuffer.cpp diff --git a/Source/Core/VideoBackends/OGL/OGL.vcxproj b/Source/Core/VideoBackends/OGL/OGL.vcxproj index a947e4454b..38ea16b42e 100644 --- a/Source/Core/VideoBackends/OGL/OGL.vcxproj +++ b/Source/Core/VideoBackends/OGL/OGL.vcxproj @@ -46,7 +46,6 @@ - @@ -64,7 +63,6 @@ - diff --git a/Source/Core/VideoBackends/OGL/OGL.vcxproj.filters b/Source/Core/VideoBackends/OGL/OGL.vcxproj.filters index ea5967fb1e..fbede5caf6 100644 --- a/Source/Core/VideoBackends/OGL/OGL.vcxproj.filters +++ b/Source/Core/VideoBackends/OGL/OGL.vcxproj.filters @@ -7,9 +7,6 @@ {5bfec41c-1031-4925-8f98-38c7b49b1924} - - {00dadfd8-a906-4b0c-b415-d42a69cf3ca7} - {696df73b-378e-4399-8f21-999b65d78dcd} @@ -24,9 +21,6 @@ GLUtil - - Logging - Render @@ -70,9 +64,6 @@ GLUtil - - Logging - Render diff --git a/Source/Core/VideoBackends/OGL/PostProcessing.cpp b/Source/Core/VideoBackends/OGL/PostProcessing.cpp index 9de1a85326..57d8f7c8f8 100644 --- a/Source/Core/VideoBackends/OGL/PostProcessing.cpp +++ b/Source/Core/VideoBackends/OGL/PostProcessing.cpp @@ -198,11 +198,6 @@ void OpenGLPostProcessing::CreateHeader() "#define SampleOffset(offset) textureOffset(samp9, float3(uv0, layer), offset)\n" - "float4 SampleFontLocation(float2 location)\n" - "{\n" - "\treturn texture(samp8, location);\n" - "}\n" - "float2 GetResolution()\n" "{\n" "\treturn resolution.xy;\n" diff --git a/Source/Core/VideoBackends/OGL/RasterFont.cpp b/Source/Core/VideoBackends/OGL/RasterFont.cpp deleted file mode 100644 index f21ac22900..0000000000 --- a/Source/Core/VideoBackends/OGL/RasterFont.cpp +++ /dev/null @@ -1,291 +0,0 @@ -// Copyright 2008 Dolphin Emulator Project -// Licensed under GPLv2+ -// Refer to the license.txt file included. - -#include - -#include "Common/Common.h" -#include "Common/GL/GLUtil.h" - -#include "VideoBackends/OGL/ProgramShaderCache.h" -#include "VideoBackends/OGL/RasterFont.h" -#include "VideoBackends/OGL/VertexManager.h" - -// globals - -namespace OGL -{ -static const int CHARACTER_WIDTH = 8; -static const int CHARACTER_HEIGHT = 13; -static const int CHARACTER_OFFSET = 32; -static const int CHARACTER_COUNT = 95; - -static const u8 rasters[CHARACTER_COUNT][CHARACTER_HEIGHT] = { - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x36, 0x36, 0x36}, - {0x00, 0x00, 0x00, 0x66, 0x66, 0xff, 0x66, 0x66, 0xff, 0x66, 0x66, 0x00, 0x00}, - {0x00, 0x00, 0x18, 0x7e, 0xff, 0x1b, 0x1f, 0x7e, 0xf8, 0xd8, 0xff, 0x7e, 0x18}, - {0x00, 0x00, 0x0e, 0x1b, 0xdb, 0x6e, 0x30, 0x18, 0x0c, 0x76, 0xdb, 0xd8, 0x70}, - {0x00, 0x00, 0x7f, 0xc6, 0xcf, 0xd8, 0x70, 0x70, 0xd8, 0xcc, 0xcc, 0x6c, 0x38}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x1c, 0x0c, 0x0e}, - {0x00, 0x00, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x18, 0x0c}, - {0x00, 0x00, 0x30, 0x18, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x18, 0x30}, - {0x00, 0x00, 0x00, 0x00, 0x99, 0x5a, 0x3c, 0xff, 0x3c, 0x5a, 0x99, 0x00, 0x00}, - {0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0xff, 0xff, 0x18, 0x18, 0x18, 0x00, 0x00}, - {0x00, 0x00, 0x30, 0x18, 0x1c, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x00, 0x38, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x60, 0x60, 0x30, 0x30, 0x18, 0x18, 0x0c, 0x0c, 0x06, 0x06, 0x03, 0x03}, - {0x00, 0x00, 0x3c, 0x66, 0xc3, 0xe3, 0xf3, 0xdb, 0xcf, 0xc7, 0xc3, 0x66, 0x3c}, - {0x00, 0x00, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x78, 0x38, 0x18}, - {0x00, 0x00, 0xff, 0xc0, 0xc0, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x03, 0xe7, 0x7e}, - {0x00, 0x00, 0x7e, 0xe7, 0x03, 0x03, 0x07, 0x7e, 0x07, 0x03, 0x03, 0xe7, 0x7e}, - {0x00, 0x00, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0xff, 0xcc, 0x6c, 0x3c, 0x1c, 0x0c}, - {0x00, 0x00, 0x7e, 0xe7, 0x03, 0x03, 0x07, 0xfe, 0xc0, 0xc0, 0xc0, 0xc0, 0xff}, - {0x00, 0x00, 0x7e, 0xe7, 0xc3, 0xc3, 0xc7, 0xfe, 0xc0, 0xc0, 0xc0, 0xe7, 0x7e}, - {0x00, 0x00, 0x30, 0x30, 0x30, 0x30, 0x18, 0x0c, 0x06, 0x03, 0x03, 0x03, 0xff}, - {0x00, 0x00, 0x7e, 0xe7, 0xc3, 0xc3, 0xe7, 0x7e, 0xe7, 0xc3, 0xc3, 0xe7, 0x7e}, - {0x00, 0x00, 0x7e, 0xe7, 0x03, 0x03, 0x03, 0x7f, 0xe7, 0xc3, 0xc3, 0xe7, 0x7e}, - {0x00, 0x00, 0x00, 0x38, 0x38, 0x00, 0x00, 0x38, 0x38, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x30, 0x18, 0x1c, 0x1c, 0x00, 0x00, 0x1c, 0x1c, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x60, 0x30, 0x18, 0x0c, 0x06}, - {0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x03, 0x06, 0x0c, 0x18, 0x30, 0x60}, - {0x00, 0x00, 0x18, 0x00, 0x00, 0x18, 0x18, 0x0c, 0x06, 0x03, 0xc3, 0xc3, 0x7e}, - {0x00, 0x00, 0x3f, 0x60, 0xcf, 0xdb, 0xd3, 0xdd, 0xc3, 0x7e, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xc3, 0xff, 0xc3, 0xc3, 0xc3, 0x66, 0x3c, 0x18}, - {0x00, 0x00, 0xfe, 0xc7, 0xc3, 0xc3, 0xc7, 0xfe, 0xc7, 0xc3, 0xc3, 0xc7, 0xfe}, - {0x00, 0x00, 0x7e, 0xe7, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xe7, 0x7e}, - {0x00, 0x00, 0xfc, 0xce, 0xc7, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc7, 0xce, 0xfc}, - {0x00, 0x00, 0xff, 0xc0, 0xc0, 0xc0, 0xc0, 0xfc, 0xc0, 0xc0, 0xc0, 0xc0, 0xff}, - {0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xfc, 0xc0, 0xc0, 0xc0, 0xff}, - {0x00, 0x00, 0x7e, 0xe7, 0xc3, 0xc3, 0xcf, 0xc0, 0xc0, 0xc0, 0xc0, 0xe7, 0x7e}, - {0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xff, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3}, - {0x00, 0x00, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x7e}, - {0x00, 0x00, 0x7c, 0xee, 0xc6, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06}, - {0x00, 0x00, 0xc3, 0xc6, 0xcc, 0xd8, 0xf0, 0xe0, 0xf0, 0xd8, 0xcc, 0xc6, 0xc3}, - {0x00, 0x00, 0xff, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0}, - {0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xdb, 0xff, 0xff, 0xe7, 0xc3}, - {0x00, 0x00, 0xc7, 0xc7, 0xcf, 0xcf, 0xdf, 0xdb, 0xfb, 0xf3, 0xf3, 0xe3, 0xe3}, - {0x00, 0x00, 0x7e, 0xe7, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xe7, 0x7e}, - {0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xfe, 0xc7, 0xc3, 0xc3, 0xc7, 0xfe}, - {0x00, 0x00, 0x3f, 0x6e, 0xdf, 0xdb, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0x66, 0x3c}, - {0x00, 0x00, 0xc3, 0xc6, 0xcc, 0xd8, 0xf0, 0xfe, 0xc7, 0xc3, 0xc3, 0xc7, 0xfe}, - {0x00, 0x00, 0x7e, 0xe7, 0x03, 0x03, 0x07, 0x7e, 0xe0, 0xc0, 0xc0, 0xe7, 0x7e}, - {0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xff}, - {0x00, 0x00, 0x7e, 0xe7, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3}, - {0x00, 0x00, 0x18, 0x3c, 0x3c, 0x66, 0x66, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3}, - {0x00, 0x00, 0xc3, 0xe7, 0xff, 0xff, 0xdb, 0xdb, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3}, - {0x00, 0x00, 0xc3, 0x66, 0x66, 0x3c, 0x3c, 0x18, 0x3c, 0x3c, 0x66, 0x66, 0xc3}, - {0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x3c, 0x66, 0x66, 0xc3}, - {0x00, 0x00, 0xff, 0xc0, 0xc0, 0x60, 0x30, 0x7e, 0x0c, 0x06, 0x03, 0x03, 0xff}, - {0x00, 0x00, 0x3c, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x3c}, - {0x00, 0x03, 0x03, 0x06, 0x06, 0x0c, 0x0c, 0x18, 0x18, 0x30, 0x30, 0x60, 0x60}, - {0x00, 0x00, 0x3c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x3c}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0x66, 0x3c, 0x18}, - {0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x38, 0x30, 0x70}, - {0x00, 0x00, 0x7f, 0xc3, 0xc3, 0x7f, 0x03, 0xc3, 0x7e, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0xfe, 0xc3, 0xc3, 0xc3, 0xc3, 0xfe, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0}, - {0x00, 0x00, 0x7e, 0xc3, 0xc0, 0xc0, 0xc0, 0xc3, 0x7e, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x7f, 0xc3, 0xc3, 0xc3, 0xc3, 0x7f, 0x03, 0x03, 0x03, 0x03, 0x03}, - {0x00, 0x00, 0x7f, 0xc0, 0xc0, 0xfe, 0xc3, 0xc3, 0x7e, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x30, 0x30, 0x30, 0x30, 0x30, 0xfc, 0x30, 0x30, 0x30, 0x33, 0x1e}, - {0x7e, 0xc3, 0x03, 0x03, 0x7f, 0xc3, 0xc3, 0xc3, 0x7e, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xfe, 0xc0, 0xc0, 0xc0, 0xc0}, - {0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x18, 0x00}, - {0x38, 0x6c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x00, 0x00, 0x0c, 0x00}, - {0x00, 0x00, 0xc6, 0xcc, 0xf8, 0xf0, 0xd8, 0xcc, 0xc6, 0xc0, 0xc0, 0xc0, 0xc0}, - {0x00, 0x00, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x78}, - {0x00, 0x00, 0xdb, 0xdb, 0xdb, 0xdb, 0xdb, 0xdb, 0xfe, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xfc, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00}, - {0xc0, 0xc0, 0xc0, 0xfe, 0xc3, 0xc3, 0xc3, 0xc3, 0xfe, 0x00, 0x00, 0x00, 0x00}, - {0x03, 0x03, 0x03, 0x7f, 0xc3, 0xc3, 0xc3, 0xc3, 0x7f, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xe0, 0xfe, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0xfe, 0x03, 0x03, 0x7e, 0xc0, 0xc0, 0x7f, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x1c, 0x36, 0x30, 0x30, 0x30, 0x30, 0xfc, 0x30, 0x30, 0x30, 0x00}, - {0x00, 0x00, 0x7e, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x18, 0x3c, 0x3c, 0x66, 0x66, 0xc3, 0xc3, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0xc3, 0xe7, 0xff, 0xdb, 0xc3, 0xc3, 0xc3, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0xc3, 0x66, 0x3c, 0x18, 0x3c, 0x66, 0xc3, 0x00, 0x00, 0x00, 0x00}, - {0xc0, 0x60, 0x60, 0x30, 0x18, 0x3c, 0x66, 0x66, 0xc3, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0xff, 0x60, 0x30, 0x18, 0x0c, 0x06, 0xff, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x0f, 0x18, 0x18, 0x18, 0x38, 0xf0, 0x38, 0x18, 0x18, 0x18, 0x0f}, - {0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18}, - {0x00, 0x00, 0xf0, 0x18, 0x18, 0x18, 0x1c, 0x0f, 0x1c, 0x18, 0x18, 0x18, 0xf0}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x8f, 0xf1, 0x60, 0x00, 0x00, 0x00}}; - -static const char* s_vertexShaderSrc = "uniform vec2 charSize;\n" - "uniform vec2 offset;" - "in vec2 rawpos;\n" - "in vec2 rawtex0;\n" - "out vec2 uv0;\n" - "void main(void) {\n" - " gl_Position = vec4(rawpos + offset,0,1);\n" - " uv0 = rawtex0 * charSize;\n" - "}\n"; - -static const char* s_fragmentShaderSrc = "SAMPLER_BINDING(8) uniform sampler2D samp8;\n" - "uniform vec4 color;\n" - "in vec2 uv0;\n" - "out vec4 ocol0;\n" - "void main(void) {\n" - " ocol0 = texture(samp8,uv0) * color;\n" - "}\n"; - -static SHADER s_shader; - -RasterFont::RasterFont() -{ - // generate the texture - glGenTextures(1, &texture); - glActiveTexture(GL_TEXTURE8); - glBindTexture(GL_TEXTURE_2D, texture); - std::vector texture_data(CHARACTER_WIDTH * CHARACTER_COUNT * CHARACTER_HEIGHT); - for (int y = 0; y < CHARACTER_HEIGHT; y++) - { - for (int c = 0; c < CHARACTER_COUNT; c++) - { - for (int x = 0; x < CHARACTER_WIDTH; x++) - { - bool pixel = (0 != (rasters[c][y] & (1 << (CHARACTER_WIDTH - x - 1)))); - texture_data[CHARACTER_WIDTH * CHARACTER_COUNT * y + CHARACTER_WIDTH * c + x] = - pixel ? -1 : 0; - } - } - } - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, CHARACTER_WIDTH * CHARACTER_COUNT, CHARACTER_HEIGHT, 0, - GL_RGBA, GL_UNSIGNED_BYTE, texture_data.data()); - - // generate shader - ProgramShaderCache::CompileShader(s_shader, s_vertexShaderSrc, s_fragmentShaderSrc); - s_shader.Bind(); - - // bound uniforms - glUniform2f(glGetUniformLocation(s_shader.glprogid, "charSize"), 1.0f / GLfloat(CHARACTER_COUNT), - 1.0f); - uniform_color_id = glGetUniformLocation(s_shader.glprogid, "color"); - glUniform4f(uniform_color_id, 1.0f, 1.0f, 1.0f, 1.0f); - uniform_offset_id = glGetUniformLocation(s_shader.glprogid, "offset"); - glUniform2f(uniform_offset_id, 0.0f, 0.0f); - - // generate VBO & VAO - glGenBuffers(1, &VBO); - glGenVertexArrays(1, &VAO); - glBindBuffer(GL_ARRAY_BUFFER, VBO); - glBindVertexArray(VAO); - glEnableVertexAttribArray(SHADER_POSITION_ATTRIB); - glVertexAttribPointer(SHADER_POSITION_ATTRIB, 2, GL_FLOAT, 0, sizeof(GLfloat) * 4, nullptr); - glEnableVertexAttribArray(SHADER_TEXTURE0_ATTRIB); - glVertexAttribPointer(SHADER_TEXTURE0_ATTRIB, 2, GL_FLOAT, 0, sizeof(GLfloat) * 4, - (GLfloat*)nullptr + 2); - glBindBuffer(GL_ARRAY_BUFFER, - static_cast(g_vertex_manager.get())->GetVertexBufferHandle()); - ProgramShaderCache::InvalidateVertexFormat(); -} - -RasterFont::~RasterFont() -{ - glDeleteTextures(1, &texture); - glDeleteBuffers(1, &VBO); - glDeleteVertexArrays(1, &VAO); - s_shader.Destroy(); -} - -void RasterFont::printMultilineText(const std::string& text, double start_x, double start_y, - double z, int bbWidth, int bbHeight, u32 color) -{ - std::vector vertices(text.length() * 6 * 4); - - int usage = 0; - GLfloat delta_x = GLfloat(2 * CHARACTER_WIDTH) / GLfloat(bbWidth); - GLfloat delta_y = GLfloat(2 * CHARACTER_HEIGHT) / GLfloat(bbHeight); - GLfloat border_x = 2.0f / GLfloat(bbWidth); - GLfloat border_y = 4.0f / GLfloat(bbHeight); - - GLfloat x = GLfloat(start_x); - GLfloat y = GLfloat(start_y); - - for (const char& c : text) - { - if (c == '\n') - { - x = GLfloat(start_x); - y -= delta_y + border_y; - continue; - } - - // do not print spaces, they can be skipped easily - if (c == ' ') - { - x += delta_x + border_x; - continue; - } - - if (c < CHARACTER_OFFSET || c >= CHARACTER_COUNT + CHARACTER_OFFSET) - continue; - - vertices[usage++] = x; - vertices[usage++] = y; - vertices[usage++] = GLfloat(c - CHARACTER_OFFSET); - vertices[usage++] = 0.0f; - - vertices[usage++] = x + delta_x; - vertices[usage++] = y; - vertices[usage++] = GLfloat(c - CHARACTER_OFFSET + 1); - vertices[usage++] = 0.0f; - - vertices[usage++] = x + delta_x; - vertices[usage++] = y + delta_y; - vertices[usage++] = GLfloat(c - CHARACTER_OFFSET + 1); - vertices[usage++] = 1.0f; - - vertices[usage++] = x; - vertices[usage++] = y; - vertices[usage++] = GLfloat(c - CHARACTER_OFFSET); - vertices[usage++] = 0.0f; - - vertices[usage++] = x + delta_x; - vertices[usage++] = y + delta_y; - vertices[usage++] = GLfloat(c - CHARACTER_OFFSET + 1); - vertices[usage++] = 1.0f; - - vertices[usage++] = x; - vertices[usage++] = y + delta_y; - vertices[usage++] = GLfloat(c - CHARACTER_OFFSET); - vertices[usage++] = 1.0f; - - x += delta_x + border_x; - } - - if (!usage) - { - return; - } - - glBindVertexArray(VAO); - glBindBuffer(GL_ARRAY_BUFFER, VBO); - glBufferData(GL_ARRAY_BUFFER, usage * sizeof(GLfloat), vertices.data(), GL_STREAM_DRAW); - - s_shader.Bind(); - - // shadows - glUniform2f(uniform_offset_id, 2.0f / GLfloat(bbWidth), -2.0f / GLfloat(bbHeight)); - glUniform4f(uniform_color_id, 0.0f, 0.0f, 0.0f, GLfloat((color >> 24) & 0xff) / 255.f); - glDrawArrays(GL_TRIANGLES, 0, usage / 4); - - glUniform2f(uniform_offset_id, 0.0f, 0.0f); - glUniform4f(uniform_color_id, GLfloat((color >> 16) & 0xff) / 255.f, - GLfloat((color >> 8) & 0xff) / 255.f, GLfloat((color >> 0) & 0xff) / 255.f, - GLfloat((color >> 24) & 0xff) / 255.f); - glDrawArrays(GL_TRIANGLES, 0, usage / 4); - - glBindBuffer(GL_ARRAY_BUFFER, - static_cast(g_vertex_manager.get())->GetVertexBufferHandle()); - ProgramShaderCache::InvalidateVertexFormat(); -} -} diff --git a/Source/Core/VideoBackends/OGL/RasterFont.h b/Source/Core/VideoBackends/OGL/RasterFont.h deleted file mode 100644 index 359e4f8551..0000000000 --- a/Source/Core/VideoBackends/OGL/RasterFont.h +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright 2008 Dolphin Emulator Project -// Licensed under GPLv2+ -// Refer to the license.txt file included. - -#pragma once - -#include - -#include "Common/CommonTypes.h" - -namespace OGL -{ -class RasterFont -{ -public: - RasterFont(); - ~RasterFont(); - static int debug; - - void printMultilineText(const std::string& text, double x, double y, double z, int bbWidth, - int bbHeight, u32 color); - -private: - u32 VBO; - u32 VAO; - u32 texture; - u32 uniform_color_id; - u32 uniform_offset_id; -}; -} diff --git a/Source/Core/VideoBackends/OGL/Render.cpp b/Source/Core/VideoBackends/OGL/Render.cpp index c857cce083..dc724353d7 100644 --- a/Source/Core/VideoBackends/OGL/Render.cpp +++ b/Source/Core/VideoBackends/OGL/Render.cpp @@ -33,7 +33,6 @@ #include "VideoBackends/OGL/OGLTexture.h" #include "VideoBackends/OGL/PostProcessing.h" #include "VideoBackends/OGL/ProgramShaderCache.h" -#include "VideoBackends/OGL/RasterFont.h" #include "VideoBackends/OGL/SamplerCache.h" #include "VideoBackends/OGL/StreamBuffer.h" #include "VideoBackends/OGL/TextureCache.h" @@ -57,7 +56,6 @@ VideoConfig g_ogl_config; // Declarations and definitions // ---------------------------- -static std::unique_ptr s_raster_font; // 1 for no MSAA. Use s_MSAASamples > 1 to check for MSAA. static int s_MSAASamples = 1; @@ -827,8 +825,6 @@ bool Renderer::Initialize() m_current_framebuffer_height = m_target_height; m_post_processor = std::make_unique(); - s_raster_font = std::make_unique(); - return true; } @@ -839,7 +835,6 @@ void Renderer::Shutdown() UpdateActiveConfig(); - s_raster_font.reset(); m_post_processor.reset(); } @@ -862,21 +857,6 @@ Renderer::CreateFramebuffer(const AbstractTexture* color_attachment, static_cast(depth_attachment)); } -void Renderer::RenderText(const std::string& text, int left, int top, u32 color) -{ - int screen_width = m_backbuffer_width; - int screen_height = m_backbuffer_height; - if (screen_width >= 2000) - { - screen_width /= 2; - screen_height /= 2; - } - - s_raster_font->printMultilineText(text, left * 2.0f / static_cast(screen_width) - 1.0f, - 1.0f - top * 2.0f / static_cast(screen_height), 0, - screen_width, screen_height, color); -} - std::unique_ptr Renderer::CreateShaderFromSource(ShaderStage stage, const char* source, size_t length) { diff --git a/Source/Core/VideoBackends/OGL/Render.h b/Source/Core/VideoBackends/OGL/Render.h index 78f410bb52..d31a87ce6a 100644 --- a/Source/Core/VideoBackends/OGL/Render.h +++ b/Source/Core/VideoBackends/OGL/Render.h @@ -119,8 +119,6 @@ public: void Draw(u32 base_vertex, u32 num_vertices) override; void DrawIndexed(u32 base_index, u32 num_indices, u32 base_vertex) override; - void RenderText(const std::string& text, int left, int top, u32 color) override; - u32 AccessEFB(EFBAccessType type, u32 x, u32 y, u32 poke_data) override; void PokeEFB(EFBAccessType type, const EfbPokeData* points, size_t num_points) override; diff --git a/Source/Core/VideoBackends/Software/SWOGLWindow.cpp b/Source/Core/VideoBackends/Software/SWOGLWindow.cpp index 81216ff7ef..2d5b82daa2 100644 --- a/Source/Core/VideoBackends/Software/SWOGLWindow.cpp +++ b/Source/Core/VideoBackends/Software/SWOGLWindow.cpp @@ -84,11 +84,6 @@ bool SWOGLWindow::Initialize(const WindowSystemInfo& wsi) return true; } -void SWOGLWindow::PrintText(const std::string& text, int x, int y, u32 color) -{ - m_text.push_back({text, x, y, color}); -} - void SWOGLWindow::ShowImage(AbstractTexture* image, const EFBRectangle& xfb_region) { SW::SWTexture* sw_image = static_cast(image); @@ -116,11 +111,5 @@ void SWOGLWindow::ShowImage(AbstractTexture* image, const EFBRectangle& xfb_regi glBindVertexArray(m_image_vao); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); - // TODO: implement OSD - // for (TextData& text : m_text) - // { - // } - m_text.clear(); - m_gl_context->Swap(); } diff --git a/Source/Core/VideoBackends/Software/SWOGLWindow.h b/Source/Core/VideoBackends/Software/SWOGLWindow.h index 38ae316d07..403ec3dbcb 100644 --- a/Source/Core/VideoBackends/Software/SWOGLWindow.h +++ b/Source/Core/VideoBackends/Software/SWOGLWindow.h @@ -24,9 +24,6 @@ public: GLContext* GetContext() const { return m_gl_context.get(); } bool IsHeadless() const; - // Will be printed on the *next* image - void PrintText(const std::string& text, int x, int y, u32 color); - // Image to show, will be swapped immediately void ShowImage(AbstractTexture* image, const EFBRectangle& xfb_region); @@ -37,14 +34,6 @@ private: bool Initialize(const WindowSystemInfo& wsi); - struct TextData - { - std::string text; - int x, y; - u32 color; - }; - std::vector m_text; - u32 m_image_program = 0; u32 m_image_texture = 0; u32 m_image_vao = 0; diff --git a/Source/Core/VideoBackends/Software/SWRenderer.cpp b/Source/Core/VideoBackends/Software/SWRenderer.cpp index f8032f7e5d..0dac3b264b 100644 --- a/Source/Core/VideoBackends/Software/SWRenderer.cpp +++ b/Source/Core/VideoBackends/Software/SWRenderer.cpp @@ -55,11 +55,6 @@ SWRenderer::CreateFramebuffer(const AbstractTexture* color_attachment, static_cast(depth_attachment)); } -void SWRenderer::RenderText(const std::string& pstr, int left, int top, u32 color) -{ - m_window->PrintText(pstr, left, top, color); -} - class SWShader final : public AbstractShader { public: diff --git a/Source/Core/VideoBackends/Software/SWRenderer.h b/Source/Core/VideoBackends/Software/SWRenderer.h index 936139516f..563f9ace1a 100644 --- a/Source/Core/VideoBackends/Software/SWRenderer.h +++ b/Source/Core/VideoBackends/Software/SWRenderer.h @@ -32,7 +32,6 @@ public: size_t length) override; std::unique_ptr CreatePipeline(const AbstractPipelineConfig& config) override; - void RenderText(const std::string& pstr, int left, int top, u32 color) override; u32 AccessEFB(EFBAccessType type, u32 x, u32 y, u32 poke_data) override; void PokeEFB(EFBAccessType type, const EfbPokeData* points, size_t num_points) override {} u16 BBoxRead(int index) override; diff --git a/Source/Core/VideoBackends/Vulkan/CMakeLists.txt b/Source/Core/VideoBackends/Vulkan/CMakeLists.txt index 889da03f6f..5746cd1aaa 100644 --- a/Source/Core/VideoBackends/Vulkan/CMakeLists.txt +++ b/Source/Core/VideoBackends/Vulkan/CMakeLists.txt @@ -5,7 +5,6 @@ add_library(videovulkan ObjectCache.cpp PerfQuery.cpp PostProcessing.cpp - RasterFont.cpp Renderer.cpp ShaderCache.cpp ShaderCompiler.cpp diff --git a/Source/Core/VideoBackends/Vulkan/PostProcessing.cpp b/Source/Core/VideoBackends/Vulkan/PostProcessing.cpp index 88bb29eee7..57dbd3e391 100644 --- a/Source/Core/VideoBackends/Vulkan/PostProcessing.cpp +++ b/Source/Core/VideoBackends/Vulkan/PostProcessing.cpp @@ -28,9 +28,8 @@ VulkanPostProcessing::~VulkanPostProcessing() vkDestroyShaderModule(g_vulkan_context->GetDevice(), m_fragment_shader, nullptr); } -bool VulkanPostProcessing::Initialize(const Texture2D* font_texture) +bool VulkanPostProcessing::Initialize() { - m_font_texture = font_texture; if (!CompileDefaultShader()) return false; @@ -63,7 +62,6 @@ void VulkanPostProcessing::BlitFromTexture(const TargetRectangle& dst, const Tar u8* uniforms = draw.AllocatePSUniforms(uniforms_size); FillUniformBuffer(uniforms, src, src_tex, src_layer); draw.CommitPSUniforms(uniforms_size); - draw.SetPSSampler(1, m_font_texture->GetView(), g_object_cache->GetLinearSampler()); } draw.DrawQuad(dst.left, dst.top, dst.GetWidth(), dst.GetHeight(), src.left, src.top, src_layer, @@ -174,11 +172,6 @@ constexpr char POSTPROCESSING_SHADER_HEADER[] = R"( #define SampleOffset(offset) float4(textureOffset(samp0, uv0, offset).xyz, 1.0) - float4 SampleFontLocation(float2 location) - { - return texture(samp1, float3(location, 0.0)); - } - float2 GetResolution() { return options.resolution.xy; diff --git a/Source/Core/VideoBackends/Vulkan/PostProcessing.h b/Source/Core/VideoBackends/Vulkan/PostProcessing.h index 9c07c47772..e9c18b9d2d 100644 --- a/Source/Core/VideoBackends/Vulkan/PostProcessing.h +++ b/Source/Core/VideoBackends/Vulkan/PostProcessing.h @@ -21,7 +21,7 @@ public: VulkanPostProcessing() = default; ~VulkanPostProcessing(); - bool Initialize(const Texture2D* font_texture); + bool Initialize(); void BlitFromTexture(const TargetRectangle& dst, const TargetRectangle& src, const Texture2D* src_tex, int src_layer, VkRenderPass render_pass); @@ -37,7 +37,6 @@ private: bool RecompileShader(); std::string GetGLSLUniformBlock() const; - const Texture2D* m_font_texture = nullptr; VkShaderModule m_fragment_shader = VK_NULL_HANDLE; VkShaderModule m_default_fragment_shader = VK_NULL_HANDLE; }; diff --git a/Source/Core/VideoBackends/Vulkan/RasterFont.cpp b/Source/Core/VideoBackends/Vulkan/RasterFont.cpp deleted file mode 100644 index 7410ba5c86..0000000000 --- a/Source/Core/VideoBackends/Vulkan/RasterFont.cpp +++ /dev/null @@ -1,421 +0,0 @@ -// Copyright 2016 Dolphin Emulator Project -// Licensed under GPLv2+ -// Refer to the license.txt file included. - -#include "VideoBackends/Vulkan/RasterFont.h" - -#include -#include - -#include "VideoBackends/Vulkan/CommandBufferManager.h" -#include "VideoBackends/Vulkan/Texture2D.h" -#include "VideoBackends/Vulkan/Util.h" -#include "VideoBackends/Vulkan/VulkanContext.h" - -// Based on OGL RasterFont -// TODO: We should move this to common. - -namespace Vulkan -{ -constexpr int CHARACTER_WIDTH = 8; -constexpr int CHARACTER_HEIGHT = 13; -constexpr int CHARACTER_OFFSET = 32; -constexpr int CHARACTER_COUNT = 95; - -static const u8 rasters[CHARACTER_COUNT][CHARACTER_HEIGHT] = { - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x36, 0x36, 0x36}, - {0x00, 0x00, 0x00, 0x66, 0x66, 0xff, 0x66, 0x66, 0xff, 0x66, 0x66, 0x00, 0x00}, - {0x00, 0x00, 0x18, 0x7e, 0xff, 0x1b, 0x1f, 0x7e, 0xf8, 0xd8, 0xff, 0x7e, 0x18}, - {0x00, 0x00, 0x0e, 0x1b, 0xdb, 0x6e, 0x30, 0x18, 0x0c, 0x76, 0xdb, 0xd8, 0x70}, - {0x00, 0x00, 0x7f, 0xc6, 0xcf, 0xd8, 0x70, 0x70, 0xd8, 0xcc, 0xcc, 0x6c, 0x38}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x1c, 0x0c, 0x0e}, - {0x00, 0x00, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x18, 0x0c}, - {0x00, 0x00, 0x30, 0x18, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x18, 0x30}, - {0x00, 0x00, 0x00, 0x00, 0x99, 0x5a, 0x3c, 0xff, 0x3c, 0x5a, 0x99, 0x00, 0x00}, - {0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0xff, 0xff, 0x18, 0x18, 0x18, 0x00, 0x00}, - {0x00, 0x00, 0x30, 0x18, 0x1c, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x00, 0x38, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x60, 0x60, 0x30, 0x30, 0x18, 0x18, 0x0c, 0x0c, 0x06, 0x06, 0x03, 0x03}, - {0x00, 0x00, 0x3c, 0x66, 0xc3, 0xe3, 0xf3, 0xdb, 0xcf, 0xc7, 0xc3, 0x66, 0x3c}, - {0x00, 0x00, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x78, 0x38, 0x18}, - {0x00, 0x00, 0xff, 0xc0, 0xc0, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x03, 0xe7, 0x7e}, - {0x00, 0x00, 0x7e, 0xe7, 0x03, 0x03, 0x07, 0x7e, 0x07, 0x03, 0x03, 0xe7, 0x7e}, - {0x00, 0x00, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0xff, 0xcc, 0x6c, 0x3c, 0x1c, 0x0c}, - {0x00, 0x00, 0x7e, 0xe7, 0x03, 0x03, 0x07, 0xfe, 0xc0, 0xc0, 0xc0, 0xc0, 0xff}, - {0x00, 0x00, 0x7e, 0xe7, 0xc3, 0xc3, 0xc7, 0xfe, 0xc0, 0xc0, 0xc0, 0xe7, 0x7e}, - {0x00, 0x00, 0x30, 0x30, 0x30, 0x30, 0x18, 0x0c, 0x06, 0x03, 0x03, 0x03, 0xff}, - {0x00, 0x00, 0x7e, 0xe7, 0xc3, 0xc3, 0xe7, 0x7e, 0xe7, 0xc3, 0xc3, 0xe7, 0x7e}, - {0x00, 0x00, 0x7e, 0xe7, 0x03, 0x03, 0x03, 0x7f, 0xe7, 0xc3, 0xc3, 0xe7, 0x7e}, - {0x00, 0x00, 0x00, 0x38, 0x38, 0x00, 0x00, 0x38, 0x38, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x30, 0x18, 0x1c, 0x1c, 0x00, 0x00, 0x1c, 0x1c, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x60, 0x30, 0x18, 0x0c, 0x06}, - {0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x03, 0x06, 0x0c, 0x18, 0x30, 0x60}, - {0x00, 0x00, 0x18, 0x00, 0x00, 0x18, 0x18, 0x0c, 0x06, 0x03, 0xc3, 0xc3, 0x7e}, - {0x00, 0x00, 0x3f, 0x60, 0xcf, 0xdb, 0xd3, 0xdd, 0xc3, 0x7e, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xc3, 0xff, 0xc3, 0xc3, 0xc3, 0x66, 0x3c, 0x18}, - {0x00, 0x00, 0xfe, 0xc7, 0xc3, 0xc3, 0xc7, 0xfe, 0xc7, 0xc3, 0xc3, 0xc7, 0xfe}, - {0x00, 0x00, 0x7e, 0xe7, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xe7, 0x7e}, - {0x00, 0x00, 0xfc, 0xce, 0xc7, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc7, 0xce, 0xfc}, - {0x00, 0x00, 0xff, 0xc0, 0xc0, 0xc0, 0xc0, 0xfc, 0xc0, 0xc0, 0xc0, 0xc0, 0xff}, - {0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xfc, 0xc0, 0xc0, 0xc0, 0xff}, - {0x00, 0x00, 0x7e, 0xe7, 0xc3, 0xc3, 0xcf, 0xc0, 0xc0, 0xc0, 0xc0, 0xe7, 0x7e}, - {0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xff, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3}, - {0x00, 0x00, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x7e}, - {0x00, 0x00, 0x7c, 0xee, 0xc6, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06}, - {0x00, 0x00, 0xc3, 0xc6, 0xcc, 0xd8, 0xf0, 0xe0, 0xf0, 0xd8, 0xcc, 0xc6, 0xc3}, - {0x00, 0x00, 0xff, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0}, - {0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xdb, 0xff, 0xff, 0xe7, 0xc3}, - {0x00, 0x00, 0xc7, 0xc7, 0xcf, 0xcf, 0xdf, 0xdb, 0xfb, 0xf3, 0xf3, 0xe3, 0xe3}, - {0x00, 0x00, 0x7e, 0xe7, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xe7, 0x7e}, - {0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xfe, 0xc7, 0xc3, 0xc3, 0xc7, 0xfe}, - {0x00, 0x00, 0x3f, 0x6e, 0xdf, 0xdb, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0x66, 0x3c}, - {0x00, 0x00, 0xc3, 0xc6, 0xcc, 0xd8, 0xf0, 0xfe, 0xc7, 0xc3, 0xc3, 0xc7, 0xfe}, - {0x00, 0x00, 0x7e, 0xe7, 0x03, 0x03, 0x07, 0x7e, 0xe0, 0xc0, 0xc0, 0xe7, 0x7e}, - {0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xff}, - {0x00, 0x00, 0x7e, 0xe7, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3}, - {0x00, 0x00, 0x18, 0x3c, 0x3c, 0x66, 0x66, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3}, - {0x00, 0x00, 0xc3, 0xe7, 0xff, 0xff, 0xdb, 0xdb, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3}, - {0x00, 0x00, 0xc3, 0x66, 0x66, 0x3c, 0x3c, 0x18, 0x3c, 0x3c, 0x66, 0x66, 0xc3}, - {0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x3c, 0x66, 0x66, 0xc3}, - {0x00, 0x00, 0xff, 0xc0, 0xc0, 0x60, 0x30, 0x7e, 0x0c, 0x06, 0x03, 0x03, 0xff}, - {0x00, 0x00, 0x3c, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x3c}, - {0x00, 0x03, 0x03, 0x06, 0x06, 0x0c, 0x0c, 0x18, 0x18, 0x30, 0x30, 0x60, 0x60}, - {0x00, 0x00, 0x3c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x3c}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0x66, 0x3c, 0x18}, - {0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x38, 0x30, 0x70}, - {0x00, 0x00, 0x7f, 0xc3, 0xc3, 0x7f, 0x03, 0xc3, 0x7e, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0xfe, 0xc3, 0xc3, 0xc3, 0xc3, 0xfe, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0}, - {0x00, 0x00, 0x7e, 0xc3, 0xc0, 0xc0, 0xc0, 0xc3, 0x7e, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x7f, 0xc3, 0xc3, 0xc3, 0xc3, 0x7f, 0x03, 0x03, 0x03, 0x03, 0x03}, - {0x00, 0x00, 0x7f, 0xc0, 0xc0, 0xfe, 0xc3, 0xc3, 0x7e, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x30, 0x30, 0x30, 0x30, 0x30, 0xfc, 0x30, 0x30, 0x30, 0x33, 0x1e}, - {0x7e, 0xc3, 0x03, 0x03, 0x7f, 0xc3, 0xc3, 0xc3, 0x7e, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xfe, 0xc0, 0xc0, 0xc0, 0xc0}, - {0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x18, 0x00}, - {0x38, 0x6c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x00, 0x00, 0x0c, 0x00}, - {0x00, 0x00, 0xc6, 0xcc, 0xf8, 0xf0, 0xd8, 0xcc, 0xc6, 0xc0, 0xc0, 0xc0, 0xc0}, - {0x00, 0x00, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x78}, - {0x00, 0x00, 0xdb, 0xdb, 0xdb, 0xdb, 0xdb, 0xdb, 0xfe, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xfc, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00}, - {0xc0, 0xc0, 0xc0, 0xfe, 0xc3, 0xc3, 0xc3, 0xc3, 0xfe, 0x00, 0x00, 0x00, 0x00}, - {0x03, 0x03, 0x03, 0x7f, 0xc3, 0xc3, 0xc3, 0xc3, 0x7f, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xe0, 0xfe, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0xfe, 0x03, 0x03, 0x7e, 0xc0, 0xc0, 0x7f, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x1c, 0x36, 0x30, 0x30, 0x30, 0x30, 0xfc, 0x30, 0x30, 0x30, 0x00}, - {0x00, 0x00, 0x7e, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x18, 0x3c, 0x3c, 0x66, 0x66, 0xc3, 0xc3, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0xc3, 0xe7, 0xff, 0xdb, 0xc3, 0xc3, 0xc3, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0xc3, 0x66, 0x3c, 0x18, 0x3c, 0x66, 0xc3, 0x00, 0x00, 0x00, 0x00}, - {0xc0, 0x60, 0x60, 0x30, 0x18, 0x3c, 0x66, 0x66, 0xc3, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0xff, 0x60, 0x30, 0x18, 0x0c, 0x06, 0xff, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x0f, 0x18, 0x18, 0x18, 0x38, 0xf0, 0x38, 0x18, 0x18, 0x18, 0x0f}, - {0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18}, - {0x00, 0x00, 0xf0, 0x18, 0x18, 0x18, 0x1c, 0x0f, 0x1c, 0x18, 0x18, 0x18, 0xf0}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x8f, 0xf1, 0x60, 0x00, 0x00, 0x00}}; - -static const char VERTEX_SHADER_SOURCE[] = R"( - -layout(std140, push_constant) uniform PCBlock { - vec2 char_size; - vec2 offset; - vec4 color; -} PC; - -layout(location = 0) in vec4 ipos; -layout(location = 5) in vec4 icol0; -layout(location = 8) in vec3 itex0; - -layout(location = 0) out vec2 uv0; - -void main() -{ - gl_Position = vec4(ipos.xy + PC.offset, 0.0f, 1.0f); - gl_Position.y = -gl_Position.y; - uv0 = itex0.xy * PC.char_size; -} - -)"; - -static const char FRAGMENT_SHADER_SOURCE[] = R"( - -layout(std140, push_constant) uniform PCBlock { - vec2 char_size; - vec2 offset; - vec4 color; -} PC; - -layout(set = 1, binding = 0) uniform sampler2DArray samp0; - -layout(location = 0) in vec2 uv0; - -layout(location = 0) out vec4 ocol0; - -void main() -{ - ocol0 = texture(samp0, float3(uv0, 0.0)) * PC.color; -} - -)"; - -RasterFont::RasterFont() -{ -} - -RasterFont::~RasterFont() -{ - if (m_vertex_shader != VK_NULL_HANDLE) - vkDestroyShaderModule(g_vulkan_context->GetDevice(), m_vertex_shader, nullptr); - if (m_fragment_shader != VK_NULL_HANDLE) - vkDestroyShaderModule(g_vulkan_context->GetDevice(), m_fragment_shader, nullptr); -} - -const Texture2D* RasterFont::GetTexture() const -{ - return m_texture.get(); -} - -bool RasterFont::Initialize() -{ - // Create shaders and texture - if (!CreateShaders() || !CreateTexture()) - return false; - - return true; -} - -bool RasterFont::CreateTexture() -{ - // generate the texture - std::vector texture_data(CHARACTER_WIDTH * CHARACTER_COUNT * CHARACTER_HEIGHT); - for (int y = 0; y < CHARACTER_HEIGHT; y++) - { - for (int c = 0; c < CHARACTER_COUNT; c++) - { - for (int x = 0; x < CHARACTER_WIDTH; x++) - { - bool pixel = (0 != (rasters[c][y] & (1 << (CHARACTER_WIDTH - x - 1)))); - texture_data[CHARACTER_WIDTH * CHARACTER_COUNT * y + CHARACTER_WIDTH * c + x] = - pixel ? -1 : 0; - } - } - } - - // create the actual texture object - m_texture = Texture2D::Create(CHARACTER_WIDTH * CHARACTER_COUNT, CHARACTER_HEIGHT, 1, 1, - VK_FORMAT_R8G8B8A8_UNORM, VK_SAMPLE_COUNT_1_BIT, - VK_IMAGE_VIEW_TYPE_2D_ARRAY, VK_IMAGE_TILING_OPTIMAL, - VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT); - if (!m_texture) - return false; - - // create temporary buffer for uploading texture - VkBufferCreateInfo buffer_info = {VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, - nullptr, - 0, - static_cast(texture_data.size() * sizeof(u32)), - VK_BUFFER_USAGE_TRANSFER_SRC_BIT, - VK_SHARING_MODE_EXCLUSIVE, - 0, - nullptr}; - VkBuffer temp_buffer; - VkResult res = vkCreateBuffer(g_vulkan_context->GetDevice(), &buffer_info, nullptr, &temp_buffer); - if (res != VK_SUCCESS) - { - LOG_VULKAN_ERROR(res, "vkCreateBuffer failed: "); - return false; - } - - VkMemoryRequirements memory_requirements; - vkGetBufferMemoryRequirements(g_vulkan_context->GetDevice(), temp_buffer, &memory_requirements); - uint32_t memory_type_index = g_vulkan_context->GetMemoryType(memory_requirements.memoryTypeBits, - VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT); - VkMemoryAllocateInfo memory_allocate_info = {VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, nullptr, - memory_requirements.size, memory_type_index}; - VkDeviceMemory temp_buffer_memory; - res = vkAllocateMemory(g_vulkan_context->GetDevice(), &memory_allocate_info, nullptr, - &temp_buffer_memory); - if (res != VK_SUCCESS) - { - LOG_VULKAN_ERROR(res, "vkAllocateMemory failed: "); - vkDestroyBuffer(g_vulkan_context->GetDevice(), temp_buffer, nullptr); - return false; - } - - // Bind buffer to memory - res = vkBindBufferMemory(g_vulkan_context->GetDevice(), temp_buffer, temp_buffer_memory, 0); - if (res != VK_SUCCESS) - { - LOG_VULKAN_ERROR(res, "vkBindBufferMemory failed: "); - vkDestroyBuffer(g_vulkan_context->GetDevice(), temp_buffer, nullptr); - vkFreeMemory(g_vulkan_context->GetDevice(), temp_buffer_memory, nullptr); - return false; - } - - // Copy into buffer - void* mapped_ptr; - res = vkMapMemory(g_vulkan_context->GetDevice(), temp_buffer_memory, 0, buffer_info.size, 0, - &mapped_ptr); - if (res != VK_SUCCESS) - { - LOG_VULKAN_ERROR(res, "vkMapMemory failed: "); - vkDestroyBuffer(g_vulkan_context->GetDevice(), temp_buffer, nullptr); - vkFreeMemory(g_vulkan_context->GetDevice(), temp_buffer_memory, nullptr); - return false; - } - - // Copy texture data into staging buffer - memcpy(mapped_ptr, texture_data.data(), texture_data.size() * sizeof(u32)); - vkUnmapMemory(g_vulkan_context->GetDevice(), temp_buffer_memory); - - // Copy from staging buffer to the final texture - VkBufferImageCopy region = {0, - CHARACTER_WIDTH * CHARACTER_COUNT, - CHARACTER_HEIGHT, - {VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1}, - {0, 0, 0}, - {CHARACTER_WIDTH * CHARACTER_COUNT, CHARACTER_HEIGHT, 1}}; - m_texture->TransitionToLayout(g_command_buffer_mgr->GetCurrentInitCommandBuffer(), - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); - vkCmdCopyBufferToImage(g_command_buffer_mgr->GetCurrentInitCommandBuffer(), temp_buffer, - m_texture->GetImage(), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ®ion); - - // Free temp buffers after command buffer executes - m_texture->TransitionToLayout(g_command_buffer_mgr->GetCurrentInitCommandBuffer(), - VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); - g_command_buffer_mgr->DeferBufferDestruction(temp_buffer); - g_command_buffer_mgr->DeferDeviceMemoryDestruction(temp_buffer_memory); - return true; -} - -bool RasterFont::CreateShaders() -{ - m_vertex_shader = Util::CompileAndCreateVertexShader(VERTEX_SHADER_SOURCE); - m_fragment_shader = Util::CompileAndCreateFragmentShader(FRAGMENT_SHADER_SOURCE); - return m_vertex_shader != VK_NULL_HANDLE && m_fragment_shader != VK_NULL_HANDLE; -} - -void RasterFont::PrintMultiLineText(VkRenderPass render_pass, const std::string& text, - float start_x, float start_y, u32 bbWidth, u32 bbHeight, - u32 color) -{ - // skip empty strings - if (text.empty()) - return; - - UtilityShaderDraw draw(g_command_buffer_mgr->GetCurrentCommandBuffer(), - g_object_cache->GetPipelineLayout(PIPELINE_LAYOUT_PUSH_CONSTANT), - render_pass, m_vertex_shader, VK_NULL_HANDLE, m_fragment_shader, - PrimitiveType::Triangles); - - UtilityShaderVertex* vertices = draw.ReserveVertices(text.length() * 6); - size_t num_vertices = 0; - if (!vertices) - return; - - float delta_x = float(2 * CHARACTER_WIDTH) / float(bbWidth); - float delta_y = float(2 * CHARACTER_HEIGHT) / float(bbHeight); - float border_x = 2.0f / float(bbWidth); - float border_y = 4.0f / float(bbHeight); - - float x = float(start_x); - float y = float(start_y); - - for (const char& c : text) - { - if (c == '\n') - { - x = float(start_x); - y -= delta_y + border_y; - continue; - } - - // do not print spaces, they can be skipped easily - if (c == ' ') - { - x += delta_x + border_x; - continue; - } - - if (c < CHARACTER_OFFSET || c >= CHARACTER_COUNT + CHARACTER_OFFSET) - continue; - - vertices[num_vertices].SetPosition(x, y); - vertices[num_vertices].SetTextureCoordinates(static_cast(c - CHARACTER_OFFSET), 0.0f); - num_vertices++; - - vertices[num_vertices].SetPosition(x + delta_x, y); - vertices[num_vertices].SetTextureCoordinates(static_cast(c - CHARACTER_OFFSET + 1), - 0.0f); - num_vertices++; - - vertices[num_vertices].SetPosition(x + delta_x, y + delta_y); - vertices[num_vertices].SetTextureCoordinates(static_cast(c - CHARACTER_OFFSET + 1), - 1.0f); - num_vertices++; - - vertices[num_vertices].SetPosition(x, y); - vertices[num_vertices].SetTextureCoordinates(static_cast(c - CHARACTER_OFFSET), 0.0f); - num_vertices++; - - vertices[num_vertices].SetPosition(x + delta_x, y + delta_y); - vertices[num_vertices].SetTextureCoordinates(static_cast(c - CHARACTER_OFFSET + 1), - 1.0f); - num_vertices++; - - vertices[num_vertices].SetPosition(x, y + delta_y); - vertices[num_vertices].SetTextureCoordinates(static_cast(c - CHARACTER_OFFSET), 1.0f); - num_vertices++; - - x += delta_x + border_x; - } - - // skip all whitespace strings - if (num_vertices == 0) - return; - - draw.CommitVertices(num_vertices); - - struct PCBlock - { - float char_size[2]; - float offset[2]; - float color[4]; - } pc_block = {}; - - pc_block.char_size[0] = 1.0f / static_cast(CHARACTER_COUNT); - pc_block.char_size[1] = 1.0f; - - // shadows - pc_block.offset[0] = 2.0f / bbWidth; - pc_block.offset[1] = -2.0f / bbHeight; - pc_block.color[3] = (color >> 24) / 255.0f; - - draw.SetPushConstants(&pc_block, sizeof(pc_block)); - draw.SetPSSampler(0, m_texture->GetView(), g_object_cache->GetLinearSampler()); - - // Setup alpha blending - BlendingState blend_state = RenderState::GetNoBlendingBlendState(); - blend_state.blendenable = true; - blend_state.srcfactor = BlendMode::SRCALPHA; - blend_state.dstfactor = BlendMode::INVSRCALPHA; - draw.SetBlendState(blend_state); - - draw.Draw(); - - // non-shadowed part - pc_block.offset[0] = 0.0f; - pc_block.offset[1] = 0.0f; - pc_block.color[0] = ((color >> 16) & 0xFF) / 255.0f; - pc_block.color[1] = ((color >> 8) & 0xFF) / 255.0f; - pc_block.color[2] = (color & 0xFF) / 255.0f; - draw.SetPushConstants(&pc_block, sizeof(pc_block)); - draw.Draw(); -} - -} // namespace Vulkan diff --git a/Source/Core/VideoBackends/Vulkan/RasterFont.h b/Source/Core/VideoBackends/Vulkan/RasterFont.h deleted file mode 100644 index f12cf0f16c..0000000000 --- a/Source/Core/VideoBackends/Vulkan/RasterFont.h +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright 2016 Dolphin Emulator Project -// Licensed under GPLv2+ -// Refer to the license.txt file included. - -#pragma once - -#include -#include - -#include "Common/CommonTypes.h" - -#include "VideoBackends/Vulkan/Constants.h" - -namespace Vulkan -{ -class Texture2D; - -class RasterFont -{ -public: - RasterFont(); - ~RasterFont(); - - const Texture2D* GetTexture() const; - - bool Initialize(); - - void PrintMultiLineText(VkRenderPass render_pass, const std::string& text, float start_x, - float start_y, u32 bbWidth, u32 bbHeight, u32 color); - -private: - bool CreateTexture(); - bool CreateShaders(); - - std::unique_ptr m_texture; - - VkShaderModule m_vertex_shader = VK_NULL_HANDLE; - VkShaderModule m_fragment_shader = VK_NULL_HANDLE; -}; - -} // namespace Vulkan diff --git a/Source/Core/VideoBackends/Vulkan/Renderer.cpp b/Source/Core/VideoBackends/Vulkan/Renderer.cpp index 5ae6093f24..eca10a1504 100644 --- a/Source/Core/VideoBackends/Vulkan/Renderer.cpp +++ b/Source/Core/VideoBackends/Vulkan/Renderer.cpp @@ -21,7 +21,6 @@ #include "VideoBackends/Vulkan/FramebufferManager.h" #include "VideoBackends/Vulkan/ObjectCache.h" #include "VideoBackends/Vulkan/PostProcessing.h" -#include "VideoBackends/Vulkan/RasterFont.h" #include "VideoBackends/Vulkan/Renderer.h" #include "VideoBackends/Vulkan/StateTracker.h" #include "VideoBackends/Vulkan/StreamBuffer.h" @@ -89,13 +88,6 @@ bool Renderer::Initialize() return false; } - m_raster_font = std::make_unique(); - if (!m_raster_font->Initialize()) - { - PanicAlert("Failed to initialize raster font."); - return false; - } - // Swap chain render pass. if (m_swap_chain) { @@ -130,8 +122,7 @@ bool Renderer::Initialize() // Initialize post processing. m_post_processor = std::make_unique(); - if (!static_cast(m_post_processor.get()) - ->Initialize(m_raster_font->GetTexture())) + if (!static_cast(m_post_processor.get())->Initialize()) { PanicAlert("failed to initialize post processor."); return false; @@ -259,17 +250,6 @@ void Renderer::SetPipeline(const AbstractPipeline* pipeline) StateTracker::GetInstance()->SetPipeline(static_cast(pipeline)); } -void Renderer::RenderText(const std::string& text, int left, int top, u32 color) -{ - u32 backbuffer_width = m_swap_chain->GetWidth(); - u32 backbuffer_height = m_swap_chain->GetHeight(); - - m_raster_font->PrintMultiLineText(m_swap_chain_render_pass, text, - left * 2.0f / static_cast(backbuffer_width) - 1, - 1 - top * 2.0f / static_cast(backbuffer_height), - backbuffer_width, backbuffer_height, color); -} - u32 Renderer::AccessEFB(EFBAccessType type, u32 x, u32 y, u32 poke_data) { if (type == EFBAccessType::PeekColor) diff --git a/Source/Core/VideoBackends/Vulkan/Renderer.h b/Source/Core/VideoBackends/Vulkan/Renderer.h index d5e89b17e2..7d109965cc 100644 --- a/Source/Core/VideoBackends/Vulkan/Renderer.h +++ b/Source/Core/VideoBackends/Vulkan/Renderer.h @@ -22,7 +22,6 @@ class FramebufferManager; class SwapChain; class StagingTexture2D; class Texture2D; -class RasterFont; class VKFramebuffer; class VKPipeline; class VKTexture; @@ -55,7 +54,6 @@ public: SwapChain* GetSwapChain() const { return m_swap_chain.get(); } BoundingBox* GetBoundingBox() const { return m_bounding_box.get(); } - void RenderText(const std::string& pstr, int left, int top, u32 color) override; u32 AccessEFB(EFBAccessType type, u32 x, u32 y, u32 poke_data) override; void PokeEFB(EFBAccessType type, const EfbPokeData* points, size_t num_points) override; u16 BBoxRead(int index) override; @@ -128,7 +126,6 @@ private: std::unique_ptr m_swap_chain; std::unique_ptr m_bounding_box; - std::unique_ptr m_raster_font; // Keep a copy of sampler states to avoid cache lookups every draw std::array m_sampler_states = {}; diff --git a/Source/Core/VideoBackends/Vulkan/Vulkan.vcxproj b/Source/Core/VideoBackends/Vulkan/Vulkan.vcxproj index 5f1311ec9a..5b465ff733 100644 --- a/Source/Core/VideoBackends/Vulkan/Vulkan.vcxproj +++ b/Source/Core/VideoBackends/Vulkan/Vulkan.vcxproj @@ -44,7 +44,6 @@ - @@ -71,7 +70,6 @@ - diff --git a/Source/Core/VideoCommon/CMakeLists.txt b/Source/Core/VideoCommon/CMakeLists.txt index 5cf64ec74f..b29492be50 100644 --- a/Source/Core/VideoCommon/CMakeLists.txt +++ b/Source/Core/VideoCommon/CMakeLists.txt @@ -65,6 +65,7 @@ PUBLIC PRIVATE png xxhash + imgui ) if(_M_X86) diff --git a/Source/Core/VideoCommon/RenderBase.h b/Source/Core/VideoCommon/RenderBase.h index b31384794c..bc0145a0d1 100644 --- a/Source/Core/VideoCommon/RenderBase.h +++ b/Source/Core/VideoCommon/RenderBase.h @@ -159,8 +159,6 @@ public: // ImGui initialization depends on being able to create textures and pipelines, so do it last. bool InitializeImGui(); - virtual void RenderText(const std::string& text, int left, int top, u32 color) = 0; - virtual void ClearScreen(const EFBRectangle& rc, bool colorEnable, bool alphaEnable, bool zEnable, u32 color, u32 z) = 0; virtual void ReinterpretPixelData(unsigned int convtype) = 0; From 36ce47635bd6b7287252fd87847629c853dabb6f Mon Sep 17 00:00:00 2001 From: Stenzek Date: Wed, 10 Oct 2018 21:41:52 +1000 Subject: [PATCH 05/15] RenderWidget: Hook up to ImGui --- Source/Core/DolphinQt/CMakeLists.txt | 1 + Source/Core/DolphinQt/DolphinQt.vcxproj | 3 + Source/Core/DolphinQt/RenderWidget.cpp | 87 +++++++++++++++++++++++++ Source/Core/DolphinQt/RenderWidget.h | 2 + Source/Core/VideoCommon/RenderBase.cpp | 9 +++ Source/Core/VideoCommon/RenderBase.h | 6 ++ 6 files changed, 108 insertions(+) diff --git a/Source/Core/DolphinQt/CMakeLists.txt b/Source/Core/DolphinQt/CMakeLists.txt index 8e6deec6f8..3d987cae90 100644 --- a/Source/Core/DolphinQt/CMakeLists.txt +++ b/Source/Core/DolphinQt/CMakeLists.txt @@ -143,6 +143,7 @@ PRIVATE core Qt5::Widgets uicommon + imgui ) if(WIN32) diff --git a/Source/Core/DolphinQt/DolphinQt.vcxproj b/Source/Core/DolphinQt/DolphinQt.vcxproj index bd0346edd7..694f7b9f13 100644 --- a/Source/Core/DolphinQt/DolphinQt.vcxproj +++ b/Source/Core/DolphinQt/DolphinQt.vcxproj @@ -463,6 +463,9 @@ {29f29a19-f141-45ad-9679-5a2923b49da3} + + {4c3b2264-ea73-4a7b-9cfe-65b0fd635ebb} + diff --git a/Source/Core/DolphinQt/RenderWidget.cpp b/Source/Core/DolphinQt/RenderWidget.cpp index 4be5f26b1d..6953de0798 100644 --- a/Source/Core/DolphinQt/RenderWidget.cpp +++ b/Source/Core/DolphinQt/RenderWidget.cpp @@ -17,6 +17,8 @@ #include #include +#include "imgui.h" + #include "Core/ConfigManager.h" #include "Core/Core.h" #include "Core/State.h" @@ -26,6 +28,7 @@ #include "DolphinQt/Resources.h" #include "DolphinQt/Settings.h" +#include "VideoCommon/RenderBase.h" #include "VideoCommon/VertexShaderManager.h" #include "VideoCommon/VideoConfig.h" @@ -49,6 +52,8 @@ RenderWidget::RenderWidget(QWidget* parent) : QWidget(parent) connect(&Settings::Instance(), &Settings::EmulationStateChanged, this, [this](Core::State state) { SetFillBackground(SConfig::GetInstance().bRenderToMain && state == Core::State::Uninitialized); + if (state == Core::State::Running) + SetImGuiKeyMap(); }); // We have to use Qt::DirectConnection here because we don't want those signals to get queued @@ -153,6 +158,8 @@ void RenderWidget::showFullScreen() bool RenderWidget::event(QEvent* event) { + PassEventToImGui(event); + switch (event->type()) { case QEvent::Paint: @@ -244,3 +251,83 @@ void RenderWidget::OnFreeLookMouseMove(QMouseEvent* event) m_last_mouse[0] = event->x(); m_last_mouse[1] = event->y(); } + +void RenderWidget::PassEventToImGui(const QEvent* event) +{ + if (!Core::IsRunningAndStarted()) + return; + + switch (event->type()) + { + case QEvent::KeyPress: + case QEvent::KeyRelease: + { + // As the imgui KeysDown array is only 512 elements wide, and some Qt keys which + // we need to track (e.g. alt) are above this value, we mask the lower 9 bits. + // Even masked, the key codes are still unique, so conflicts aren't an issue. + // The actual text input goes through AddInputCharactersUTF8(). + const QKeyEvent* key_event = static_cast(event); + const bool is_down = event->type() == QEvent::KeyPress; + const int key = (key_event->key() & 0x1FF); + auto lock = g_renderer->GetImGuiLock(); + if (key < ArraySize(ImGui::GetIO().KeysDown)) + ImGui::GetIO().KeysDown[key] = is_down; + + if (is_down) + { + auto utf8 = key_event->text().toUtf8(); + ImGui::GetIO().AddInputCharactersUTF8(utf8.constData()); + } + } + break; + + case QEvent::MouseMove: + { + auto lock = g_renderer->GetImGuiLock(); + ImGui::GetIO().MousePos.x = static_cast(event)->x(); + ImGui::GetIO().MousePos.y = static_cast(event)->y(); + } + break; + + case QEvent::MouseButtonPress: + case QEvent::MouseButtonRelease: + { + auto lock = g_renderer->GetImGuiLock(); + const u32 button_mask = static_cast(static_cast(event)->buttons()); + for (size_t i = 0; i < ArraySize(ImGui::GetIO().MouseDown); i++) + ImGui::GetIO().MouseDown[i] = (button_mask & (1u << i)) != 0; + } + break; + + default: + break; + } +} + +void RenderWidget::SetImGuiKeyMap() +{ + static const int key_map[][2] = {{ImGuiKey_Tab, Qt::Key_Tab}, + {ImGuiKey_LeftArrow, Qt::Key_Left}, + {ImGuiKey_RightArrow, Qt::Key_Right}, + {ImGuiKey_UpArrow, Qt::Key_Up}, + {ImGuiKey_DownArrow, Qt::Key_Down}, + {ImGuiKey_PageUp, Qt::Key_PageUp}, + {ImGuiKey_PageDown, Qt::Key_PageDown}, + {ImGuiKey_Home, Qt::Key_Home}, + {ImGuiKey_End, Qt::Key_End}, + {ImGuiKey_Insert, Qt::Key_Insert}, + {ImGuiKey_Delete, Qt::Key_Delete}, + {ImGuiKey_Backspace, Qt::Key_Backspace}, + {ImGuiKey_Space, Qt::Key_Space}, + {ImGuiKey_Enter, Qt::Key_Enter}, + {ImGuiKey_Escape, Qt::Key_Escape}, + {ImGuiKey_A, Qt::Key_A}, + {ImGuiKey_C, Qt::Key_C}, + {ImGuiKey_V, Qt::Key_V}, + {ImGuiKey_X, Qt::Key_X}, + {ImGuiKey_Y, Qt::Key_Y}, + {ImGuiKey_Z, Qt::Key_Z}}; + auto lock = g_renderer->GetImGuiLock(); + for (size_t i = 0; i < ArraySize(key_map); i++) + ImGui::GetIO().KeyMap[key_map[i][0]] = (key_map[i][1] & 0x1FF); +} diff --git a/Source/Core/DolphinQt/RenderWidget.h b/Source/Core/DolphinQt/RenderWidget.h index 4d7e53f24e..a9099fd5a7 100644 --- a/Source/Core/DolphinQt/RenderWidget.h +++ b/Source/Core/DolphinQt/RenderWidget.h @@ -36,6 +36,8 @@ private: void OnKeepOnTopChanged(bool top); void SetFillBackground(bool fill); void OnFreeLookMouseMove(QMouseEvent* event); + void PassEventToImGui(const QEvent* event); + void SetImGuiKeyMap(); void dragEnterEvent(QDragEnterEvent* event) override; void dropEvent(QDropEvent* event) override; diff --git a/Source/Core/VideoCommon/RenderBase.cpp b/Source/Core/VideoCommon/RenderBase.cpp index 76f3d29864..dd988b3f5c 100644 --- a/Source/Core/VideoCommon/RenderBase.cpp +++ b/Source/Core/VideoCommon/RenderBase.cpp @@ -812,9 +812,18 @@ void Renderer::DrawImGui() } } +std::unique_lock Renderer::GetImGuiLock() +{ + return std::unique_lock(m_imgui_mutex); +} + void Renderer::Swap(u32 xfbAddr, u32 fbWidth, u32 fbStride, u32 fbHeight, const EFBRectangle& rc, u64 ticks) { + // Hold the imgui lock while we're presenting. + // It's only to prevent races on inputs anyway, at this point. + std::unique_lock imgui_lock(m_imgui_mutex); + const AspectMode suggested = g_ActiveConfig.suggested_aspect_mode; if (suggested == AspectMode::Analog || suggested == AspectMode::AnalogWide) { diff --git a/Source/Core/VideoCommon/RenderBase.h b/Source/Core/VideoCommon/RenderBase.h index bc0145a0d1..df0de0fa48 100644 --- a/Source/Core/VideoCommon/RenderBase.h +++ b/Source/Core/VideoCommon/RenderBase.h @@ -188,6 +188,11 @@ public: virtual std::unique_ptr CreateAsyncShaderCompiler(); + // Returns a lock for the ImGui mutex, enabling data structures to be modified from outside. + // Use with care, only non-drawing functions should be called from outside the video thread, + // as the drawing is tied to a "frame". + std::unique_lock GetImGuiLock(); + protected: std::tuple CalculateTargetScale(int x, int y) const; bool CalculateTargetSize(); @@ -243,6 +248,7 @@ protected: std::unique_ptr m_imgui_vertex_format; std::vector> m_imgui_textures; std::unique_ptr m_imgui_pipeline; + std::mutex m_imgui_mutex; u64 m_imgui_last_frame_time; private: From e03b8e899e14a2a57bf32ad539f7f987edc5b24c Mon Sep 17 00:00:00 2001 From: Stenzek Date: Sat, 19 Jan 2019 00:27:09 +1000 Subject: [PATCH 06/15] Vulkan: Move texture upload buffer to ObjectCache --- Source/Core/VideoBackends/Vulkan/ObjectCache.cpp | 9 +++++++++ Source/Core/VideoBackends/Vulkan/ObjectCache.h | 2 ++ Source/Core/VideoBackends/Vulkan/TextureCache.cpp | 14 -------------- Source/Core/VideoBackends/Vulkan/TextureCache.h | 3 --- Source/Core/VideoBackends/Vulkan/VKTexture.cpp | 2 +- 5 files changed, 12 insertions(+), 18 deletions(-) diff --git a/Source/Core/VideoBackends/Vulkan/ObjectCache.cpp b/Source/Core/VideoBackends/Vulkan/ObjectCache.cpp index 8f5721b4d3..1de68b8349 100644 --- a/Source/Core/VideoBackends/Vulkan/ObjectCache.cpp +++ b/Source/Core/VideoBackends/Vulkan/ObjectCache.cpp @@ -54,6 +54,15 @@ bool ObjectCache::Initialize() if (!CreateStaticSamplers()) return false; + m_texture_upload_buffer = + StreamBuffer::Create(VK_BUFFER_USAGE_TRANSFER_SRC_BIT, INITIAL_TEXTURE_UPLOAD_BUFFER_SIZE, + MAXIMUM_TEXTURE_UPLOAD_BUFFER_SIZE); + if (!m_texture_upload_buffer) + { + PanicAlert("Failed to create texture upload buffer"); + return false; + } + m_utility_shader_vertex_buffer = StreamBuffer::Create(VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, 1024 * 1024, 4 * 1024 * 1024); m_utility_shader_uniform_buffer = diff --git a/Source/Core/VideoBackends/Vulkan/ObjectCache.h b/Source/Core/VideoBackends/Vulkan/ObjectCache.h index 5b7939f95b..c3502f7c66 100644 --- a/Source/Core/VideoBackends/Vulkan/ObjectCache.h +++ b/Source/Core/VideoBackends/Vulkan/ObjectCache.h @@ -58,6 +58,7 @@ public: { return m_utility_shader_uniform_buffer.get(); } + StreamBuffer* GetTextureUploadBuffer() const { return m_texture_upload_buffer.get(); } // Static samplers VkSampler GetPointSampler() const { return m_point_sampler; } @@ -94,6 +95,7 @@ private: std::unique_ptr m_utility_shader_vertex_format; std::unique_ptr m_utility_shader_vertex_buffer; std::unique_ptr m_utility_shader_uniform_buffer; + std::unique_ptr m_texture_upload_buffer; VkSampler m_point_sampler = VK_NULL_HANDLE; VkSampler m_linear_sampler = VK_NULL_HANDLE; diff --git a/Source/Core/VideoBackends/Vulkan/TextureCache.cpp b/Source/Core/VideoBackends/Vulkan/TextureCache.cpp index e9b92ba1e1..3f26b28a7c 100644 --- a/Source/Core/VideoBackends/Vulkan/TextureCache.cpp +++ b/Source/Core/VideoBackends/Vulkan/TextureCache.cpp @@ -45,11 +45,6 @@ VkShaderModule TextureCache::GetCopyShader() const return m_copy_shader; } -StreamBuffer* TextureCache::GetTextureUploadBuffer() const -{ - return m_texture_upload_buffer.get(); -} - TextureCache* TextureCache::GetInstance() { return static_cast(g_texture_cache.get()); @@ -57,15 +52,6 @@ TextureCache* TextureCache::GetInstance() bool TextureCache::Initialize() { - m_texture_upload_buffer = - StreamBuffer::Create(VK_BUFFER_USAGE_TRANSFER_SRC_BIT, INITIAL_TEXTURE_UPLOAD_BUFFER_SIZE, - MAXIMUM_TEXTURE_UPLOAD_BUFFER_SIZE); - if (!m_texture_upload_buffer) - { - PanicAlert("Failed to create texture upload buffer"); - return false; - } - m_texture_converter = std::make_unique(); if (!m_texture_converter->Initialize()) { diff --git a/Source/Core/VideoBackends/Vulkan/TextureCache.h b/Source/Core/VideoBackends/Vulkan/TextureCache.h index fd6b57981a..35b3b6c360 100644 --- a/Source/Core/VideoBackends/Vulkan/TextureCache.h +++ b/Source/Core/VideoBackends/Vulkan/TextureCache.h @@ -49,7 +49,6 @@ public: TLUTFormat palette_format) override; VkShaderModule GetCopyShader() const; - StreamBuffer* GetTextureUploadBuffer() const; private: void CopyEFBToCacheEntry(TCacheEntry* entry, bool is_depth_copy, const EFBRectangle& src_rect, @@ -57,8 +56,6 @@ private: float gamma, bool clamp_top, bool clamp_bottom, const CopyFilterCoefficientArray& filter_coefficients) override; - std::unique_ptr m_texture_upload_buffer; - std::unique_ptr m_texture_converter; VkShaderModule m_copy_shader = VK_NULL_HANDLE; diff --git a/Source/Core/VideoBackends/Vulkan/VKTexture.cpp b/Source/Core/VideoBackends/Vulkan/VKTexture.cpp index 304c5cc908..929307edb3 100644 --- a/Source/Core/VideoBackends/Vulkan/VKTexture.cpp +++ b/Source/Core/VideoBackends/Vulkan/VKTexture.cpp @@ -290,7 +290,7 @@ void VKTexture::Load(u32 level, u32 width, u32 height, u32 row_length, const u8* if (upload_size <= STAGING_TEXTURE_UPLOAD_THRESHOLD && upload_size <= MAXIMUM_TEXTURE_UPLOAD_BUFFER_SIZE) { - StreamBuffer* stream_buffer = TextureCache::GetInstance()->GetTextureUploadBuffer(); + StreamBuffer* stream_buffer = g_object_cache->GetTextureUploadBuffer(); if (!stream_buffer->ReserveMemory(upload_size, upload_alignment)) { // Execute the command buffer first. From c9c0b8505615cb16a770d66650e89c0f41d00dc8 Mon Sep 17 00:00:00 2001 From: Stenzek Date: Sat, 19 Jan 2019 00:35:00 +1000 Subject: [PATCH 07/15] VideoBackends: Store a backbuffer 'scale' This is a scaling factor, used for hi-dpi configurations. --- Source/Core/Common/WindowSystemInfo.h | 3 +++ Source/Core/DolphinQt/MainWindow.cpp | 1 + Source/Core/VideoBackends/D3D/Render.cpp | 5 +++-- Source/Core/VideoBackends/D3D/Render.h | 2 +- Source/Core/VideoBackends/D3D/main.cpp | 3 ++- Source/Core/VideoBackends/Null/Render.cpp | 2 +- Source/Core/VideoBackends/OGL/Render.cpp | 4 ++-- Source/Core/VideoBackends/OGL/Render.h | 2 +- Source/Core/VideoBackends/OGL/main.cpp | 2 +- Source/Core/VideoBackends/Software/SWRenderer.cpp | 2 +- Source/Core/VideoBackends/Vulkan/Renderer.cpp | 4 ++-- Source/Core/VideoBackends/Vulkan/Renderer.h | 2 +- Source/Core/VideoBackends/Vulkan/main.cpp | 2 +- Source/Core/VideoCommon/RenderBase.cpp | 4 ++-- Source/Core/VideoCommon/RenderBase.h | 5 ++++- 15 files changed, 26 insertions(+), 17 deletions(-) diff --git a/Source/Core/Common/WindowSystemInfo.h b/Source/Core/Common/WindowSystemInfo.h index 897d034c2c..bea853d445 100644 --- a/Source/Core/Common/WindowSystemInfo.h +++ b/Source/Core/Common/WindowSystemInfo.h @@ -32,4 +32,7 @@ struct WindowSystemInfo // on the platform. e.g. HWND for Windows, Window for X11. If the surface is // set to nullptr, the video backend will run in headless mode. void* render_surface = nullptr; + + // Scale of the render surface. For hidpi systems, this will be >1. + float render_surface_scale = 1.0f; }; diff --git a/Source/Core/DolphinQt/MainWindow.cpp b/Source/Core/DolphinQt/MainWindow.cpp index ef9557e3db..9caf98d966 100644 --- a/Source/Core/DolphinQt/MainWindow.cpp +++ b/Source/Core/DolphinQt/MainWindow.cpp @@ -164,6 +164,7 @@ static WindowSystemInfo GetWindowSystemInfo(QWindow* window) else wsi.render_surface = window ? reinterpret_cast(window->winId()) : nullptr; #endif + wsi.render_surface_scale = window ? static_cast(window->devicePixelRatio()) : 1.0f; return wsi; } diff --git a/Source/Core/VideoBackends/D3D/Render.cpp b/Source/Core/VideoBackends/D3D/Render.cpp index aff6fe6bc0..8e98fc8832 100644 --- a/Source/Core/VideoBackends/D3D/Render.cpp +++ b/Source/Core/VideoBackends/D3D/Render.cpp @@ -62,8 +62,9 @@ typedef struct _Nv_Stereo_Image_Header #define NVSTEREO_IMAGE_SIGNATURE 0x4433564e -Renderer::Renderer(int backbuffer_width, int backbuffer_height) - : ::Renderer(backbuffer_width, backbuffer_height, AbstractTextureFormat::RGBA8) +Renderer::Renderer(int backbuffer_width, int backbuffer_height, float backbuffer_scale) + : ::Renderer(backbuffer_width, backbuffer_height, backbuffer_scale, + AbstractTextureFormat::RGBA8) { m_last_multisamples = g_ActiveConfig.iMultisamples; m_last_stereo_mode = g_ActiveConfig.stereo_mode != StereoMode::Off; diff --git a/Source/Core/VideoBackends/D3D/Render.h b/Source/Core/VideoBackends/D3D/Render.h index 68f7f2b669..fc0b95acfc 100644 --- a/Source/Core/VideoBackends/D3D/Render.h +++ b/Source/Core/VideoBackends/D3D/Render.h @@ -18,7 +18,7 @@ class D3DTexture2D; class Renderer : public ::Renderer { public: - Renderer(int backbuffer_width, int backbuffer_height); + Renderer(int backbuffer_width, int backbuffer_height, float backbuffer_scale); ~Renderer() override; StateCache& GetStateCache() { return m_state_cache; } diff --git a/Source/Core/VideoBackends/D3D/main.cpp b/Source/Core/VideoBackends/D3D/main.cpp index 684bc1350b..27c880e730 100644 --- a/Source/Core/VideoBackends/D3D/main.cpp +++ b/Source/Core/VideoBackends/D3D/main.cpp @@ -147,7 +147,8 @@ bool VideoBackend::Initialize(const WindowSystemInfo& wsi) } // internal interfaces - g_renderer = std::make_unique(backbuffer_width, backbuffer_height); + g_renderer = + std::make_unique(backbuffer_width, backbuffer_height, wsi.render_surface_scale); g_shader_cache = std::make_unique(); g_texture_cache = std::make_unique(); g_vertex_manager = std::make_unique(); diff --git a/Source/Core/VideoBackends/Null/Render.cpp b/Source/Core/VideoBackends/Null/Render.cpp index f905d95a0f..ff427626d3 100644 --- a/Source/Core/VideoBackends/Null/Render.cpp +++ b/Source/Core/VideoBackends/Null/Render.cpp @@ -14,7 +14,7 @@ namespace Null { // Init functions -Renderer::Renderer() : ::Renderer(1, 1, AbstractTextureFormat::RGBA8) +Renderer::Renderer() : ::Renderer(1, 1, 1.0f, AbstractTextureFormat::RGBA8) { UpdateActiveConfig(); } diff --git a/Source/Core/VideoBackends/OGL/Render.cpp b/Source/Core/VideoBackends/OGL/Render.cpp index dc724353d7..630cea738e 100644 --- a/Source/Core/VideoBackends/OGL/Render.cpp +++ b/Source/Core/VideoBackends/OGL/Render.cpp @@ -351,10 +351,10 @@ static void InitDriverInfo() } // Init functions -Renderer::Renderer(std::unique_ptr main_gl_context) +Renderer::Renderer(std::unique_ptr main_gl_context, float backbuffer_scale) : ::Renderer(static_cast(std::max(main_gl_context->GetBackBufferWidth(), 1u)), static_cast(std::max(main_gl_context->GetBackBufferHeight(), 1u)), - AbstractTextureFormat::RGBA8), + backbuffer_scale, AbstractTextureFormat::RGBA8), m_main_gl_context(std::move(main_gl_context)), m_current_rasterization_state(RenderState::GetInvalidRasterizationState()), m_current_depth_state(RenderState::GetInvalidDepthState()), diff --git a/Source/Core/VideoBackends/OGL/Render.h b/Source/Core/VideoBackends/OGL/Render.h index d31a87ce6a..43c110996b 100644 --- a/Source/Core/VideoBackends/OGL/Render.h +++ b/Source/Core/VideoBackends/OGL/Render.h @@ -83,7 +83,7 @@ extern VideoConfig g_ogl_config; class Renderer : public ::Renderer { public: - Renderer(std::unique_ptr main_gl_context); + Renderer(std::unique_ptr main_gl_context, float backbuffer_scale); ~Renderer() override; bool IsHeadless() const override; diff --git a/Source/Core/VideoBackends/OGL/main.cpp b/Source/Core/VideoBackends/OGL/main.cpp index c4ccbdcfd5..3624a7fd7a 100644 --- a/Source/Core/VideoBackends/OGL/main.cpp +++ b/Source/Core/VideoBackends/OGL/main.cpp @@ -172,7 +172,7 @@ bool VideoBackend::Initialize(const WindowSystemInfo& wsi) if (!InitializeGLExtensions(main_gl_context.get()) || !FillBackendInfo()) return false; - g_renderer = std::make_unique(std::move(main_gl_context)); + g_renderer = std::make_unique(std::move(main_gl_context), wsi.render_surface_scale); g_vertex_manager = std::make_unique(); g_perf_query = GetPerfQuery(); ProgramShaderCache::Init(); diff --git a/Source/Core/VideoBackends/Software/SWRenderer.cpp b/Source/Core/VideoBackends/Software/SWRenderer.cpp index 0dac3b264b..edddd5156f 100644 --- a/Source/Core/VideoBackends/Software/SWRenderer.cpp +++ b/Source/Core/VideoBackends/Software/SWRenderer.cpp @@ -25,7 +25,7 @@ #include "VideoCommon/VideoConfig.h" SWRenderer::SWRenderer(std::unique_ptr window) - : ::Renderer(static_cast(MAX_XFB_WIDTH), static_cast(MAX_XFB_HEIGHT), + : ::Renderer(static_cast(MAX_XFB_WIDTH), static_cast(MAX_XFB_HEIGHT), 1.0f, AbstractTextureFormat::RGBA8), m_window(std::move(window)) { diff --git a/Source/Core/VideoBackends/Vulkan/Renderer.cpp b/Source/Core/VideoBackends/Vulkan/Renderer.cpp index eca10a1504..683df63d21 100644 --- a/Source/Core/VideoBackends/Vulkan/Renderer.cpp +++ b/Source/Core/VideoBackends/Vulkan/Renderer.cpp @@ -46,9 +46,9 @@ namespace Vulkan { -Renderer::Renderer(std::unique_ptr swap_chain) +Renderer::Renderer(std::unique_ptr swap_chain, float backbuffer_scale) : ::Renderer(swap_chain ? static_cast(swap_chain->GetWidth()) : 1, - swap_chain ? static_cast(swap_chain->GetHeight()) : 0, + swap_chain ? static_cast(swap_chain->GetHeight()) : 0, backbuffer_scale, swap_chain ? swap_chain->GetTextureFormat() : AbstractTextureFormat::Undefined), m_swap_chain(std::move(swap_chain)) { diff --git a/Source/Core/VideoBackends/Vulkan/Renderer.h b/Source/Core/VideoBackends/Vulkan/Renderer.h index 7d109965cc..1fa3db7008 100644 --- a/Source/Core/VideoBackends/Vulkan/Renderer.h +++ b/Source/Core/VideoBackends/Vulkan/Renderer.h @@ -29,7 +29,7 @@ class VKTexture; class Renderer : public ::Renderer { public: - Renderer(std::unique_ptr swap_chain); + Renderer(std::unique_ptr swap_chain, float backbuffer_scale); ~Renderer() override; static Renderer* GetInstance(); diff --git a/Source/Core/VideoBackends/Vulkan/main.cpp b/Source/Core/VideoBackends/Vulkan/main.cpp index 63d61c9d01..af3a7b56d8 100644 --- a/Source/Core/VideoBackends/Vulkan/main.cpp +++ b/Source/Core/VideoBackends/Vulkan/main.cpp @@ -225,7 +225,7 @@ bool VideoBackend::Initialize(const WindowSystemInfo& wsi) // Create main wrapper instances. g_framebuffer_manager = std::make_unique(); - g_renderer = std::make_unique(std::move(swap_chain)); + g_renderer = std::make_unique(std::move(swap_chain), wsi.render_surface_scale); g_vertex_manager = std::make_unique(); g_texture_cache = std::make_unique(); ::g_shader_cache = std::make_unique(); diff --git a/Source/Core/VideoCommon/RenderBase.cpp b/Source/Core/VideoCommon/RenderBase.cpp index dd988b3f5c..be0e48728e 100644 --- a/Source/Core/VideoCommon/RenderBase.cpp +++ b/Source/Core/VideoCommon/RenderBase.cpp @@ -81,10 +81,10 @@ static float AspectToWidescreen(float aspect) return aspect * ((16.0f / 9.0f) / (4.0f / 3.0f)); } -Renderer::Renderer(int backbuffer_width, int backbuffer_height, +Renderer::Renderer(int backbuffer_width, int backbuffer_height, float backbuffer_scale, AbstractTextureFormat backbuffer_format) : m_backbuffer_width(backbuffer_width), m_backbuffer_height(backbuffer_height), - m_backbuffer_format(backbuffer_format) + m_backbuffer_scale(backbuffer_scale), m_backbuffer_format(backbuffer_format) { UpdateActiveConfig(); UpdateDrawRectangle(); diff --git a/Source/Core/VideoCommon/RenderBase.h b/Source/Core/VideoCommon/RenderBase.h index df0de0fa48..410d998497 100644 --- a/Source/Core/VideoCommon/RenderBase.h +++ b/Source/Core/VideoCommon/RenderBase.h @@ -63,7 +63,8 @@ extern int frameCount; class Renderer { public: - Renderer(int backbuffer_width, int backbuffer_height, AbstractTextureFormat backbuffer_format); + Renderer(int backbuffer_width, int backbuffer_height, float backbuffer_scale, + AbstractTextureFormat backbuffer_format); virtual ~Renderer(); using ClearColor = std::array; @@ -125,6 +126,7 @@ public: // Display resolution int GetBackbufferWidth() const { return m_backbuffer_width; } int GetBackbufferHeight() const { return m_backbuffer_height; } + float GetBackbufferScale() const { return m_backbuffer_scale; } void SetWindowSize(int width, int height); // EFB coordinate conversion functions @@ -229,6 +231,7 @@ protected: // Backbuffer (window) size and render area int m_backbuffer_width = 0; int m_backbuffer_height = 0; + float m_backbuffer_scale = 1.0f; AbstractTextureFormat m_backbuffer_format = AbstractTextureFormat::Undefined; TargetRectangle m_target_rectangle = {}; From f1e7fb505bc52fa3d6ed1a13e8c43d44c13cb943 Mon Sep 17 00:00:00 2001 From: Stenzek Date: Sat, 19 Jan 2019 00:35:33 +1000 Subject: [PATCH 08/15] Renderer: Scale all imgui fonts by the backbuffer scale --- Source/Core/VideoCommon/RenderBase.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Source/Core/VideoCommon/RenderBase.cpp b/Source/Core/VideoCommon/RenderBase.cpp index be0e48728e..97903d7c53 100644 --- a/Source/Core/VideoCommon/RenderBase.cpp +++ b/Source/Core/VideoCommon/RenderBase.cpp @@ -661,6 +661,10 @@ bool Renderer::InitializeImGui() // Don't create an ini file. TODO: Do we want this in the future? ImGui::GetIO().IniFilename = nullptr; + ImGui::GetIO().DisplayFramebufferScale.x = m_backbuffer_scale; + ImGui::GetIO().DisplayFramebufferScale.y = m_backbuffer_scale; + ImGui::GetIO().FontGlobalScale = m_backbuffer_scale; + ImGui::GetStyle().ScaleAllSizes(m_backbuffer_scale); PortableVertexDeclaration vdecl = {}; vdecl.position = {VAR_FLOAT, 2, offsetof(ImDrawVert, pos), true, false}; From e4b205c76937d379cd9043939e2cef1651b1a21b Mon Sep 17 00:00:00 2001 From: Stenzek Date: Wed, 28 Nov 2018 14:30:47 +1000 Subject: [PATCH 09/15] Decouple XFB scanout from presentation --- .../VideoBackends/D3D/FramebufferManager.cpp | 4 + Source/Core/VideoBackends/D3D/Render.cpp | 127 +++++------- Source/Core/VideoBackends/D3D/Render.h | 10 +- Source/Core/VideoBackends/D3D/main.cpp | 5 +- Source/Core/VideoBackends/Null/Render.cpp | 5 - Source/Core/VideoBackends/Null/Render.h | 2 - Source/Core/VideoBackends/OGL/Render.cpp | 180 ++++++------------ Source/Core/VideoBackends/OGL/Render.h | 11 +- .../VideoBackends/Software/SWOGLWindow.cpp | 4 +- .../Core/VideoBackends/Software/SWOGLWindow.h | 2 +- .../VideoBackends/Software/SWRenderer.cpp | 4 +- .../Core/VideoBackends/Software/SWRenderer.h | 2 +- Source/Core/VideoBackends/Vulkan/Renderer.cpp | 142 +++++--------- Source/Core/VideoBackends/Vulkan/Renderer.h | 13 +- Source/Core/VideoCommon/RenderBase.cpp | 139 ++++++++++---- Source/Core/VideoCommon/RenderBase.h | 52 ++++- 16 files changed, 319 insertions(+), 383 deletions(-) diff --git a/Source/Core/VideoBackends/D3D/FramebufferManager.cpp b/Source/Core/VideoBackends/D3D/FramebufferManager.cpp index e7e8fa9ddc..5a2088f40d 100644 --- a/Source/Core/VideoBackends/D3D/FramebufferManager.cpp +++ b/Source/Core/VideoBackends/D3D/FramebufferManager.cpp @@ -125,6 +125,7 @@ void FramebufferManager::BindEFBRenderTarget(bool bind_depth) FramebufferManager::FramebufferManager(int target_width, int target_height) { + static constexpr std::array clear_color = {0.0f, 0.0f, 0.0f, 1.0f}; m_target_width = static_cast(std::max(target_width, 1)); m_target_height = static_cast(std::max(target_height, 1)); DXGI_SAMPLE_DESC sample_desc; @@ -154,6 +155,7 @@ FramebufferManager::FramebufferManager(int target_width, int target_height) D3D::SetDebugObjectName(m_efb.color_tex->GetTex(), "EFB color texture"); D3D::SetDebugObjectName(m_efb.color_tex->GetSRV(), "EFB color texture shader resource view"); D3D::SetDebugObjectName(m_efb.color_tex->GetRTV(), "EFB color texture render target view"); + D3D::context->ClearRenderTargetView(m_efb.color_tex->GetRTV(), clear_color.data()); // Temporary EFB color texture - used in ReinterpretPixelData texdesc = @@ -173,6 +175,7 @@ FramebufferManager::FramebufferManager(int target_width, int target_height) "EFB color temp texture shader resource view"); D3D::SetDebugObjectName(m_efb.color_temp_tex->GetRTV(), "EFB color temp texture render target view"); + D3D::context->ClearRenderTargetView(m_efb.color_temp_tex->GetRTV(), clear_color.data()); // Integer render targets for EFB, used for logic op CD3D11_RENDER_TARGET_VIEW_DESC int_rtv_desc(m_efb.color_tex->GetTex(), @@ -222,6 +225,7 @@ FramebufferManager::FramebufferManager(int target_width, int target_height) D3D::SetDebugObjectName(m_efb.depth_tex->GetTex(), "EFB depth texture"); D3D::SetDebugObjectName(m_efb.depth_tex->GetDSV(), "EFB depth texture depth stencil view"); D3D::SetDebugObjectName(m_efb.depth_tex->GetSRV(), "EFB depth texture shader resource view"); + D3D::context->ClearDepthStencilView(m_efb.depth_tex->GetDSV(), D3D11_CLEAR_DEPTH, 0.0f, 0); // Render buffer for AccessEFB (depth data) texdesc = CD3D11_TEXTURE2D_DESC(DXGI_FORMAT_R32_FLOAT, 1, 1, 1, 1, D3D11_BIND_RENDER_TARGET); diff --git a/Source/Core/VideoBackends/D3D/Render.cpp b/Source/Core/VideoBackends/D3D/Render.cpp index 8e98fc8832..2a82924708 100644 --- a/Source/Core/VideoBackends/D3D/Render.cpp +++ b/Source/Core/VideoBackends/D3D/Render.cpp @@ -66,19 +66,10 @@ Renderer::Renderer(int backbuffer_width, int backbuffer_height, float backbuffer : ::Renderer(backbuffer_width, backbuffer_height, backbuffer_scale, AbstractTextureFormat::RGBA8) { - m_last_multisamples = g_ActiveConfig.iMultisamples; - m_last_stereo_mode = g_ActiveConfig.stereo_mode != StereoMode::Off; m_last_fullscreen_state = D3D::GetFullscreenState(); g_framebuffer_manager = std::make_unique(m_target_width, m_target_height); SetupDeviceObjects(); - // Clear EFB textures - constexpr std::array clear_color{{0.f, 0.f, 0.f, 1.f}}; - D3D::context->ClearRenderTargetView(FramebufferManager::GetEFBColorTexture()->GetRTV(), - clear_color.data()); - D3D::context->ClearDepthStencilView(FramebufferManager::GetEFBDepthTexture()->GetDSV(), - D3D11_CLEAR_DEPTH, 0.f, 0); - D3D11_VIEWPORT vp = CD3D11_VIEWPORT(0.f, 0.f, (float)m_target_width, (float)m_target_height); D3D::context->RSSetViewports(1, &vp); FramebufferManager::BindEFBRenderTarget(); @@ -560,68 +551,33 @@ void Renderer::ReinterpretPixelData(unsigned int convtype) RestoreAPIState(); } -// This function has the final picture. We adjust the aspect ratio here. -void Renderer::SwapImpl(AbstractTexture* texture, const EFBRectangle& xfb_region, u64 ticks) +void Renderer::BindBackbuffer(const ClearColor& clear_color) { - ResetAPIState(); - - // Prepare to copy the XFBs to our backbuffer CheckForSurfaceChange(); CheckForSurfaceResize(); - UpdateDrawRectangle(); - TargetRectangle targetRc = GetTargetRectangle(); - static constexpr std::array clear_color{{0.f, 0.f, 0.f, 1.f}}; D3D::context->OMSetRenderTargets(1, &D3D::GetBackBuffer()->GetRTV(), nullptr); D3D::context->ClearRenderTargetView(D3D::GetBackBuffer()->GetRTV(), clear_color.data()); m_current_framebuffer = nullptr; m_current_framebuffer_width = m_backbuffer_width; m_current_framebuffer_height = m_backbuffer_height; +} - // activate linear filtering for the buffer copies - D3D::SetLinearCopySampler(); - auto* xfb_texture = static_cast(texture); - - BlitScreen(xfb_region, targetRc, xfb_texture->GetRawTexIdentifier(), - xfb_texture->GetConfig().width, xfb_texture->GetConfig().height); - - // Reset viewport for drawing text - D3D11_VIEWPORT vp = CD3D11_VIEWPORT(0.0f, 0.0f, static_cast(m_backbuffer_width), - static_cast(m_backbuffer_height)); - D3D::context->RSSetViewports(1, &vp); - DrawImGui(); - - g_texture_cache->Cleanup(frameCount); - - // Enable configuration changes - UpdateActiveConfig(); - g_texture_cache->OnConfigChanged(g_ActiveConfig); - - // Flip/present backbuffer to frontbuffer here - if (D3D::swapchain) - D3D::Present(); +void Renderer::PresentBackbuffer() +{ + D3D::Present(); +} +void Renderer::OnConfigChanged(u32 bits) +{ // Resize the back buffers NOW to avoid flickering - if (CalculateTargetSize() || m_last_multisamples != g_ActiveConfig.iMultisamples || - m_last_stereo_mode != (g_ActiveConfig.stereo_mode != StereoMode::Off)) + if (bits & (CONFIG_CHANGE_BIT_TARGET_SIZE | CONFIG_CHANGE_BIT_MULTISAMPLES | + CONFIG_CHANGE_BIT_STEREO_MODE)) { - m_last_multisamples = g_ActiveConfig.iMultisamples; - m_last_stereo_mode = g_ActiveConfig.stereo_mode != StereoMode::Off; PixelShaderCache::InvalidateMSAAShaders(); - UpdateDrawRectangle(); - g_framebuffer_manager.reset(); g_framebuffer_manager = std::make_unique(m_target_width, m_target_height); - D3D::context->ClearRenderTargetView(FramebufferManager::GetEFBColorTexture()->GetRTV(), - clear_color.data()); - D3D::context->ClearDepthStencilView(FramebufferManager::GetEFBDepthTexture()->GetDSV(), - D3D11_CLEAR_DEPTH, 0.f, 0); } - - CheckForHostConfigChanges(); - - // begin next frame - RestoreAPIState(); } void Renderer::CheckForSurfaceChange() @@ -780,28 +736,34 @@ void Renderer::BBoxWrite(int index, u16 _value) BBox::Set(index, value); } -void Renderer::BlitScreen(TargetRectangle src, TargetRectangle dst, D3DTexture2D* src_texture, - u32 src_width, u32 src_height) +void Renderer::RenderXFBToScreen(const AbstractTexture* texture, const EFBRectangle& rc) { + const CD3D11_RECT source_rc(rc.left, rc.top, rc.right, rc.bottom); + const TargetRectangle target_rc = GetTargetRectangle(); + + // activate linear filtering for the buffer copies + D3D::SetLinearCopySampler(); + if (g_ActiveConfig.stereo_mode == StereoMode::SBS || g_ActiveConfig.stereo_mode == StereoMode::TAB) { - TargetRectangle leftRc, rightRc; - std::tie(leftRc, rightRc) = ConvertStereoRectangle(dst); + TargetRectangle left_rc, right_rc; + std::tie(left_rc, right_rc) = ConvertStereoRectangle(target_rc); - D3D11_VIEWPORT leftVp = CD3D11_VIEWPORT((float)leftRc.left, (float)leftRc.top, - (float)leftRc.GetWidth(), (float)leftRc.GetHeight()); - D3D11_VIEWPORT rightVp = CD3D11_VIEWPORT((float)rightRc.left, (float)rightRc.top, - (float)rightRc.GetWidth(), (float)rightRc.GetHeight()); - - D3D::context->RSSetViewports(1, &leftVp); - D3D::drawShadedTexQuad(src_texture->GetSRV(), src.AsRECT(), src_width, src_height, + SetViewport(static_cast(left_rc.left), static_cast(left_rc.top), + static_cast(left_rc.GetWidth()), static_cast(right_rc.GetHeight()), + 0.0f, 1.0f); + D3D::drawShadedTexQuad(static_cast(texture)->GetRawTexIdentifier()->GetSRV(), + &source_rc, texture->GetWidth(), texture->GetHeight(), PixelShaderCache::GetColorCopyProgram(false), VertexShaderCache::GetSimpleVertexShader(), VertexShaderCache::GetSimpleInputLayout(), nullptr, 0); - D3D::context->RSSetViewports(1, &rightVp); - D3D::drawShadedTexQuad(src_texture->GetSRV(), src.AsRECT(), src_width, src_height, + SetViewport(static_cast(right_rc.left), static_cast(right_rc.top), + static_cast(right_rc.GetWidth()), static_cast(right_rc.GetHeight()), + 0.0f, 1.0f); + D3D::drawShadedTexQuad(static_cast(texture)->GetRawTexIdentifier()->GetSRV(), + &source_rc, texture->GetWidth(), texture->GetHeight(), PixelShaderCache::GetColorCopyProgram(false), VertexShaderCache::GetSimpleVertexShader(), VertexShaderCache::GetSimpleInputLayout(), nullptr, 1); @@ -811,29 +773,33 @@ void Renderer::BlitScreen(TargetRectangle src, TargetRectangle dst, D3DTexture2D if (!m_3d_vision_texture) Create3DVisionTexture(m_backbuffer_width, m_backbuffer_height); - D3D11_VIEWPORT leftVp = CD3D11_VIEWPORT((float)dst.left, (float)dst.top, (float)dst.GetWidth(), - (float)dst.GetHeight()); - D3D11_VIEWPORT rightVp = CD3D11_VIEWPORT((float)(dst.left + m_backbuffer_width), (float)dst.top, - (float)dst.GetWidth(), (float)dst.GetHeight()); + const CD3D11_VIEWPORT left_vp( + static_cast(target_rc.left), static_cast(target_rc.top), + static_cast(target_rc.GetWidth()), static_cast(target_rc.GetHeight())); + const CD3D11_VIEWPORT right_vp( + static_cast(target_rc.left + m_backbuffer_width), static_cast(target_rc.top), + static_cast(target_rc.GetWidth()), static_cast(target_rc.GetHeight())); // Render to staging texture which is double the width of the backbuffer D3D::context->OMSetRenderTargets(1, &m_3d_vision_texture->GetRTV(), nullptr); - D3D::context->RSSetViewports(1, &leftVp); - D3D::drawShadedTexQuad(src_texture->GetSRV(), src.AsRECT(), src_width, src_height, + D3D::context->RSSetViewports(1, &left_vp); + D3D::drawShadedTexQuad(static_cast(texture)->GetRawTexIdentifier()->GetSRV(), + &source_rc, texture->GetWidth(), texture->GetHeight(), PixelShaderCache::GetColorCopyProgram(false), VertexShaderCache::GetSimpleVertexShader(), VertexShaderCache::GetSimpleInputLayout(), nullptr, 0); - D3D::context->RSSetViewports(1, &rightVp); - D3D::drawShadedTexQuad(src_texture->GetSRV(), src.AsRECT(), src_width, src_height, + D3D::context->RSSetViewports(1, &right_vp); + D3D::drawShadedTexQuad(static_cast(texture)->GetRawTexIdentifier()->GetSRV(), + &source_rc, texture->GetWidth(), texture->GetHeight(), PixelShaderCache::GetColorCopyProgram(false), VertexShaderCache::GetSimpleVertexShader(), VertexShaderCache::GetSimpleInputLayout(), nullptr, 1); // Copy the left eye to the backbuffer, if Nvidia 3D Vision is enabled it should // recognize the signature and automatically include the right eye frame. - D3D11_BOX box = CD3D11_BOX(0, 0, 0, m_backbuffer_width, m_backbuffer_height, 1); + const CD3D11_BOX box(0, 0, 0, m_backbuffer_width, m_backbuffer_height, 1); D3D::context->CopySubresourceRegion(D3D::GetBackBuffer()->GetTex(), 0, 0, 0, 0, m_3d_vision_texture->GetTex(), 0, &box); @@ -842,9 +808,9 @@ void Renderer::BlitScreen(TargetRectangle src, TargetRectangle dst, D3DTexture2D } else { - D3D11_VIEWPORT vp = CD3D11_VIEWPORT((float)dst.left, (float)dst.top, (float)dst.GetWidth(), - (float)dst.GetHeight()); - D3D::context->RSSetViewports(1, &vp); + SetViewport(static_cast(target_rc.left), static_cast(target_rc.top), + static_cast(target_rc.GetWidth()), static_cast(target_rc.GetHeight()), + 0.0f, 1.0f); ID3D11PixelShader* pixelShader = (g_Config.stereo_mode == StereoMode::Anaglyph) ? PixelShaderCache::GetAnaglyphProgram() : @@ -852,7 +818,8 @@ void Renderer::BlitScreen(TargetRectangle src, TargetRectangle dst, D3DTexture2D ID3D11GeometryShader* geomShader = (g_ActiveConfig.stereo_mode == StereoMode::QuadBuffer) ? GeometryShaderCache::GetCopyGeometryShader() : nullptr; - D3D::drawShadedTexQuad(src_texture->GetSRV(), src.AsRECT(), src_width, src_height, pixelShader, + D3D::drawShadedTexQuad(static_cast(texture)->GetRawTexIdentifier()->GetSRV(), + &source_rc, texture->GetWidth(), texture->GetHeight(), pixelShader, VertexShaderCache::GetSimpleVertexShader(), VertexShaderCache::GetSimpleInputLayout(), geomShader); } diff --git a/Source/Core/VideoBackends/D3D/Render.h b/Source/Core/VideoBackends/D3D/Render.h index fc0b95acfc..399babffad 100644 --- a/Source/Core/VideoBackends/D3D/Render.h +++ b/Source/Core/VideoBackends/D3D/Render.h @@ -52,6 +52,8 @@ public: float far_depth) override; void Draw(u32 base_vertex, u32 num_vertices) override; void DrawIndexed(u32 base_index, u32 num_indices, u32 base_vertex) override; + void BindBackbuffer(const ClearColor& clear_color = {}) override; + void PresentBackbuffer() override; void SetFullscreen(bool enable_fullscreen) override; bool IsFullscreen() const override; @@ -66,7 +68,8 @@ public: TargetRectangle ConvertEFBRectangle(const EFBRectangle& rc) override; - void SwapImpl(AbstractTexture* texture, const EFBRectangle& rc, u64 ticks) override; + void RenderXFBToScreen(const AbstractTexture* texture, const EFBRectangle& rc) override; + void OnConfigChanged(u32 bits) override; void ClearScreen(const EFBRectangle& rc, bool colorEnable, bool alphaEnable, bool zEnable, u32 color, u32 z) override; @@ -81,9 +84,6 @@ private: void CheckForSurfaceResize(); void UpdateBackbufferSize(); - void BlitScreen(TargetRectangle src, TargetRectangle dst, D3DTexture2D* src_texture, - u32 src_width, u32 src_height); - StateCache m_state_cache; std::array m_clear_blend_states{}; @@ -95,8 +95,6 @@ private: ID3D11Texture2D* m_screenshot_texture = nullptr; D3DTexture2D* m_3d_vision_texture = nullptr; - u32 m_last_multisamples = 1; - bool m_last_stereo_mode = false; bool m_last_fullscreen_state = false; }; } diff --git a/Source/Core/VideoBackends/D3D/main.cpp b/Source/Core/VideoBackends/D3D/main.cpp index 27c880e730..5795fce3a2 100644 --- a/Source/Core/VideoBackends/D3D/main.cpp +++ b/Source/Core/VideoBackends/D3D/main.cpp @@ -157,13 +157,14 @@ bool VideoBackend::Initialize(const WindowSystemInfo& wsi) VertexShaderCache::Init(); PixelShaderCache::Init(); GeometryShaderCache::Init(); - if (!g_shader_cache->Initialize()) + + if (!g_renderer->Initialize() || !g_shader_cache->Initialize()) return false; D3D::InitUtils(); BBox::Init(); - return g_renderer->Initialize(); + return true; } void VideoBackend::Shutdown() diff --git a/Source/Core/VideoBackends/Null/Render.cpp b/Source/Core/VideoBackends/Null/Render.cpp index ff427626d3..d076e0f091 100644 --- a/Source/Core/VideoBackends/Null/Render.cpp +++ b/Source/Core/VideoBackends/Null/Render.cpp @@ -92,9 +92,4 @@ TargetRectangle Renderer::ConvertEFBRectangle(const EFBRectangle& rc) return result; } -void Renderer::SwapImpl(AbstractTexture*, const EFBRectangle&, u64) -{ - UpdateActiveConfig(); -} - } // namespace Null diff --git a/Source/Core/VideoBackends/Null/Render.h b/Source/Core/VideoBackends/Null/Render.h index 6567b239fb..75c4adfffc 100644 --- a/Source/Core/VideoBackends/Null/Render.h +++ b/Source/Core/VideoBackends/Null/Render.h @@ -35,8 +35,6 @@ public: void BBoxWrite(int index, u16 value) override {} TargetRectangle ConvertEFBRectangle(const EFBRectangle& rc) override; - void SwapImpl(AbstractTexture* texture, const EFBRectangle& rc, u64 ticks) override; - void ClearScreen(const EFBRectangle& rc, bool colorEnable, bool alphaEnable, bool zEnable, u32 color, u32 z) override { diff --git a/Source/Core/VideoBackends/OGL/Render.cpp b/Source/Core/VideoBackends/OGL/Render.cpp index 630cea738e..35ec1a6715 100644 --- a/Source/Core/VideoBackends/OGL/Render.cpp +++ b/Source/Core/VideoBackends/OGL/Render.cpp @@ -59,10 +59,6 @@ VideoConfig g_ogl_config; // 1 for no MSAA. Use s_MSAASamples > 1 to check for MSAA. static int s_MSAASamples = 1; -static u32 s_last_multisamples = 1; -static bool s_last_stereo_mode = false; - -static bool s_vsync; // EFB cache related static const u32 EFB_CACHE_RECT_SIZE = 64; // Cache 64x64 blocks. @@ -725,9 +721,6 @@ Renderer::Renderer(std::unique_ptr main_gl_context, float backbuffer_ g_Config.VerifyValidity(); UpdateActiveConfig(); - // Since we modify the config here, we need to update the last host bits, it may have changed. - m_last_host_config_bits = ShaderHostConfig::GetCurrent().bits; - OSD::AddMessage(StringFromFormat("Video Info: %s, %s, %s", g_ogl_config.gl_vendor, g_ogl_config.gl_renderer, g_ogl_config.gl_version), 5000); @@ -756,15 +749,9 @@ Renderer::Renderer(std::unique_ptr main_gl_context, float backbuffer_ g_ogl_config.bSupportsCopySubImage ? "" : "CopyImageSubData ", g_ActiveConfig.backend_info.bSupportsDepthClamp ? "" : "DepthClamp "); - s_last_multisamples = g_ActiveConfig.iMultisamples; - s_MSAASamples = s_last_multisamples; - - s_last_stereo_mode = g_ActiveConfig.stereo_mode != StereoMode::Off; - // Handle VSync on/off - s_vsync = g_ActiveConfig.IsVSync(); if (!DriverDetails::HasBug(DriverDetails::BUG_BROKEN_VSYNC)) - m_main_gl_context->SwapInterval(s_vsync); + m_main_gl_context->SwapInterval(g_ActiveConfig.IsVSync()); // Because of the fixed framebuffer size we need to disable the resolution // options while running @@ -1220,37 +1207,55 @@ void Renderer::ClearScreen(const EFBRectangle& rc, bool colorEnable, bool alphaE ClearEFBCache(); } -void Renderer::BlitScreen(TargetRectangle src, TargetRectangle dst, GLuint src_texture, - int src_width, int src_height) +void Renderer::RenderXFBToScreen(const AbstractTexture* texture, const EFBRectangle& rc) { + TargetRectangle source_rc = rc; + source_rc.top = rc.GetHeight(); + source_rc.bottom = 0; + + // Check if we need to render to a new surface. + TargetRectangle flipped_trc = GetTargetRectangle(); + std::swap(flipped_trc.top, flipped_trc.bottom); + + // Copy the framebuffer to screen. OpenGLPostProcessing* post_processor = static_cast(m_post_processor.get()); if (g_ActiveConfig.stereo_mode == StereoMode::SBS || g_ActiveConfig.stereo_mode == StereoMode::TAB) { - TargetRectangle leftRc, rightRc; + TargetRectangle left_rc, right_rc; // Top-and-Bottom mode needs to compensate for inverted vertical screen coordinates. if (g_ActiveConfig.stereo_mode == StereoMode::TAB) - std::tie(rightRc, leftRc) = ConvertStereoRectangle(dst); + std::tie(right_rc, left_rc) = ConvertStereoRectangle(flipped_trc); else - std::tie(leftRc, rightRc) = ConvertStereoRectangle(dst); + std::tie(left_rc, right_rc) = ConvertStereoRectangle(flipped_trc); - post_processor->BlitFromTexture(src, leftRc, src_texture, src_width, src_height, 0); - post_processor->BlitFromTexture(src, rightRc, src_texture, src_width, src_height, 1); + post_processor->BlitFromTexture(source_rc, left_rc, + static_cast(texture)->GetRawTexIdentifier(), + texture->GetWidth(), texture->GetHeight(), 0); + post_processor->BlitFromTexture(source_rc, right_rc, + static_cast(texture)->GetRawTexIdentifier(), + texture->GetWidth(), texture->GetHeight(), 1); } else if (g_ActiveConfig.stereo_mode == StereoMode::QuadBuffer) { glDrawBuffer(GL_BACK_LEFT); - post_processor->BlitFromTexture(src, dst, src_texture, src_width, src_height, 0); + post_processor->BlitFromTexture(source_rc, flipped_trc, + static_cast(texture)->GetRawTexIdentifier(), + texture->GetWidth(), texture->GetHeight(), 0); glDrawBuffer(GL_BACK_RIGHT); - post_processor->BlitFromTexture(src, dst, src_texture, src_width, src_height, 1); + post_processor->BlitFromTexture(source_rc, flipped_trc, + static_cast(texture)->GetRawTexIdentifier(), + texture->GetWidth(), texture->GetHeight(), 1); glDrawBuffer(GL_BACK); } else { - post_processor->BlitFromTexture(src, dst, src_texture, src_width, src_height, 0); + post_processor->BlitFromTexture(source_rc, flipped_trc, + static_cast(texture)->GetRawTexIdentifier(), + texture->GetWidth(), texture->GetHeight(), 0); } } @@ -1385,8 +1390,20 @@ void Renderer::ApplyBlendingState(const BlendingState state, bool force) m_current_blend_state = state; } -// This function has the final picture. We adjust the aspect ratio here. -void Renderer::SwapImpl(AbstractTexture* texture, const EFBRectangle& xfb_region, u64 ticks) +void Renderer::BindBackbuffer(const ClearColor& clear_color) +{ + CheckForSurfaceChange(); + CheckForSurfaceResize(); + + glBindFramebuffer(GL_FRAMEBUFFER, 0); + glClearColor(0, 0, 0, 0); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + m_current_framebuffer = nullptr; + m_current_framebuffer_width = m_backbuffer_width; + m_current_framebuffer_height = m_backbuffer_height; +} + +void Renderer::PresentBackbuffer() { if (g_ogl_config.bSupportsDebug) { @@ -1396,72 +1413,22 @@ void Renderer::SwapImpl(AbstractTexture* texture, const EFBRectangle& xfb_region glDisable(GL_DEBUG_OUTPUT); } - auto* xfb_texture = static_cast(texture); + // Swap the back and front buffers, presenting the image. + m_main_gl_context->Swap(); +} - TargetRectangle sourceRc = xfb_region; - sourceRc.top = xfb_region.GetHeight(); - sourceRc.bottom = 0; - - ResetAPIState(); - - // Check if we need to render to a new surface. - CheckForSurfaceChange(); - CheckForSurfaceResize(); - UpdateDrawRectangle(); - TargetRectangle flipped_trc = GetTargetRectangle(); - std::swap(flipped_trc.top, flipped_trc.bottom); - - // Skip screen rendering when running in headless mode. - if (!IsHeadless()) +void Renderer::OnConfigChanged(u32 bits) +{ + if (bits & (CONFIG_CHANGE_BIT_TARGET_SIZE | CONFIG_CHANGE_BIT_MULTISAMPLES | + CONFIG_CHANGE_BIT_STEREO_MODE | CONFIG_CHANGE_BIT_BBOX)) { - // Clear the framebuffer before drawing anything. - glBindFramebuffer(GL_FRAMEBUFFER, 0); - glClearColor(0, 0, 0, 0); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - m_current_framebuffer = nullptr; - m_current_framebuffer_width = m_backbuffer_width; - m_current_framebuffer_height = m_backbuffer_height; - - // Copy the framebuffer to screen. - BlitScreen(sourceRc, flipped_trc, xfb_texture->GetRawTexIdentifier(), - xfb_texture->GetConfig().width, xfb_texture->GetConfig().height); - - // Render OSD messages. - glViewport(0, 0, m_backbuffer_width, m_backbuffer_height); - DrawImGui(); - - // Swap the back and front buffers, presenting the image. - m_main_gl_context->Swap(); - } - else - { - // Since we're not swapping in headless mode, ensure all commands are sent to the GPU. - // Otherwise the driver could batch several frames togehter. - glFlush(); - } - - // Was the size changed since the last frame? - bool target_size_changed = CalculateTargetSize(); - bool stencil_buffer_enabled = - static_cast(g_framebuffer_manager.get())->HasStencilBuffer(); - - bool fb_needs_update = target_size_changed || - s_last_multisamples != g_ActiveConfig.iMultisamples || - stencil_buffer_enabled != BoundingBox::NeedsStencilBuffer() || - s_last_stereo_mode != (g_ActiveConfig.stereo_mode != StereoMode::Off); - - if (fb_needs_update) - { - s_last_stereo_mode = g_ActiveConfig.stereo_mode != StereoMode::Off; - s_last_multisamples = g_ActiveConfig.iMultisamples; - s_MSAASamples = s_last_multisamples; - + s_MSAASamples = g_ActiveConfig.iMultisamples; if (s_MSAASamples > 1 && s_MSAASamples > g_ogl_config.max_samples) { s_MSAASamples = g_ogl_config.max_samples; OSD::AddMessage( StringFromFormat("%d Anti Aliasing samples selected, but only %d supported by your GPU.", - s_last_multisamples, g_ogl_config.max_samples), + s_MSAASamples, g_ogl_config.max_samples), 10000); } @@ -1469,40 +1436,13 @@ void Renderer::SwapImpl(AbstractTexture* texture, const EFBRectangle& xfb_region g_framebuffer_manager = std::make_unique( m_target_width, m_target_height, s_MSAASamples, BoundingBox::NeedsStencilBuffer()); BoundingBox::SetTargetSizeChanged(m_target_width, m_target_height); - UpdateDrawRectangle(); } - if (s_vsync != g_ActiveConfig.IsVSync()) - { - s_vsync = g_ActiveConfig.IsVSync(); - if (!DriverDetails::HasBug(DriverDetails::BUG_BROKEN_VSYNC)) - m_main_gl_context->SwapInterval(s_vsync); - } + if (bits & CONFIG_CHANGE_BIT_VSYNC && !DriverDetails::HasBug(DriverDetails::BUG_BROKEN_VSYNC)) + m_main_gl_context->SwapInterval(g_ActiveConfig.IsVSync()); - // Clean out old stuff from caches. It's not worth it to clean out the shader caches. - g_texture_cache->Cleanup(frameCount); - - RestoreAPIState(); - - g_Config.iSaveTargetId = 0; - - int old_anisotropy = g_ActiveConfig.iMaxAnisotropy; - UpdateActiveConfig(); - g_texture_cache->OnConfigChanged(g_ActiveConfig); - - if (old_anisotropy != g_ActiveConfig.iMaxAnisotropy) + if (bits & CONFIG_CHANGE_BIT_ANISOTROPY) g_sampler_cache->Clear(); - - // Invalidate shader cache when the host config changes. - CheckForHostConfigChanges(); - - // For testing zbuffer targets. - // Renderer::SetZBufferRender(); - // SaveTexture("tex.png", GL_TEXTURE_2D, s_FakeZTarget, - // GetTargetWidth(), GetTargetHeight()); - - // Invalidate EFB cache - ClearEFBCache(); } void Renderer::Flush() @@ -1535,15 +1475,6 @@ void Renderer::CheckForSurfaceResize() m_backbuffer_height = m_main_gl_context->GetBackBufferHeight(); } -void Renderer::DrawEFB(GLuint framebuffer, const TargetRectangle& target_rc, - const TargetRectangle& source_rc) -{ - // for msaa mode, we must resolve the efb content to non-msaa - GLuint tex = FramebufferManager::ResolveAndGetRenderTarget(source_rc); - glBindFramebuffer(GL_FRAMEBUFFER, framebuffer); - BlitScreen(source_rc, target_rc, tex, m_target_width, m_target_height); -} - // ALWAYS call RestoreAPIState for each ResetAPIState call you're doing void Renderer::ResetAPIState() { @@ -1671,6 +1602,7 @@ void Renderer::UnbindTexture(const AbstractTexture* texture) glActiveTexture(static_cast(GL_TEXTURE0 + i)); glBindTexture(GL_TEXTURE_2D_ARRAY, 0); + m_bound_textures[i] = nullptr; } } diff --git a/Source/Core/VideoBackends/OGL/Render.h b/Source/Core/VideoBackends/OGL/Render.h index 43c110996b..398a49377d 100644 --- a/Source/Core/VideoBackends/OGL/Render.h +++ b/Source/Core/VideoBackends/OGL/Render.h @@ -118,6 +118,8 @@ public: float far_depth) override; void Draw(u32 base_vertex, u32 num_vertices) override; void DrawIndexed(u32 base_index, u32 num_indices, u32 base_vertex) override; + void BindBackbuffer(const ClearColor& clear_color = {}) override; + void PresentBackbuffer() override; u32 AccessEFB(EFBAccessType type, u32 x, u32 y, u32 poke_data) override; void PokeEFB(EFBAccessType type, const EfbPokeData* points, size_t num_points) override; @@ -130,8 +132,9 @@ public: TargetRectangle ConvertEFBRectangle(const EFBRectangle& rc) override; - void SwapImpl(AbstractTexture* texture, const EFBRectangle& rc, u64 ticks) override; void Flush() override; + void RenderXFBToScreen(const AbstractTexture* texture, const EFBRectangle& rc) override; + void OnConfigChanged(u32 bits) override; void ClearScreen(const EFBRectangle& rc, bool colorEnable, bool alphaEnable, bool zEnable, u32 color, u32 z) override; @@ -150,12 +153,6 @@ private: void UpdateEFBCache(EFBAccessType type, u32 cacheRectIdx, const EFBRectangle& efbPixelRc, const TargetRectangle& targetPixelRc, const void* data); - void DrawEFB(GLuint framebuffer, const TargetRectangle& target_rc, - const TargetRectangle& source_rc); - - void BlitScreen(TargetRectangle src, TargetRectangle dst, GLuint src_texture, int src_width, - int src_height); - void CheckForSurfaceChange(); void CheckForSurfaceResize(); diff --git a/Source/Core/VideoBackends/Software/SWOGLWindow.cpp b/Source/Core/VideoBackends/Software/SWOGLWindow.cpp index 2d5b82daa2..91c8cf0806 100644 --- a/Source/Core/VideoBackends/Software/SWOGLWindow.cpp +++ b/Source/Core/VideoBackends/Software/SWOGLWindow.cpp @@ -84,9 +84,9 @@ bool SWOGLWindow::Initialize(const WindowSystemInfo& wsi) return true; } -void SWOGLWindow::ShowImage(AbstractTexture* image, const EFBRectangle& xfb_region) +void SWOGLWindow::ShowImage(const AbstractTexture* image, const EFBRectangle& xfb_region) { - SW::SWTexture* sw_image = static_cast(image); + const SW::SWTexture* sw_image = static_cast(image); m_gl_context->Update(); // just updates the render window position and the backbuffer size GLsizei glWidth = (GLsizei)m_gl_context->GetBackBufferWidth(); diff --git a/Source/Core/VideoBackends/Software/SWOGLWindow.h b/Source/Core/VideoBackends/Software/SWOGLWindow.h index 403ec3dbcb..f1eadc4dd5 100644 --- a/Source/Core/VideoBackends/Software/SWOGLWindow.h +++ b/Source/Core/VideoBackends/Software/SWOGLWindow.h @@ -25,7 +25,7 @@ public: bool IsHeadless() const; // Image to show, will be swapped immediately - void ShowImage(AbstractTexture* image, const EFBRectangle& xfb_region); + void ShowImage(const AbstractTexture* image, const EFBRectangle& xfb_region); static std::unique_ptr Create(const WindowSystemInfo& wsi); diff --git a/Source/Core/VideoBackends/Software/SWRenderer.cpp b/Source/Core/VideoBackends/Software/SWRenderer.cpp index edddd5156f..6369b35b20 100644 --- a/Source/Core/VideoBackends/Software/SWRenderer.cpp +++ b/Source/Core/VideoBackends/Software/SWRenderer.cpp @@ -90,12 +90,10 @@ std::unique_ptr SWRenderer::CreatePipeline(const AbstractPipel } // Called on the GPU thread -void SWRenderer::SwapImpl(AbstractTexture* texture, const EFBRectangle& xfb_region, u64 ticks) +void SWRenderer::RenderXFBToScreen(const AbstractTexture* texture, const EFBRectangle& xfb_region) { if (!IsHeadless()) m_window->ShowImage(texture, xfb_region); - - UpdateActiveConfig(); } u32 SWRenderer::AccessEFB(EFBAccessType type, u32 x, u32 y, u32 InputData) diff --git a/Source/Core/VideoBackends/Software/SWRenderer.h b/Source/Core/VideoBackends/Software/SWRenderer.h index 563f9ace1a..88c5ece360 100644 --- a/Source/Core/VideoBackends/Software/SWRenderer.h +++ b/Source/Core/VideoBackends/Software/SWRenderer.h @@ -39,7 +39,7 @@ public: TargetRectangle ConvertEFBRectangle(const EFBRectangle& rc) override; - void SwapImpl(AbstractTexture* texture, const EFBRectangle& rc, u64 ticks) override; + void RenderXFBToScreen(const AbstractTexture* texture, const EFBRectangle& rc) override; void ClearScreen(const EFBRectangle& rc, bool colorEnable, bool alphaEnable, bool zEnable, u32 color, u32 z) override; diff --git a/Source/Core/VideoBackends/Vulkan/Renderer.cpp b/Source/Core/VideoBackends/Vulkan/Renderer.cpp index 683df63d21..dbb0c6e582 100644 --- a/Source/Core/VideoBackends/Vulkan/Renderer.cpp +++ b/Source/Core/VideoBackends/Vulkan/Renderer.cpp @@ -557,76 +557,24 @@ void Renderer::ReinterpretPixelData(unsigned int convtype) BindEFBToStateTracker(); } -void Renderer::SwapImpl(AbstractTexture* texture, const EFBRectangle& xfb_region, u64 ticks) +void Renderer::Flush() { - // Pending/batched EFB pokes should be included in the final image. - FramebufferManager::GetInstance()->FlushEFBPokes(); + Util::ExecuteCurrentCommandsAndRestoreState(true, false); +} - auto* xfb_texture = static_cast(texture); - - // End the current render pass. +void Renderer::BindBackbuffer(const ClearColor& clear_color) +{ StateTracker::GetInstance()->EndRenderPass(); - StateTracker::GetInstance()->OnEndFrame(); // Handle host window resizes. CheckForSurfaceChange(); CheckForSurfaceResize(); - // There are a few variables which can alter the final window draw rectangle, and some of them - // are determined by guest state. Currently, the only way to catch these is to update every frame. - UpdateDrawRectangle(); - // Ensure the worker thread is not still submitting a previous command buffer. // In other words, the last frame has been submitted (otherwise the next call would // be a race, as the image may not have been consumed yet). g_command_buffer_mgr->PrepareToSubmitCommandBuffer(); - // Draw to the screen if we have a swap chain. - if (m_swap_chain) - { - DrawScreen(xfb_texture, xfb_region); - - // Submit the current command buffer, signaling rendering finished semaphore when it's done - // Because this final command buffer is rendering to the swap chain, we need to wait for - // the available semaphore to be signaled before executing the buffer. This final submission - // can happen off-thread in the background while we're preparing the next frame. - g_command_buffer_mgr->SubmitCommandBuffer( - true, m_image_available_semaphore, m_rendering_finished_semaphore, - m_swap_chain->GetSwapChain(), m_swap_chain->GetCurrentImageIndex()); - } - else - { - // No swap chain, just execute command buffer. - g_command_buffer_mgr->SubmitCommandBuffer(true); - } - - // NOTE: It is important that no rendering calls are made to the EFB between submitting the - // (now-previous) frame and after the below config checks are completed. If the target size - // changes, as the resize methods to not defer the destruction of the framebuffer, the current - // command buffer will contain references to a now non-existent framebuffer. - - // Prep for the next frame (get command buffer ready) before doing anything else. - BeginFrame(); - - // Restore the EFB color texture to color attachment ready for rendering the next frame. - FramebufferManager::GetInstance()->GetEFBColorTexture()->TransitionToLayout( - g_command_buffer_mgr->GetCurrentCommandBuffer(), VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); - RestoreAPIState(); - - // Determine what (if anything) has changed in the config. - CheckForConfigChanges(); - - // Clean up stale textures. - TextureCache::GetInstance()->Cleanup(frameCount); -} - -void Renderer::Flush() -{ - Util::ExecuteCurrentCommandsAndRestoreState(true, false); -} - -void Renderer::DrawScreen(VKTexture* xfb_texture, const EFBRectangle& xfb_region) -{ VkResult res; if (!g_command_buffer_mgr->CheckLastPresentFail()) { @@ -676,48 +624,65 @@ void Renderer::DrawScreen(VKTexture* xfb_texture, const EFBRectangle& xfb_region // Begin render pass for rendering to the swap chain. VkClearValue clear_value = {{{0.0f, 0.0f, 0.0f, 1.0f}}}; StateTracker::GetInstance()->BeginClearRenderPass(region, &clear_value, 1); +} - // Draw - BlitScreen(m_swap_chain_render_pass, GetTargetRectangle(), xfb_region, - xfb_texture->GetRawTexIdentifier()); - - // Draw OSD - SetViewport(0.0f, 0.0f, static_cast(backbuffer->GetWidth()), - static_cast(backbuffer->GetHeight()), 0.0f, 1.0f); - StateTracker::GetInstance()->SetPendingRebind(); - DrawImGui(); - +void Renderer::PresentBackbuffer() +{ // End drawing to backbuffer StateTracker::GetInstance()->EndRenderPass(); + StateTracker::GetInstance()->OnEndFrame(); // Transition the backbuffer to PRESENT_SRC to ensure all commands drawing // to it have finished before present. + Texture2D* backbuffer = m_swap_chain->GetCurrentTexture(); backbuffer->TransitionToLayout(g_command_buffer_mgr->GetCurrentCommandBuffer(), VK_IMAGE_LAYOUT_PRESENT_SRC_KHR); + + // Submit the current command buffer, signaling rendering finished semaphore when it's done + // Because this final command buffer is rendering to the swap chain, we need to wait for + // the available semaphore to be signaled before executing the buffer. This final submission + // can happen off-thread in the background while we're preparing the next frame. + g_command_buffer_mgr->SubmitCommandBuffer( + true, m_image_available_semaphore, m_rendering_finished_semaphore, + m_swap_chain->GetSwapChain(), m_swap_chain->GetCurrentImageIndex()); + + BeginFrame(); } -void Renderer::BlitScreen(VkRenderPass render_pass, const TargetRectangle& dst_rect, - const TargetRectangle& src_rect, const Texture2D* src_tex) +void Renderer::RenderXFBToScreen(const AbstractTexture* texture, const EFBRectangle& rc) { + const TargetRectangle target_rc = GetTargetRectangle(); + VulkanPostProcessing* post_processor = static_cast(m_post_processor.get()); if (g_ActiveConfig.stereo_mode == StereoMode::SBS || g_ActiveConfig.stereo_mode == StereoMode::TAB) { TargetRectangle left_rect; TargetRectangle right_rect; - std::tie(left_rect, right_rect) = ConvertStereoRectangle(dst_rect); + std::tie(left_rect, right_rect) = ConvertStereoRectangle(target_rc); - post_processor->BlitFromTexture(left_rect, src_rect, src_tex, 0, render_pass); - post_processor->BlitFromTexture(right_rect, src_rect, src_tex, 1, render_pass); + post_processor->BlitFromTexture(left_rect, rc, + static_cast(texture)->GetRawTexIdentifier(), + 0, m_swap_chain_render_pass); + post_processor->BlitFromTexture(right_rect, rc, + static_cast(texture)->GetRawTexIdentifier(), + 1, m_swap_chain_render_pass); } else if (g_ActiveConfig.stereo_mode == StereoMode::QuadBuffer) { - post_processor->BlitFromTexture(dst_rect, src_rect, src_tex, -1, render_pass); + post_processor->BlitFromTexture(target_rc, rc, + static_cast(texture)->GetRawTexIdentifier(), + -1, m_swap_chain_render_pass); } else { - post_processor->BlitFromTexture(dst_rect, src_rect, src_tex, 0, render_pass); + post_processor->BlitFromTexture(target_rc, rc, + static_cast(texture)->GetRawTexIdentifier(), + 0, m_swap_chain_render_pass); } + + // The post-processor uses the old-style Vulkan draws, which mess with the tracked state. + StateTracker::GetInstance()->SetPendingRebind(); } void Renderer::CheckForSurfaceChange() @@ -766,36 +731,20 @@ void Renderer::CheckForSurfaceResize() OnSwapChainResized(); } -void Renderer::CheckForConfigChanges() +void Renderer::OnConfigChanged(u32 bits) { - // Save the video config so we can compare against to determine which settings have changed. - const u32 old_multisamples = g_ActiveConfig.iMultisamples; - const int old_anisotropy = g_ActiveConfig.iMaxAnisotropy; - const bool old_force_filtering = g_ActiveConfig.bForceFiltering; - - // Copy g_Config to g_ActiveConfig. - // NOTE: This can potentially race with the UI thread, however if it does, the changes will be - // delayed until the next time CheckForConfigChanges is called. - UpdateActiveConfig(); - - // Determine which (if any) settings have changed. - const bool multisamples_changed = old_multisamples != g_ActiveConfig.iMultisamples; - const bool anisotropy_changed = old_anisotropy != g_ActiveConfig.iMaxAnisotropy; - const bool force_texture_filtering_changed = - old_force_filtering != g_ActiveConfig.bForceFiltering; - // Update texture cache settings with any changed options. TextureCache::GetInstance()->OnConfigChanged(g_ActiveConfig); // Handle settings that can cause the EFB framebuffer to change. - if (CalculateTargetSize() || multisamples_changed) + if (bits & CONFIG_CHANGE_BIT_TARGET_SIZE) RecreateEFBFramebuffer(); // MSAA samples changed, we need to recreate the EFB render pass. // If the stereoscopy mode changed, we need to recreate the buffers as well. // SSAA changed on/off, we have to recompile shaders. // Changing stereoscopy from off<->on also requires shaders to be recompiled. - if (CheckForHostConfigChanges()) + if (bits & (CONFIG_CHANGE_BIT_HOST_CONFIG | CONFIG_CHANGE_BIT_MULTISAMPLES)) { RecreateEFBFramebuffer(); RecompileShaders(); @@ -805,22 +754,21 @@ void Renderer::CheckForConfigChanges() } // For vsync, we need to change the present mode, which means recreating the swap chain. - if (m_swap_chain && g_ActiveConfig.IsVSync() != m_swap_chain->IsVSyncEnabled()) + if (m_swap_chain && bits & CONFIG_CHANGE_BIT_VSYNC) { g_command_buffer_mgr->WaitForGPUIdle(); m_swap_chain->SetVSync(g_ActiveConfig.IsVSync()); } // For quad-buffered stereo we need to change the layer count, so recreate the swap chain. - if (m_swap_chain && - (g_ActiveConfig.stereo_mode == StereoMode::QuadBuffer) != m_swap_chain->IsStereoEnabled()) + if (m_swap_chain && bits & CONFIG_CHANGE_BIT_STEREO_MODE) { g_command_buffer_mgr->WaitForGPUIdle(); m_swap_chain->RecreateSwapChain(); } // Wipe sampler cache if force texture filtering or anisotropy changes. - if (anisotropy_changed || force_texture_filtering_changed) + if (bits & (CONFIG_CHANGE_BIT_ANISOTROPY | CONFIG_CHANGE_BIT_FORCE_TEXTURE_FILTERING)) ResetSamplerStates(); // Check for a changed post-processing shader and recompile if needed. diff --git a/Source/Core/VideoBackends/Vulkan/Renderer.h b/Source/Core/VideoBackends/Vulkan/Renderer.h index 1fa3db7008..46a57a036e 100644 --- a/Source/Core/VideoBackends/Vulkan/Renderer.h +++ b/Source/Core/VideoBackends/Vulkan/Renderer.h @@ -60,8 +60,9 @@ public: void BBoxWrite(int index, u16 value) override; TargetRectangle ConvertEFBRectangle(const EFBRectangle& rc) override; - void SwapImpl(AbstractTexture* texture, const EFBRectangle& rc, u64 ticks) override; void Flush() override; + void RenderXFBToScreen(const AbstractTexture* texture, const EFBRectangle& rc) override; + void OnConfigChanged(u32 bits) override; void ClearScreen(const EFBRectangle& rc, bool color_enable, bool alpha_enable, bool z_enable, u32 color, u32 z) override; @@ -88,6 +89,8 @@ public: float far_depth) override; void Draw(u32 base_vertex, u32 num_vertices) override; void DrawIndexed(u32 base_index, u32 num_indices, u32 base_vertex) override; + void BindBackbuffer(const ClearColor& clear_color = {}) override; + void PresentBackbuffer() override; private: bool CreateSemaphores(); @@ -97,7 +100,6 @@ private: void CheckForSurfaceChange(); void CheckForSurfaceResize(); - void CheckForConfigChanges(); void ResetSamplerStates(); @@ -110,13 +112,6 @@ private: bool CompileShaders(); void DestroyShaders(); - // Draw the frame, as well as the OSD to the swap chain. - void DrawScreen(VKTexture* xfb_texture, const EFBRectangle& xfb_region); - - // Copies/scales an image to the currently-bound framebuffer. - void BlitScreen(VkRenderPass render_pass, const TargetRectangle& dst_rect, - const TargetRectangle& src_rect, const Texture2D* src_tex); - std::tuple UpdateUtilityUniformBuffer(const void* uniforms, u32 uniforms_size); VkSemaphore m_image_available_semaphore = VK_NULL_HANDLE; diff --git a/Source/Core/VideoCommon/RenderBase.cpp b/Source/Core/VideoCommon/RenderBase.cpp index 97903d7c53..aef425a726 100644 --- a/Source/Core/VideoCommon/RenderBase.cpp +++ b/Source/Core/VideoCommon/RenderBase.cpp @@ -91,9 +91,6 @@ Renderer::Renderer(int backbuffer_width, int backbuffer_height, float backbuffer CalculateTargetSize(); m_aspect_wide = SConfig::GetInstance().bWii && Config::Get(Config::SYSCONF_WIDESCREEN); - - m_last_host_config_bits = ShaderHostConfig::GetCurrent().bits; - m_last_efb_multisamples = g_ActiveConfig.iMultisamples; } Renderer::~Renderer() = default; @@ -239,24 +236,56 @@ void Renderer::SaveScreenshot(const std::string& filename, bool wait_for_complet } } -bool Renderer::CheckForHostConfigChanges() +void Renderer::CheckForConfigChanges() { + const ShaderHostConfig old_shader_host_config = ShaderHostConfig::GetCurrent(); + const StereoMode old_stereo = g_ActiveConfig.stereo_mode; + const u32 old_multisamples = g_ActiveConfig.iMultisamples; + const int old_anisotropy = g_ActiveConfig.iMaxAnisotropy; + const bool old_force_filtering = g_ActiveConfig.bForceFiltering; + const bool old_vsync = g_ActiveConfig.IsVSync(); + const bool old_bbox = g_ActiveConfig.bBBoxEnable; + + UpdateActiveConfig(); + + // Update texture cache settings with any changed options. + g_texture_cache->OnConfigChanged(g_ActiveConfig); + + // Determine which (if any) settings have changed. ShaderHostConfig new_host_config = ShaderHostConfig::GetCurrent(); - if (new_host_config.bits == m_last_host_config_bits && - m_last_efb_multisamples == g_ActiveConfig.iMultisamples) + u32 changed_bits = 0; + if (old_shader_host_config.bits != new_host_config.bits) + changed_bits |= CONFIG_CHANGE_BIT_HOST_CONFIG; + if (old_stereo != g_ActiveConfig.stereo_mode) + changed_bits |= CONFIG_CHANGE_BIT_STEREO_MODE; + if (old_multisamples != g_ActiveConfig.iMultisamples) + changed_bits |= CONFIG_CHANGE_BIT_MULTISAMPLES; + if (old_anisotropy != g_ActiveConfig.iMaxAnisotropy) + changed_bits |= CONFIG_CHANGE_BIT_ANISOTROPY; + if (old_force_filtering != g_ActiveConfig.bForceFiltering) + changed_bits |= CONFIG_CHANGE_BIT_FORCE_TEXTURE_FILTERING; + if (old_vsync != g_ActiveConfig.IsVSync()) + changed_bits |= CONFIG_CHANGE_BIT_VSYNC; + if (old_bbox != g_ActiveConfig.bBBoxEnable) + changed_bits |= CONFIG_CHANGE_BIT_BBOX; + if (CalculateTargetSize()) + changed_bits |= CONFIG_CHANGE_BIT_TARGET_SIZE; + + // No changes? + if (changed_bits == 0) + return; + + // Notify the backend of the changes, if any. + OnConfigChanged(changed_bits); + + // Reload shaders if host config has changed. + if (changed_bits & (CONFIG_CHANGE_BIT_HOST_CONFIG | CONFIG_CHANGE_BIT_MULTISAMPLES)) { - return false; + OSD::AddMessage("Video config changed, reloading shaders.", OSD::Duration::NORMAL); + SetPipeline(nullptr); + g_vertex_manager->InvalidatePipelineObject(); + g_shader_cache->SetHostConfig(new_host_config, g_ActiveConfig.iMultisamples); } - - m_last_host_config_bits = new_host_config.bits; - m_last_efb_multisamples = g_ActiveConfig.iMultisamples; - - // Reload shaders. - OSD::AddMessage("Video config changed, reloading shaders.", OSD::Duration::NORMAL); - SetPipeline(nullptr); - g_vertex_manager->InvalidatePipelineObject(); - g_shader_cache->SetHostConfig(new_host_config, g_ActiveConfig.iMultisamples); - return true; } // Create On-Screen-Messages @@ -754,6 +783,8 @@ void Renderer::ShutdownImGui() void Renderer::BeginImGuiFrame() { + std::unique_lock imgui_lock(m_imgui_mutex); + const u64 current_time_us = Common::Timer::GetTimeUs(); const u64 time_diff_us = current_time_us - m_imgui_last_frame_time; const float time_diff_secs = static_cast(time_diff_us / 1000000.0); @@ -768,12 +799,17 @@ void Renderer::BeginImGuiFrame() ImGui::NewFrame(); } -void Renderer::DrawImGui() +void Renderer::RenderImGui() { + ImGui::Render(); + ImDrawData* draw_data = ImGui::GetDrawData(); if (!draw_data) return; + SetViewport(0.0f, 0.0f, static_cast(m_backbuffer_width), + static_cast(m_backbuffer_height), 0.0f, 1.0f); + // Uniform buffer for draws. struct ImGuiUbo { @@ -783,8 +819,9 @@ void Renderer::DrawImGui() ImGuiUbo ubo = {{1.0f / m_backbuffer_width * 2.0f, 1.0f / m_backbuffer_height * 2.0f}}; // Set up common state for drawing. - g_vertex_manager->UploadUtilityUniforms(&ubo, sizeof(ubo)); + SetPipeline(m_imgui_pipeline.get()); SetSamplerState(0, RenderState::GetPointSamplerState()); + g_vertex_manager->UploadUtilityUniforms(&ubo, sizeof(ubo)); for (int i = 0; i < draw_data->CmdListsCount; i++) { @@ -805,7 +842,6 @@ void Renderer::DrawImGui() continue; } - SetPipeline(m_imgui_pipeline.get()); SetScissorRect(MathUtil::Rectangle( static_cast(cmd.ClipRect.x), static_cast(cmd.ClipRect.y), static_cast(cmd.ClipRect.z), static_cast(cmd.ClipRect.w))); @@ -821,13 +857,31 @@ std::unique_lock Renderer::GetImGuiLock() return std::unique_lock(m_imgui_mutex); } +void Renderer::BeginUIFrame() +{ + ResetAPIState(); + BindBackbuffer({0.0f, 0.0f, 0.0f, 1.0f}); +} + +void Renderer::EndUIFrame() +{ + { + auto lock = GetImGuiLock(); + RenderImGui(); + } + + { + std::lock_guard guard(m_swap_mutex); + PresentBackbuffer(); + } + + BeginImGuiFrame(); + RestoreAPIState(); +} + void Renderer::Swap(u32 xfbAddr, u32 fbWidth, u32 fbStride, u32 fbHeight, const EFBRectangle& rc, u64 ticks) { - // Hold the imgui lock while we're presenting. - // It's only to prevent races on inputs anyway, at this point. - std::unique_lock imgui_lock(m_imgui_mutex); - const AspectMode suggested = g_ActiveConfig.suggested_aspect_mode; if (suggested == AspectMode::Analog || suggested == AspectMode::AnalogWide) { @@ -892,16 +946,27 @@ void Renderer::Swap(u32 xfbAddr, u32 fbWidth, u32 fbStride, u32 fbHeight, const // with the loader, and it has not been unmapped yet. Force a pipeline flush to avoid this. g_vertex_manager->Flush(); - // Draw any imgui overlays we have. Note that "draw" here means "create commands", the actual - // draw calls don't get issued until DrawImGui is called, which happens in SwapImpl. - DrawDebugText(); - OSD::DrawMessages(); - ImGui::Render(); + // Render the XFB to the screen. + ResetAPIState(); + BindBackbuffer({0.0f, 0.0f, 0.0f, 1.0f}); + UpdateDrawRectangle(); + RenderXFBToScreen(xfb_entry->texture.get(), xfb_rect); - // TODO: merge more generic parts into VideoCommon + // Hold the imgui lock while we're presenting. + // It's only to prevent races on inputs anyway, at this point. + { + auto lock = GetImGuiLock(); + + DrawDebugText(); + OSD::DrawMessages(); + + RenderImGui(); + } + + // Present to the window system. { std::lock_guard guard(m_swap_mutex); - g_renderer->SwapImpl(xfb_entry->texture.get(), xfb_rect, ticks); + PresentBackbuffer(); } // Update the window size based on the frame that was just rendered. @@ -923,10 +988,9 @@ void Renderer::Swap(u32 xfbAddr, u32 fbWidth, u32 fbStride, u32 fbHeight, const GFX_DEBUGGER_PAUSE_AT(NEXT_FRAME, true); // Begin new frame - // Set default viewport and scissor, for the clear to work correctly - // New frame stats.ResetFrame(); g_shader_cache->RetrieveAsyncShaders(); + BeginImGuiFrame(); // We invalidate the pipeline object at the start of the frame. // This is for the rare case where only a single pipeline configuration is used, @@ -938,7 +1002,14 @@ void Renderer::Swap(u32 xfbAddr, u32 fbWidth, u32 fbStride, u32 fbHeight, const // rate and not waiting for vblank. Otherwise, we'd end up with a huge list of pending copies. g_texture_cache->FlushEFBCopies(); - BeginImGuiFrame(); + // Remove stale EFB/XFB copies. + g_texture_cache->Cleanup(frameCount); + + // Handle any config changes, this gets propogated to the backend. + CheckForConfigChanges(); + g_Config.iSaveTargetId = 0; + + RestoreAPIState(); Core::Callback_VideoCopiedToXFB(true); } diff --git a/Source/Core/VideoCommon/RenderBase.h b/Source/Core/VideoCommon/RenderBase.h index 410d998497..45a82c1968 100644 --- a/Source/Core/VideoCommon/RenderBase.h +++ b/Source/Core/VideoCommon/RenderBase.h @@ -109,6 +109,14 @@ public: virtual void Draw(u32 base_vertex, u32 num_vertices) {} virtual void DrawIndexed(u32 base_index, u32 num_indices, u32 base_vertex) {} + // Binds the backbuffer for rendering. The buffer will be cleared immediately after binding. + // This is where any window size changes are detected, therefore m_backbuffer_width and/or + // m_backbuffer_height may change after this function returns. + virtual void BindBackbuffer(const ClearColor& clear_color = {}) {} + + // Presents the backbuffer to the window system, or "swaps buffers". + virtual void PresentBackbuffer() {} + // Shader modules/objects. virtual std::unique_ptr CreateShaderFromSource(ShaderStage stage, const char* source, size_t length) = 0; @@ -173,11 +181,18 @@ public: virtual u16 BBoxRead(int index) = 0; virtual void BBoxWrite(int index, u16 value) = 0; + virtual void Flush() {} + // Finish up the current frame, print some stats void Swap(u32 xfbAddr, u32 fbWidth, u32 fbStride, u32 fbHeight, const EFBRectangle& rc, u64 ticks); - virtual void SwapImpl(AbstractTexture* texture, const EFBRectangle& rc, u64 ticks) = 0; - virtual void Flush() {} + + // Draws the specified XFB buffer to the screen, performing any post-processing. + // Assumes that the backbuffer has already been bound and cleared. + virtual void RenderXFBToScreen(const AbstractTexture* texture, const EFBRectangle& rc) {} + + // Called when the configuration changes, and backend structures need to be updated. + virtual void OnConfigChanged(u32 bits) {} PEControl::PixelFormat GetPrevPixelFormat() const { return m_prev_efb_format; } void StorePixelFormat(PEControl::PixelFormat new_format) { m_prev_efb_format = new_format; } @@ -195,23 +210,43 @@ public: // as the drawing is tied to a "frame". std::unique_lock GetImGuiLock(); + // Begins/presents a "UI frame". UI frames do not draw any of the console XFB, but this could + // change in the future. + void BeginUIFrame(); + void EndUIFrame(); + protected: + // Bitmask containing information about which configuration has changed for the backend. + enum ConfigChangeBits : u32 + { + CONFIG_CHANGE_BIT_HOST_CONFIG = (1 << 0), + CONFIG_CHANGE_BIT_MULTISAMPLES = (1 << 1), + CONFIG_CHANGE_BIT_STEREO_MODE = (1 << 2), + CONFIG_CHANGE_BIT_TARGET_SIZE = (1 << 3), + CONFIG_CHANGE_BIT_ANISOTROPY = (1 << 4), + CONFIG_CHANGE_BIT_FORCE_TEXTURE_FILTERING = (1 << 5), + CONFIG_CHANGE_BIT_VSYNC = (1 << 6), + CONFIG_CHANGE_BIT_BBOX = (1 << 7) + }; + std::tuple CalculateTargetScale(int x, int y) const; bool CalculateTargetSize(); - bool CheckForHostConfigChanges(); + void CheckForConfigChanges(); void CheckFifoRecording(); void RecordVideoMemory(); - // Renders ImGui windows to the currently-bound framebuffer. - void DrawImGui(); + // Sets up ImGui state for the next frame. + // This function itself acquires the ImGui lock, so it should not be held. + void BeginImGuiFrame(); // Destroys all ImGui GPU resources, must do before shutdown. void ShutdownImGui(); - // Sets up ImGui state for the next frame. - void BeginImGuiFrame(); + // Renders ImGui windows to the currently-bound framebuffer. + // Should be called with the ImGui lock held. + void RenderImGui(); // TODO: Remove the width/height parameters once we make the EFB an abstract framebuffer. const AbstractFramebuffer* m_current_framebuffer = nullptr; @@ -244,9 +279,6 @@ protected: Common::Flag m_surface_resized; std::mutex m_swap_mutex; - u32 m_last_host_config_bits = 0; - u32 m_last_efb_multisamples = 1; - // ImGui resources. std::unique_ptr m_imgui_vertex_format; std::vector> m_imgui_textures; From 78588ce79dceef745c6931a12ad1e59677346227 Mon Sep 17 00:00:00 2001 From: Stenzek Date: Wed, 28 Nov 2018 23:36:39 +1000 Subject: [PATCH 10/15] ShaderCache: Use imgui for shader compilation dialog --- .../Core/VideoCommon/AsyncShaderCompiler.cpp | 2 +- Source/Core/VideoCommon/ShaderCache.cpp | 26 ++++++++++++++++--- 2 files changed, 23 insertions(+), 5 deletions(-) diff --git a/Source/Core/VideoCommon/AsyncShaderCompiler.cpp b/Source/Core/VideoCommon/AsyncShaderCompiler.cpp index 755f105942..942f293f1b 100644 --- a/Source/Core/VideoCommon/AsyncShaderCompiler.cpp +++ b/Source/Core/VideoCommon/AsyncShaderCompiler.cpp @@ -77,7 +77,7 @@ void AsyncShaderCompiler::WaitUntilCompletion( // Wait a second before opening a progress dialog. // This way, if the operation completes quickly, we don't annoy the user. - constexpr u32 CHECK_INTERVAL_MS = 50; + constexpr u32 CHECK_INTERVAL_MS = 1000 / 30; constexpr auto CHECK_INTERVAL = std::chrono::milliseconds(CHECK_INTERVAL_MS); for (u32 i = 0; i < (1000 / CHECK_INTERVAL_MS); i++) { diff --git a/Source/Core/VideoCommon/ShaderCache.cpp b/Source/Core/VideoCommon/ShaderCache.cpp index 299b0d1bca..3b0c110f96 100644 --- a/Source/Core/VideoCommon/ShaderCache.cpp +++ b/Source/Core/VideoCommon/ShaderCache.cpp @@ -8,7 +8,6 @@ #include "Common/FileUtil.h" #include "Common/MsgHandler.h" #include "Core/ConfigManager.h" -#include "Core/Host.h" #include "VideoCommon/FramebufferManagerBase.h" #include "VideoCommon/RenderBase.h" @@ -16,6 +15,8 @@ #include "VideoCommon/VertexLoaderManager.h" #include "VideoCommon/VertexManagerBase.h" +#include "imgui.h" + std::unique_ptr g_shader_cache; namespace VideoCommon @@ -153,12 +154,29 @@ void ShaderCache::WaitForAsyncCompiler() while (m_async_shader_compiler->HasPendingWork() || m_async_shader_compiler->HasCompletedWork()) { m_async_shader_compiler->WaitUntilCompletion([](size_t completed, size_t total) { - Host_UpdateProgressDialog(GetStringT("Compiling shaders...").c_str(), - static_cast(completed), static_cast(total)); + g_renderer->BeginUIFrame(); + + const float scale = ImGui::GetIO().DisplayFramebufferScale.x; + + ImGui::SetNextWindowSize(ImVec2(400.0f * scale, 50.0f * scale), ImGuiCond_Always); + ImGui::SetNextWindowPosCenter(ImGuiCond_Always); + if (ImGui::Begin(GetStringT("Compiling Shaders").c_str(), nullptr, + ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoInputs | + ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoSavedSettings | + ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoNav | + ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoFocusOnAppearing)) + { + ImGui::Text("Compiling shaders: %zu/%zu", completed, total); + ImGui::ProgressBar(static_cast(completed) / + static_cast(std::max(total, static_cast(1))), + ImVec2(-1.0f, 0.0f), ""); + } + ImGui::End(); + + g_renderer->EndUIFrame(); }); m_async_shader_compiler->RetrieveWorkItems(); } - Host_UpdateProgressDialog("", -1, -1); } template From e9b02e7dd0f0e9a509e4444e335edec621562c50 Mon Sep 17 00:00:00 2001 From: Stenzek Date: Sun, 20 Jan 2019 11:41:37 +1000 Subject: [PATCH 11/15] Vulkan: Remove unused UpdateUtilityUniformBuffer function --- Source/Core/VideoBackends/Vulkan/Renderer.cpp | 22 ------------------- Source/Core/VideoBackends/Vulkan/Renderer.h | 3 --- 2 files changed, 25 deletions(-) diff --git a/Source/Core/VideoBackends/Vulkan/Renderer.cpp b/Source/Core/VideoBackends/Vulkan/Renderer.cpp index dbb0c6e582..dffe3fdd3c 100644 --- a/Source/Core/VideoBackends/Vulkan/Renderer.cpp +++ b/Source/Core/VideoBackends/Vulkan/Renderer.cpp @@ -223,28 +223,6 @@ Renderer::CreateFramebuffer(const AbstractTexture* color_attachment, static_cast(depth_attachment)); } -std::tuple Renderer::UpdateUtilityUniformBuffer(const void* uniforms, - u32 uniforms_size) -{ - StreamBuffer* ubo_buf = g_object_cache->GetUtilityShaderUniformBuffer(); - if (!ubo_buf->ReserveMemory(uniforms_size, g_vulkan_context->GetUniformBufferAlignment())) - { - Util::ExecuteCurrentCommandsAndRestoreState(false, true); - if (!ubo_buf->ReserveMemory(uniforms_size, g_vulkan_context->GetUniformBufferAlignment())) - { - PanicAlert("Failed to reserve uniform buffer space for utility draw."); - return {}; - } - } - - VkBuffer ubo = ubo_buf->GetBuffer(); - u32 ubo_offset = static_cast(ubo_buf->GetCurrentOffset()); - std::memcpy(ubo_buf->GetCurrentHostPointer(), uniforms, uniforms_size); - ubo_buf->CommitMemory(uniforms_size); - - return std::tie(ubo, ubo_offset); -} - void Renderer::SetPipeline(const AbstractPipeline* pipeline) { StateTracker::GetInstance()->SetPipeline(static_cast(pipeline)); diff --git a/Source/Core/VideoBackends/Vulkan/Renderer.h b/Source/Core/VideoBackends/Vulkan/Renderer.h index 46a57a036e..e6b1c910b5 100644 --- a/Source/Core/VideoBackends/Vulkan/Renderer.h +++ b/Source/Core/VideoBackends/Vulkan/Renderer.h @@ -7,7 +7,6 @@ #include #include #include -#include #include "Common/CommonTypes.h" #include "VideoBackends/Vulkan/Constants.h" @@ -112,8 +111,6 @@ private: bool CompileShaders(); void DestroyShaders(); - std::tuple UpdateUtilityUniformBuffer(const void* uniforms, u32 uniforms_size); - VkSemaphore m_image_available_semaphore = VK_NULL_HANDLE; VkSemaphore m_rendering_finished_semaphore = VK_NULL_HANDLE; VkRenderPass m_swap_chain_render_pass = VK_NULL_HANDLE; From 82fd923a4e33451dd30fcb6a612c8b5db0034f75 Mon Sep 17 00:00:00 2001 From: Stenzek Date: Tue, 22 Jan 2019 22:44:30 +1000 Subject: [PATCH 12/15] Android: Add getter method for NativeLibrary.sEmulationActivity Also makes sEmulationActivity private. --- .../java/org/dolphinemu/dolphinemu/NativeLibrary.java | 11 ++++++++++- .../dolphinemu/dolphinemu/utils/Java_GCAdapter.java | 4 ++-- .../dolphinemu/utils/Java_WiimoteAdapter.java | 2 +- 3 files changed, 13 insertions(+), 4 deletions(-) diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/NativeLibrary.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/NativeLibrary.java index 442a4e8644..b901f2f691 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/NativeLibrary.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/NativeLibrary.java @@ -21,7 +21,16 @@ import java.lang.ref.WeakReference; */ public final class NativeLibrary { - public static WeakReference sEmulationActivity = new WeakReference<>(null); + private static WeakReference sEmulationActivity = new WeakReference<>(null); + + /** + * Returns the current instance of EmulationActivity. + * There should only ever be one EmulationActivity instantiated. + */ + public static EmulationActivity getEmulationActivity() + { + return sEmulationActivity.get(); + } /** * Button type for use in onTouchEvent diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/Java_GCAdapter.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/Java_GCAdapter.java index d83c348ea2..babf5069e5 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/Java_GCAdapter.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/Java_GCAdapter.java @@ -31,7 +31,7 @@ public class Java_GCAdapter private static void RequestPermission() { - Context context = NativeLibrary.sEmulationActivity.get(); + Context context = NativeLibrary.getEmulationActivity(); if (context != null) { HashMap devices = manager.getDeviceList(); @@ -141,7 +141,7 @@ public class Java_GCAdapter } } - final Activity emulationActivity = NativeLibrary.sEmulationActivity.get(); + final Activity emulationActivity = NativeLibrary.getEmulationActivity(); if (emulationActivity != null) { emulationActivity.runOnUiThread(() -> Toast.makeText(emulationActivity, diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/Java_WiimoteAdapter.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/Java_WiimoteAdapter.java index de11e4fd62..4ecc1a64ca 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/Java_WiimoteAdapter.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/Java_WiimoteAdapter.java @@ -34,7 +34,7 @@ public class Java_WiimoteAdapter private static void RequestPermission() { - Context context = NativeLibrary.sEmulationActivity.get(); + Context context = NativeLibrary.getEmulationActivity(); if (context != null) { HashMap devices = manager.getDeviceList(); From c6f151c4e10d08108316ae235f8463e88364d2e1 Mon Sep 17 00:00:00 2001 From: Stenzek Date: Tue, 22 Jan 2019 22:45:02 +1000 Subject: [PATCH 13/15] Android: Use scaledDensity as backbuffer scale (for imgui) --- Source/Android/jni/MainAndroid.cpp | 53 ++++++++++++++++++++++++++++-- 1 file changed, 50 insertions(+), 3 deletions(-) diff --git a/Source/Android/jni/MainAndroid.cpp b/Source/Android/jni/MainAndroid.cpp index 441080e57a..9ffa7d2b0d 100644 --- a/Source/Android/jni/MainAndroid.cpp +++ b/Source/Android/jni/MainAndroid.cpp @@ -52,6 +52,7 @@ #include "VideoCommon/RenderBase.h" #include "VideoCommon/VideoBackendBase.h" +#include "../../Core/Common/WindowSystemInfo.h" #include "jni/AndroidCommon/AndroidCommon.h" #include "jni/AndroidCommon/IDCache.h" #include "jni/ButtonManager.h" @@ -589,7 +590,52 @@ JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_ReloadWiimot Wiimote::LoadConfig(); } -static void Run(const std::vector& paths, bool first_open, +// Returns the scale factor for imgui rendering. +// Based on the scaledDensity of the device's display metrics. +static float GetRenderSurfaceScale(JNIEnv* env) +{ + // NativeLibrary emulation_activity = NativeLibrary.getEmulationActivity(); + jclass native_library_class = env->FindClass("org/dolphinemu/dolphinemu/NativeLibrary"); + jmethodID get_emulation_activity_method = + env->GetStaticMethodID(native_library_class, "getEmulationActivity", + "()Lorg/dolphinemu/dolphinemu/activities/EmulationActivity;"); + jobject emulation_activity = + env->CallStaticObjectMethod(native_library_class, get_emulation_activity_method); + + // WindowManager window_manager = emulation_activity.getWindowManager(); + jmethodID get_window_manager_method = + env->GetMethodID(env->GetObjectClass(emulation_activity), "getWindowManager", + "()Landroid/view/WindowManager;"); + jobject window_manager = env->CallObjectMethod(emulation_activity, get_window_manager_method); + + // Display display = window_manager.getDisplay(); + jmethodID get_display_method = env->GetMethodID(env->GetObjectClass(window_manager), + "getDefaultDisplay", "()Landroid/view/Display;"); + jobject display = env->CallObjectMethod(window_manager, get_display_method); + + // DisplayMetrics metrics = new DisplayMetrics(); + jclass display_metrics_class = env->FindClass("android/util/DisplayMetrics"); + jmethodID display_metrics_constructor = env->GetMethodID(display_metrics_class, "", "()V"); + jobject metrics = env->NewObject(display_metrics_class, display_metrics_constructor); + + // display.getMetrics(metrics); + jmethodID get_metrics_method = env->GetMethodID(env->GetObjectClass(display), "getMetrics", + "(Landroid/util/DisplayMetrics;)V"); + env->CallVoidMethod(display, get_metrics_method, metrics); + + // float scaled_density = metrics.scaledDensity; + jfieldID scaled_density_field = + env->GetFieldID(env->GetObjectClass(metrics), "scaledDensity", "F"); + float scaled_density = env->GetFloatField(metrics, scaled_density_field); + __android_log_print(ANDROID_LOG_INFO, DOLPHIN_TAG, "Using %f for render surface scale.", + scaled_density); + + // cleanup + env->DeleteLocalRef(metrics); + return scaled_density; +} + +static void Run(JNIEnv* env, const std::vector& paths, bool first_open, std::optional savestate_path = {}, bool delete_savestate = false) { ASSERT(!paths.empty()); @@ -614,6 +660,7 @@ static void Run(const std::vector& paths, bool first_open, std::unique_ptr boot = BootParameters::GenerateFromFile(paths, savestate_path); boot->delete_savestate = delete_savestate; WindowSystemInfo wsi(WindowSystemType::Android, nullptr, s_surf); + wsi.render_surface_scale = GetRenderSurfaceScale(env); if (BootManager::BootCore(std::move(boot), wsi)) { ButtonManager::Init(SConfig::GetInstance().GetGameID()); @@ -650,14 +697,14 @@ static void Run(const std::vector& paths, bool first_open, JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_Run___3Ljava_lang_String_2Z( JNIEnv* env, jobject obj, jobjectArray jPaths, jboolean jfirstOpen) { - Run(JStringArrayToVector(env, jPaths), jfirstOpen); + Run(env, JStringArrayToVector(env, jPaths), jfirstOpen); } JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_Run___3Ljava_lang_String_2Ljava_lang_String_2Z( JNIEnv* env, jobject obj, jobjectArray jPaths, jstring jSavestate, jboolean jDeleteSavestate) { - Run(JStringArrayToVector(env, jPaths), false, GetJString(env, jSavestate), jDeleteSavestate); + Run(env, JStringArrayToVector(env, jPaths), false, GetJString(env, jSavestate), jDeleteSavestate); } JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_ChangeDisc(JNIEnv* env, From ee0fa548bc60b6f2abc9a2122c6d7debc1e9b576 Mon Sep 17 00:00:00 2001 From: Stenzek Date: Wed, 23 Jan 2019 00:36:46 +1000 Subject: [PATCH 14/15] Vulkan: Don't bind last descriptor set if bounding box is unsupported Fixes crash on a4xx/Vulkan. --- Source/Core/VideoBackends/Vulkan/StateTracker.cpp | 4 +++- Source/Core/VideoBackends/Vulkan/StateTracker.h | 5 +++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/Source/Core/VideoBackends/Vulkan/StateTracker.cpp b/Source/Core/VideoBackends/Vulkan/StateTracker.cpp index 471a8b12f5..089b385ffe 100644 --- a/Source/Core/VideoBackends/Vulkan/StateTracker.cpp +++ b/Source/Core/VideoBackends/Vulkan/StateTracker.cpp @@ -767,7 +767,9 @@ bool StateTracker::UpdateGXDescriptorSet() if (num_writes > 0) vkUpdateDescriptorSets(g_vulkan_context->GetDevice(), num_writes, writes.data(), 0, nullptr); - m_num_active_descriptor_sets = NUM_GX_DRAW_DESCRIPTOR_SETS; + m_num_active_descriptor_sets = g_vulkan_context->SupportsBoundingBox() ? + NUM_GX_DRAW_DESCRIPTOR_SETS_SSBO : + NUM_GX_DRAW_DESCRIPTOR_SETS; m_num_dynamic_offsets = NUM_UBO_DESCRIPTOR_SET_BINDINGS; return true; } diff --git a/Source/Core/VideoBackends/Vulkan/StateTracker.h b/Source/Core/VideoBackends/Vulkan/StateTracker.h index a3d7a365ae..f4cbc8e180 100644 --- a/Source/Core/VideoBackends/Vulkan/StateTracker.h +++ b/Source/Core/VideoBackends/Vulkan/StateTracker.h @@ -103,7 +103,8 @@ private: // Number of descriptor sets for game draws. enum { - NUM_GX_DRAW_DESCRIPTOR_SETS = DESCRIPTOR_SET_BIND_POINT_STORAGE_OR_TEXEL_BUFFER + 1, + NUM_GX_DRAW_DESCRIPTOR_SETS = DESCRIPTOR_SET_BIND_POINT_PIXEL_SHADER_SAMPLERS + 1, + NUM_GX_DRAW_DESCRIPTOR_SETS_SSBO = DESCRIPTOR_SET_BIND_POINT_STORAGE_OR_TEXEL_BUFFER + 1, NUM_UTILITY_DRAW_DESCRIPTOR_SETS = 2 }; @@ -192,4 +193,4 @@ private: std::vector m_scheduled_command_buffer_kicks; bool m_allow_background_execution = true; }; -} +} // namespace Vulkan From 774480ba234c788d2973cf6a3ccd1cd4c3fcc673 Mon Sep 17 00:00:00 2001 From: Stenzek Date: Sat, 26 Jan 2019 00:02:02 +1000 Subject: [PATCH 15/15] Vulkan: Set contents scale of Metal layer to screen factor This gives us a native resolution framebuffer. --- Source/Core/VideoBackends/Vulkan/main.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/Source/Core/VideoBackends/Vulkan/main.cpp b/Source/Core/VideoBackends/Vulkan/main.cpp index af3a7b56d8..53c04c4e37 100644 --- a/Source/Core/VideoBackends/Vulkan/main.cpp +++ b/Source/Core/VideoBackends/Vulkan/main.cpp @@ -303,6 +303,18 @@ void VideoBackend::PrepareWindow(const WindowSystemInfo& wsi) // [view setLayer:layer] reinterpret_cast(objc_msgSend)(view, sel_getUid("setLayer:"), layer); + + // NSScreen* screen = [NSScreen mainScreen] + id screen = reinterpret_cast(objc_msgSend)(objc_getClass("NSScreen"), + sel_getUid("mainScreen")); + + // CGFloat factor = [screen backingScaleFactor] + double factor = + reinterpret_cast(objc_msgSend)(screen, sel_getUid("backingScaleFactor")); + + // layer.contentsScale = factor + reinterpret_cast(objc_msgSend)(layer, sel_getUid("setContentsScale:"), + factor); #endif } } // namespace Vulkan