mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-04-20 11:35:54 +00:00
VideoCommon: add editor backend
This commit is contained in:
parent
8bdaeb5665
commit
0c8626d7cc
2 changed files with 397 additions and 0 deletions
354
Source/Core/VideoCommon/GraphicsModEditor/EditorBackend.cpp
Normal file
354
Source/Core/VideoCommon/GraphicsModEditor/EditorBackend.cpp
Normal file
|
@ -0,0 +1,354 @@
|
|||
// Copyright 2024 Dolphin Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "VideoCommon/GraphicsModEditor/EditorBackend.h"
|
||||
|
||||
#include <chrono>
|
||||
#include <memory>
|
||||
|
||||
#include "Common/EnumUtils.h"
|
||||
#include "Common/FileUtil.h"
|
||||
#include "Core/ConfigManager.h"
|
||||
#include "Core/System.h"
|
||||
|
||||
#include "VideoCommon/BPMemory.h"
|
||||
#include "VideoCommon/CPMemory.h"
|
||||
#include "VideoCommon/GraphicsModEditor/EditorEvents.h"
|
||||
#include "VideoCommon/GraphicsModEditor/MaterialGeneration.h"
|
||||
#include "VideoCommon/GraphicsModEditor/ShaderGeneration.h"
|
||||
#include "VideoCommon/GraphicsModSystem/Runtime/CustomResourceManager.h"
|
||||
#include "VideoCommon/GraphicsModSystem/Runtime/GraphicsModHash.h"
|
||||
#include "VideoCommon/GraphicsModSystem/Types.h"
|
||||
#include "VideoCommon/PixelShaderGen.h"
|
||||
#include "VideoCommon/ShaderGenCommon.h"
|
||||
#include "VideoCommon/VertexLoaderManager.h"
|
||||
#include "VideoCommon/VertexShaderGen.h"
|
||||
#include "VideoCommon/VideoConfig.h"
|
||||
#include "VideoCommon/XFMemory.h"
|
||||
|
||||
namespace GraphicsModEditor
|
||||
{
|
||||
EditorBackend::EditorBackend(EditorState& state) : m_state(state)
|
||||
{
|
||||
m_selection_event = EditorEvents::ItemsSelectedEvent::Register(
|
||||
[this](const auto& selected_targets) { SelectionOccurred(selected_targets); },
|
||||
"EditorBackendSelect");
|
||||
}
|
||||
|
||||
void EditorBackend::OnDraw(const GraphicsModSystem::DrawDataView& draw_data,
|
||||
VertexManagerBase* vertex_manager)
|
||||
{
|
||||
const auto hash_output =
|
||||
GraphicsModSystem::Runtime::GetDrawDataHash(m_state.m_user_data.m_hash_policy, draw_data);
|
||||
|
||||
const GraphicsModSystem::DrawCallID draw_call_id =
|
||||
GetSkinnedDrawCallID(hash_output.draw_call_id, hash_output.material_id, draw_data);
|
||||
|
||||
if (m_state.m_scene_dumper.IsRecording())
|
||||
{
|
||||
if (m_state.m_scene_dumper.IsDrawCallInRecording(draw_call_id))
|
||||
{
|
||||
GraphicsModEditor::SceneDumper::AdditionalDrawData additional_draw_data;
|
||||
if (!draw_data.vertex_format->GetVertexDeclaration().posmtx.enable)
|
||||
{
|
||||
float* pos = &xfmem.posMatrices[g_main_cp_state.matrix_index_a.PosNormalMtxIdx * 4];
|
||||
additional_draw_data.transform = {pos, 12};
|
||||
}
|
||||
m_state.m_scene_dumper.AddDataToRecording(hash_output.draw_call_id, draw_data,
|
||||
std::move(additional_draw_data));
|
||||
}
|
||||
}
|
||||
|
||||
if (draw_call_id == hash_output.draw_call_id)
|
||||
{
|
||||
const auto now = std::chrono::steady_clock::now();
|
||||
if (auto iter = m_state.m_runtime_data.m_draw_call_id_to_data.find(hash_output.draw_call_id);
|
||||
iter != m_state.m_runtime_data.m_draw_call_id_to_data.end())
|
||||
{
|
||||
if (m_xfb_counter > (iter->second.draw_data.xfb_counter + 1))
|
||||
{
|
||||
iter->second.m_create_time = now;
|
||||
}
|
||||
iter->second.draw_data.blending_state = draw_data.uid->blending_state;
|
||||
iter->second.draw_data.depth_state = draw_data.uid->depth_state;
|
||||
iter->second.draw_data.projection_type = draw_data.projection_type;
|
||||
iter->second.draw_data.projection_mat = xfmem.projection.rawProjection;
|
||||
iter->second.draw_data.rasterization_state = draw_data.uid->rasterization_state;
|
||||
iter->second.draw_data.xfb_counter = m_xfb_counter;
|
||||
iter->second.draw_data.vertex_count = draw_data.vertex_data.size();
|
||||
iter->second.draw_data.index_count = draw_data.index_data.size();
|
||||
|
||||
Common::SmallVector<GraphicsModSystem::Texture, 8> textures;
|
||||
for (const auto& texture_view : draw_data.textures)
|
||||
{
|
||||
GraphicsModSystem::Texture texture;
|
||||
texture.hash_name = std::string{texture_view.hash_name};
|
||||
texture.texture_type = texture_view.texture_type;
|
||||
texture.unit = texture_view.unit;
|
||||
textures.push_back(std::move(texture));
|
||||
}
|
||||
iter->second.draw_data.textures = textures;
|
||||
iter->second.draw_data.samplers = draw_data.samplers;
|
||||
RuntimeState::XFBData::DrawCallWithTime draw_call_with_time{hash_output.draw_call_id,
|
||||
iter->second.m_create_time};
|
||||
m_state.m_runtime_data.m_current_xfb.m_draw_call_ids.insert(draw_call_with_time);
|
||||
iter->second.m_last_update_time = now;
|
||||
}
|
||||
else
|
||||
{
|
||||
GraphicsModEditor::DrawCallData data;
|
||||
data.m_id = hash_output.draw_call_id;
|
||||
data.draw_data.blending_state = draw_data.uid->blending_state;
|
||||
data.draw_data.depth_state = draw_data.uid->depth_state;
|
||||
data.draw_data.projection_type = draw_data.projection_type;
|
||||
data.draw_data.projection_mat = xfmem.projection.rawProjection;
|
||||
data.draw_data.rasterization_state = draw_data.uid->rasterization_state;
|
||||
data.draw_data.xfb_counter = m_xfb_counter;
|
||||
|
||||
Common::SmallVector<GraphicsModSystem::Texture, 8> textures;
|
||||
for (const auto& texture_view : draw_data.textures)
|
||||
{
|
||||
GraphicsModSystem::Texture texture;
|
||||
texture.hash_name = std::string{texture_view.hash_name};
|
||||
texture.texture_type = texture_view.texture_type;
|
||||
texture.unit = texture_view.unit;
|
||||
textures.push_back(std::move(texture));
|
||||
}
|
||||
data.draw_data.textures = textures;
|
||||
data.draw_data.samplers = draw_data.samplers;
|
||||
|
||||
data.m_create_time = now;
|
||||
data.m_last_update_time = now;
|
||||
m_state.m_runtime_data.m_draw_call_id_to_data.try_emplace(hash_output.draw_call_id,
|
||||
std::move(data));
|
||||
RuntimeState::XFBData::DrawCallWithTime draw_call_with_time{hash_output.draw_call_id, now};
|
||||
m_state.m_runtime_data.m_current_xfb.m_draw_call_ids.insert(draw_call_with_time);
|
||||
}
|
||||
}
|
||||
|
||||
if (m_state.m_editor_data.m_export_dolphin_material_draw_call == draw_call_id)
|
||||
{
|
||||
const std::string path = File::GetUserPath(D_DUMP_IDX) + SConfig::GetInstance().GetGameID();
|
||||
const auto path_drawcall = fmt::format("{}-{}", path, Common::ToUnderlying(draw_call_id));
|
||||
const auto vertex_shader_code = GenerateVertexShaderCode(
|
||||
g_backend_info.api_type, m_shader_host_config, draw_data.uid->vs_uid.GetUidData());
|
||||
File::WriteStringToFile(path_drawcall + ".vs.glsl", vertex_shader_code.GetBuffer());
|
||||
const auto pixel_shader_code = GeneratePixelShaderCode(
|
||||
g_backend_info.api_type, m_shader_host_config, draw_data.uid->ps_uid.GetUidData(), {});
|
||||
File::WriteStringToFile(path_drawcall + ".ps.glsl", pixel_shader_code.GetBuffer());
|
||||
const auto geometry_shader_code = GenerateGeometryShaderCode(
|
||||
g_backend_info.api_type, m_shader_host_config, draw_data.uid->gs_uid.GetUidData());
|
||||
File::WriteStringToFile(path_drawcall + ".gs.glsl", geometry_shader_code.GetBuffer());
|
||||
|
||||
const auto updated_vertex_shader_code = VertexShader::WriteFullShader(
|
||||
g_backend_info.api_type, m_shader_host_config, draw_data.uid->vs_uid.GetUidData(), "", "");
|
||||
File::WriteStringToFile(path_drawcall + "-updated.vs.glsl",
|
||||
updated_vertex_shader_code.GetBuffer());
|
||||
const auto updated_pixel_shader_code = PixelShader::WriteFullShader(
|
||||
g_backend_info.api_type, m_shader_host_config, draw_data.uid->ps_uid.GetUidData(), "", "");
|
||||
File::WriteStringToFile(path_drawcall + "-updated.ps.glsl",
|
||||
updated_pixel_shader_code.GetBuffer());
|
||||
|
||||
m_state.m_editor_data.m_export_dolphin_material_draw_call = {};
|
||||
}
|
||||
|
||||
if (m_state.m_editor_data.m_create_material_draw_call == draw_call_id)
|
||||
{
|
||||
ShaderCode ps_out;
|
||||
ps_out.Write("{}\n", PixelShader::fragment_definition);
|
||||
ps_out.Write("{{\n");
|
||||
|
||||
PixelShader::WriteFragmentBody(g_backend_info.api_type, m_shader_host_config,
|
||||
draw_data.uid->ps_uid.GetUidData(), ps_out);
|
||||
|
||||
ps_out.Write("}}\n");
|
||||
|
||||
ShaderCode vs_out;
|
||||
vs_out.Write("{}\n", VertexShader::vertex_definition);
|
||||
vs_out.Write("{{\n");
|
||||
|
||||
VertexShader::WriteVertexBody(g_backend_info.api_type, m_shader_host_config,
|
||||
draw_data.uid->vs_uid.GetUidData(), vs_out);
|
||||
|
||||
vs_out.Write("}}\n");
|
||||
|
||||
const auto material_metadata_name =
|
||||
fmt::format("{}.rastermaterial", Common::ToUnderlying(draw_call_id));
|
||||
const auto shader_metadata_name =
|
||||
fmt::format("{}.rastershader", Common::ToUnderlying(draw_call_id));
|
||||
const auto pixel_name = fmt::format("{}.ps.glsl", Common::ToUnderlying(draw_call_id));
|
||||
const auto vertex_name = fmt::format("{}.vs.glsl", Common::ToUnderlying(draw_call_id));
|
||||
|
||||
GraphicsModEditor::ShaderGenerationContext shader_gen_context;
|
||||
shader_gen_context.metadata_name = shader_metadata_name;
|
||||
|
||||
VideoCommon::RasterShaderData shader_template;
|
||||
shader_template.m_pixel_source = ps_out.GetBuffer();
|
||||
shader_template.m_vertex_source = vs_out.GetBuffer();
|
||||
|
||||
shader_gen_context.shader_template = std::move(shader_template);
|
||||
shader_gen_context.pixel_name = pixel_name;
|
||||
shader_gen_context.vertex_name = vertex_name;
|
||||
|
||||
VideoCommon::RasterMaterialData material_template;
|
||||
|
||||
GraphicsModEditor::GenerateMaterial(
|
||||
material_metadata_name, m_state.m_user_data.m_current_mod_path, material_template,
|
||||
shader_gen_context, m_state.m_user_data.m_asset_library.get());
|
||||
|
||||
m_state.m_editor_data.m_create_material_draw_call = {};
|
||||
}
|
||||
|
||||
static Common::Matrix44 identity = Common::Matrix44::Identity();
|
||||
|
||||
if (m_selected_objects.contains(draw_call_id))
|
||||
{
|
||||
auto& resource_manager = Core::System::GetInstance().GetCustomResourceManager();
|
||||
auto* material_resource = resource_manager.GetMaterialFromAsset(
|
||||
"editor-highlight-material", m_state.m_editor_data.m_asset_library, draw_data);
|
||||
vertex_manager->DrawEmulatedMesh(material_resource, draw_data, identity, m_camera_manager);
|
||||
}
|
||||
else if (m_state.m_editor_data.m_view_lighting &&
|
||||
draw_data.projection_type != ProjectionType::Orthographic)
|
||||
{
|
||||
auto& resource_manager = Core::System::GetInstance().GetCustomResourceManager();
|
||||
auto* material_resource = resource_manager.GetMaterialFromAsset(
|
||||
"editor-lighting-vis-material", m_state.m_editor_data.m_asset_library, draw_data);
|
||||
vertex_manager->DrawEmulatedMesh(material_resource, draw_data, identity, m_camera_manager);
|
||||
}
|
||||
else if (m_state.m_editor_data.m_view_normals &&
|
||||
draw_data.projection_type != ProjectionType::Orthographic)
|
||||
{
|
||||
auto& resource_manager = Core::System::GetInstance().GetCustomResourceManager();
|
||||
auto* material_resource = resource_manager.GetMaterialFromAsset(
|
||||
"editor-normal-vis-material", m_state.m_editor_data.m_asset_library, draw_data);
|
||||
vertex_manager->DrawEmulatedMesh(material_resource, draw_data, identity, m_camera_manager);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_state.m_editor_data.m_disable_all_actions)
|
||||
{
|
||||
vertex_manager->DrawEmulatedMesh(m_camera_manager);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (const auto iter = m_state.m_user_data.m_draw_call_id_to_actions.find(draw_call_id);
|
||||
iter != m_state.m_user_data.m_draw_call_id_to_actions.end())
|
||||
{
|
||||
CustomDraw(draw_data, vertex_manager, iter->second, draw_call_id);
|
||||
}
|
||||
else
|
||||
{
|
||||
vertex_manager->DrawEmulatedMesh(m_camera_manager);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void EditorBackend::OnTextureLoad(const GraphicsModSystem::TextureView& texture)
|
||||
{
|
||||
std::string texture_cache_id{texture.hash_name};
|
||||
auto iter = m_state.m_runtime_data.m_texture_cache_id_to_data.lower_bound(texture.hash_name);
|
||||
if (iter == m_state.m_runtime_data.m_texture_cache_id_to_data.end() ||
|
||||
iter->first != texture.hash_name)
|
||||
{
|
||||
m_state.m_runtime_data.m_current_xfb.m_texture_cache_ids.insert(texture_cache_id);
|
||||
|
||||
GraphicsModEditor::TextureCacheData data;
|
||||
data.m_id = std::move(texture_cache_id);
|
||||
data.m_create_time = std::chrono::steady_clock::now();
|
||||
iter = m_state.m_runtime_data.m_texture_cache_id_to_data.emplace_hint(iter, texture.hash_name,
|
||||
std::move(data));
|
||||
}
|
||||
else
|
||||
{
|
||||
m_state.m_runtime_data.m_current_xfb.m_texture_cache_ids.insert(std::move(texture_cache_id));
|
||||
}
|
||||
iter->second.texture = texture;
|
||||
iter->second.m_active = true;
|
||||
iter->second.m_last_load_time = std::chrono::steady_clock::now();
|
||||
}
|
||||
|
||||
void EditorBackend::OnTextureUnload(GraphicsModSystem::TextureType, std::string_view texture_hash)
|
||||
{
|
||||
if (auto iter = m_state.m_runtime_data.m_texture_cache_id_to_data.find(texture_hash);
|
||||
iter != m_state.m_runtime_data.m_texture_cache_id_to_data.end())
|
||||
{
|
||||
iter->second.m_active = false;
|
||||
}
|
||||
}
|
||||
|
||||
void EditorBackend::OnTextureCreate(const GraphicsModSystem::TextureView& texture)
|
||||
{
|
||||
GraphicsModSystem::Runtime::GraphicsModBackend::OnTextureCreate(texture);
|
||||
|
||||
if (texture.texture_type == GraphicsModSystem::TextureType::XFB)
|
||||
{
|
||||
// Skip XFBs that have no draw calls
|
||||
if (m_state.m_runtime_data.m_current_xfb.m_draw_call_ids.empty())
|
||||
return;
|
||||
|
||||
// TODO: use string_view directly in C++26 (or use a different container)
|
||||
const std::string xfb_hash_name{texture.hash_name};
|
||||
m_state.m_runtime_data.m_xfb_to_data[xfb_hash_name] =
|
||||
std::move(m_state.m_runtime_data.m_current_xfb);
|
||||
m_state.m_runtime_data.m_current_xfb = {};
|
||||
|
||||
m_state.m_scene_dumper.OnXFBCreated(xfb_hash_name);
|
||||
m_xfb_counter++;
|
||||
return;
|
||||
}
|
||||
|
||||
std::string texture_cache_id{texture.hash_name};
|
||||
GraphicsModEditor::TextureCacheData data;
|
||||
data.m_id = texture_cache_id;
|
||||
data.texture = texture;
|
||||
data.m_create_time = std::chrono::steady_clock::now();
|
||||
m_state.m_runtime_data.m_texture_cache_id_to_data.insert_or_assign(std::move(texture_cache_id),
|
||||
std::move(data));
|
||||
}
|
||||
|
||||
void EditorBackend::OnLight()
|
||||
{
|
||||
}
|
||||
|
||||
void EditorBackend::OnFramePresented(const PresentInfo& present_info)
|
||||
{
|
||||
GraphicsModSystem::Runtime::GraphicsModBackend::OnFramePresented(present_info);
|
||||
|
||||
for (const auto& action : m_state.m_user_data.m_actions)
|
||||
{
|
||||
action->OnFrameEnd();
|
||||
}
|
||||
|
||||
// Clear out the old xfbs presented
|
||||
for (const auto& xfb_presented : m_state.m_runtime_data.m_xfbs_presented)
|
||||
{
|
||||
m_state.m_runtime_data.m_xfb_to_data.erase(xfb_presented);
|
||||
}
|
||||
|
||||
// Set the new ones
|
||||
m_state.m_runtime_data.m_xfbs_presented.clear();
|
||||
for (const auto& xfb_presented : present_info.xfb_copy_hashes)
|
||||
{
|
||||
m_state.m_runtime_data.m_xfbs_presented.push_back(std::string{xfb_presented});
|
||||
}
|
||||
|
||||
m_state.m_scene_dumper.OnFramePresented(m_state.m_runtime_data.m_xfbs_presented);
|
||||
}
|
||||
|
||||
void EditorBackend::SelectionOccurred(const std::set<SelectableType>& selection)
|
||||
{
|
||||
m_selected_objects = selection;
|
||||
}
|
||||
|
||||
void EditorBackend::AddIndices(OpcodeDecoder::Primitive primitive, u32 num_vertices)
|
||||
{
|
||||
m_state.m_scene_dumper.AddIndices(primitive, num_vertices);
|
||||
}
|
||||
|
||||
void EditorBackend::ResetIndices()
|
||||
{
|
||||
m_state.m_scene_dumper.ResetIndices();
|
||||
}
|
||||
} // namespace GraphicsModEditor
|
43
Source/Core/VideoCommon/GraphicsModEditor/EditorBackend.h
Normal file
43
Source/Core/VideoCommon/GraphicsModEditor/EditorBackend.h
Normal file
|
@ -0,0 +1,43 @@
|
|||
// Copyright 2024 Dolphin Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <set>
|
||||
|
||||
#include "Common/HookableEvent.h"
|
||||
#include "VideoCommon/GraphicsModEditor/EditorState.h"
|
||||
#include "VideoCommon/GraphicsModEditor/EditorTypes.h"
|
||||
#include "VideoCommon/GraphicsModSystem/Runtime/CameraManager.h"
|
||||
#include "VideoCommon/GraphicsModSystem/Runtime/GraphicsModBackend.h"
|
||||
|
||||
namespace GraphicsModEditor
|
||||
{
|
||||
class EditorBackend final : public GraphicsModSystem::Runtime::GraphicsModBackend
|
||||
{
|
||||
public:
|
||||
explicit EditorBackend(EditorState&);
|
||||
void OnDraw(const GraphicsModSystem::DrawDataView& draw_started,
|
||||
VertexManagerBase* vertex_manager) override;
|
||||
void OnTextureLoad(const GraphicsModSystem::TextureView& texture) override;
|
||||
void OnTextureUnload(GraphicsModSystem::TextureType texture_type,
|
||||
std::string_view texture_hash) override;
|
||||
void OnTextureCreate(const GraphicsModSystem::TextureView& texture) override;
|
||||
void OnLight() override;
|
||||
void OnFramePresented(const PresentInfo& present_info) override;
|
||||
|
||||
void AddIndices(OpcodeDecoder::Primitive primitive, u32 num_vertices) override;
|
||||
void ResetIndices() override;
|
||||
|
||||
VideoCommon::CameraManager& GetCameraManager() { return m_camera_manager; }
|
||||
|
||||
private:
|
||||
void SelectionOccurred(const std::set<SelectableType>& selection);
|
||||
|
||||
EditorState& m_state;
|
||||
Common::EventHook m_selection_event;
|
||||
std::set<SelectableType> m_selected_objects;
|
||||
|
||||
u64 m_xfb_counter = 0;
|
||||
};
|
||||
} // namespace GraphicsModEditor
|
Loading…
Add table
Reference in a new issue