mirror of
https://github.com/cemu-project/Cemu.git
synced 2025-01-07 15:48:15 +01:00
start metal backend
This commit is contained in:
parent
4b9c7c0d30
commit
2477bad06b
@ -78,6 +78,7 @@ endif()
|
||||
|
||||
option(ENABLE_OPENGL "Enables the OpenGL backend" ON)
|
||||
option(ENABLE_VULKAN "Enables the Vulkan backend" ON)
|
||||
option(ENABLE_METAL "Enables the Metal backend" ON)
|
||||
option(ENABLE_DISCORD_RPC "Enables the Discord Rich Presence feature" ON)
|
||||
|
||||
|
||||
@ -190,9 +191,9 @@ if (ENABLE_WXWIDGETS)
|
||||
endif()
|
||||
|
||||
if (ENABLE_CUBEB)
|
||||
if (NOT ENABLE_VCPKG)
|
||||
find_package(cubeb)
|
||||
endif()
|
||||
#if (NOT ENABLE_VCPKG)
|
||||
#find_package(cubeb)
|
||||
#endif()
|
||||
if (NOT cubeb_FOUND)
|
||||
option(BUILD_TESTS "" OFF)
|
||||
option(BUILD_TOOLS "" OFF)
|
||||
|
@ -524,6 +524,16 @@ if(APPLE)
|
||||
target_sources(CemuCafe PRIVATE "HW/Latte/Renderer/Vulkan/CocoaSurface.mm")
|
||||
endif()
|
||||
|
||||
if(ENABLE_METAL)
|
||||
if(APPLE)
|
||||
target_sources(CemuCafe PRIVATE
|
||||
HW/Latte/Renderer/Metal/MetalRenderer.cpp
|
||||
)
|
||||
else()
|
||||
message(FATAL_ERROR "Metal is only supported on macOS")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
set_property(TARGET CemuCafe PROPERTY MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")
|
||||
|
||||
target_include_directories(CemuCafe PUBLIC "../")
|
||||
|
@ -109,7 +109,7 @@ bool GraphicPack2::LoadGraphicPack(const fs::path& rulesPath, IniParser& rules)
|
||||
|
||||
gp->SetActivePreset(kv.first, kv.second, false);
|
||||
}
|
||||
|
||||
|
||||
gp->SetEnabled(enabled);
|
||||
}
|
||||
|
||||
@ -141,7 +141,7 @@ bool GraphicPack2::DeactivateGraphicPack(const std::shared_ptr<GraphicPack2>& gr
|
||||
if (!graphic_pack->IsActivated())
|
||||
return false;
|
||||
|
||||
const auto it = std::find_if(s_active_graphic_packs.begin(), s_active_graphic_packs.end(),
|
||||
const auto it = std::find_if(s_active_graphic_packs.begin(), s_active_graphic_packs.end(),
|
||||
[graphic_pack](const GraphicPackPtr& gp)
|
||||
{
|
||||
return gp->GetNormalizedPathString() == graphic_pack->GetNormalizedPathString();
|
||||
@ -269,6 +269,8 @@ GraphicPack2::GraphicPack2(fs::path rulesPath, IniParser& rules)
|
||||
m_renderer_api = RendererAPI::Vulkan;
|
||||
else if (boost::iequals(*option_rendererFilter, "opengl"))
|
||||
m_renderer_api = RendererAPI::OpenGL;
|
||||
else if (boost::iequals(*option_rendererFilter, "metal"))
|
||||
m_renderer_api = RendererAPI::Metal;
|
||||
else
|
||||
cemuLog_log(LogType::Force, "Unknown value '{}' for rendererFilter option", *option_rendererFilter);
|
||||
}
|
||||
@ -348,7 +350,7 @@ GraphicPack2::GraphicPack2(fs::path rulesPath, IniParser& rules)
|
||||
cemuLog_log(LogType::Force, "Graphic pack \"{}\": Preset in line {} skipped because it has no name option defined", m_name, rules.GetCurrentSectionLineNumber());
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
const auto category = rules.FindOption("category");
|
||||
const auto condition = rules.FindOption("condition");
|
||||
const auto default_selected = rules.FindOption("default");
|
||||
@ -420,12 +422,12 @@ GraphicPack2::GraphicPack2(fs::path rulesPath, IniParser& rules)
|
||||
{
|
||||
// store by category
|
||||
std::unordered_map<std::string, std::vector<PresetPtr>> tmp_map;
|
||||
|
||||
|
||||
// all vars must be defined in the default preset vars before
|
||||
for (const auto& entry : m_presets)
|
||||
{
|
||||
tmp_map[entry->category].emplace_back(entry);
|
||||
|
||||
|
||||
for (auto& kv : entry->variables)
|
||||
{
|
||||
const auto it = m_preset_vars.find(kv.first);
|
||||
@ -560,7 +562,7 @@ void GraphicPack2::ValidatePresetSelections()
|
||||
//
|
||||
// example: a preset category might be hidden entirely (e.g. due to a separate advanced options dropdown)
|
||||
// how to handle: leave the previously selected preset
|
||||
//
|
||||
//
|
||||
// the logic is therefore as follows:
|
||||
// if there is a preset category with at least 1 visible preset entry then make sure one of those is actually selected
|
||||
// for completely hidden preset categories we leave the selection as-is
|
||||
@ -624,17 +626,17 @@ bool GraphicPack2::SetActivePreset(std::string_view category, std::string_view n
|
||||
// disable currently active preset
|
||||
std::for_each(m_presets.begin(), m_presets.end(), [category](PresetPtr& p)
|
||||
{
|
||||
if(p->category == category)
|
||||
if(p->category == category)
|
||||
p->active = false;
|
||||
});
|
||||
|
||||
|
||||
if (name.empty())
|
||||
return true;
|
||||
|
||||
|
||||
// enable new preset
|
||||
const auto it = std::find_if(m_presets.cbegin(), m_presets.cend(), [category, name](const PresetPtr& preset)
|
||||
{
|
||||
return preset->category == category && preset->name == name;
|
||||
return preset->category == category && preset->name == name;
|
||||
});
|
||||
|
||||
bool result;
|
||||
@ -775,7 +777,7 @@ std::optional<GraphicPack2::PresetVar> GraphicPack2::GetPresetVariable(const std
|
||||
return it->second;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
for (const auto& preset : presets)
|
||||
{
|
||||
if (!preset->visible)
|
||||
@ -785,7 +787,7 @@ std::optional<GraphicPack2::PresetVar> GraphicPack2::GetPresetVariable(const std
|
||||
return it->second;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const auto it = std::find_if(m_preset_vars.cbegin(), m_preset_vars.cend(), [&var_name](auto p) { return p.first == var_name; });
|
||||
if (it != m_preset_vars.cend())
|
||||
{
|
||||
@ -831,7 +833,7 @@ void GraphicPack2::_iterateReplacedFiles(const fs::path& currentPath, bool isAOC
|
||||
virtualMountPath = fs::path("vol/content/") / virtualMountPath;
|
||||
}
|
||||
fscDeviceRedirect_add(virtualMountPath.generic_string(), it.path().generic_string(), m_fs_priority);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -851,7 +853,7 @@ void GraphicPack2::LoadReplacedFiles()
|
||||
std::error_code ec;
|
||||
if (fs::exists(contentPath, ec))
|
||||
{
|
||||
// setup redirections
|
||||
// setup redirections
|
||||
fscDeviceRedirect_map();
|
||||
_iterateReplacedFiles(contentPath, false);
|
||||
}
|
||||
@ -864,7 +866,7 @@ void GraphicPack2::LoadReplacedFiles()
|
||||
uint64 aocTitleId = CafeSystem::GetForegroundTitleId();
|
||||
aocTitleId = aocTitleId & 0xFFFFFFFFULL;
|
||||
aocTitleId |= 0x0005000c00000000ULL;
|
||||
// setup redirections
|
||||
// setup redirections
|
||||
fscDeviceRedirect_map();
|
||||
_iterateReplacedFiles(aocPath, true);
|
||||
}
|
||||
@ -980,7 +982,7 @@ bool GraphicPack2::Activate()
|
||||
|
||||
// enable patch groups
|
||||
EnablePatches();
|
||||
|
||||
|
||||
// load replaced files
|
||||
LoadReplacedFiles();
|
||||
|
||||
@ -1026,7 +1028,7 @@ bool GraphicPack2::Deactivate()
|
||||
m_output_shader_source.clear();
|
||||
m_upscaling_shader_source.clear();
|
||||
m_downscaling_shader_source.clear();
|
||||
|
||||
|
||||
if (HasCustomVSyncFrequency())
|
||||
{
|
||||
m_vsync_frequency = -1;
|
||||
@ -1058,7 +1060,7 @@ const std::string* GraphicPack2::FindCustomShaderSource(uint64 shaderBaseHash, u
|
||||
std::unordered_map<std::string, std::vector<GraphicPack2::PresetPtr>> GraphicPack2::GetCategorizedPresets(std::vector<std::string>& order) const
|
||||
{
|
||||
order.clear();
|
||||
|
||||
|
||||
std::unordered_map<std::string, std::vector<PresetPtr>> result;
|
||||
for(const auto& entry : m_presets)
|
||||
{
|
||||
@ -1067,13 +1069,13 @@ std::unordered_map<std::string, std::vector<GraphicPack2::PresetPtr>> GraphicPac
|
||||
if (it == order.cend())
|
||||
order.emplace_back(entry->category);
|
||||
}
|
||||
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool GraphicPack2::HasShaders() const
|
||||
{
|
||||
return !GetCustomShaders().empty()
|
||||
return !GetCustomShaders().empty()
|
||||
|| !m_output_shader_source.empty() || !m_upscaling_shader_source.empty() || !m_downscaling_shader_source.empty();
|
||||
}
|
||||
|
||||
|
198
src/Cafe/HW/Latte/Renderer/Metal/MetalRenderer.cpp
Normal file
198
src/Cafe/HW/Latte/Renderer/Metal/MetalRenderer.cpp
Normal file
@ -0,0 +1,198 @@
|
||||
#include "Cafe/HW/Latte/Renderer/Metal/MetalRenderer.h"
|
||||
|
||||
void MetalRenderer::InitializeLayer(const Vector2i& size, bool mainWindow) {
|
||||
/*
|
||||
const auto& windowInfo = gui_getWindowInfo().window_main;
|
||||
|
||||
NSView* view = (NS::View*)handle;
|
||||
|
||||
MetalView* childView = [[MetalView alloc] initWithFrame:view.bounds];
|
||||
childView.autoresizingMask = NSViewWidthSizable | NSViewHeightSizable;
|
||||
childView.wantsLayer = YES;
|
||||
|
||||
[view addSubview:childView];
|
||||
|
||||
VkMetalSurfaceCreateInfoEXT surface;
|
||||
surface.sType = VK_STRUCTURE_TYPE_METAL_SURFACE_CREATE_INFO_EXT;
|
||||
surface.pNext = NULL;
|
||||
surface.flags = 0;
|
||||
surface.pLayer = (CAMetalLayer*)childView.layer;
|
||||
*/
|
||||
}
|
||||
|
||||
void MetalRenderer::Initialize() {
|
||||
cemuLog_logDebug(LogType::Force, "not implemented");
|
||||
}
|
||||
|
||||
void MetalRenderer::Shutdown() {
|
||||
cemuLog_logDebug(LogType::Force, "not implemented");
|
||||
}
|
||||
|
||||
bool MetalRenderer::IsPadWindowActive() {
|
||||
cemuLog_logDebug(LogType::Force, "not implemented");
|
||||
}
|
||||
|
||||
bool MetalRenderer::GetVRAMInfo(int& usageInMB, int& totalInMB) const {
|
||||
cemuLog_logDebug(LogType::Force, "not implemented");
|
||||
}
|
||||
|
||||
void MetalRenderer::ClearColorbuffer(bool padView) {
|
||||
cemuLog_logDebug(LogType::Force, "not implemented");
|
||||
}
|
||||
|
||||
void MetalRenderer::DrawEmptyFrame(bool mainWindow) {
|
||||
cemuLog_logDebug(LogType::Force, "not implemented");
|
||||
}
|
||||
|
||||
void MetalRenderer::SwapBuffers(bool swapTV, bool swapDRC) {
|
||||
cemuLog_logDebug(LogType::Force, "not implemented");
|
||||
}
|
||||
|
||||
void MetalRenderer::DrawBackbufferQuad(LatteTextureView* texView, RendererOutputShader* shader, bool useLinearTexFilter,
|
||||
sint32 imageX, sint32 imageY, sint32 imageWidth, sint32 imageHeight,
|
||||
bool padView, bool clearBackground) {
|
||||
cemuLog_logDebug(LogType::Force, "not implemented");
|
||||
}
|
||||
bool MetalRenderer::BeginFrame(bool mainWindow) {
|
||||
cemuLog_logDebug(LogType::Force, "not implemented");
|
||||
}
|
||||
|
||||
void MetalRenderer::Flush(bool waitIdle) {
|
||||
cemuLog_logDebug(LogType::Force, "not implemented");
|
||||
}
|
||||
|
||||
void MetalRenderer::NotifyLatteCommandProcessorIdle() {
|
||||
cemuLog_logDebug(LogType::Force, "not implemented");
|
||||
}
|
||||
|
||||
void MetalRenderer::AppendOverlayDebugInfo() {
|
||||
cemuLog_logDebug(LogType::Force, "not implemented");
|
||||
}
|
||||
|
||||
void MetalRenderer::renderTarget_setViewport(float x, float y, float width, float height, float nearZ, float farZ, bool halfZ) {
|
||||
cemuLog_logDebug(LogType::Force, "not implemented");
|
||||
}
|
||||
|
||||
void MetalRenderer::renderTarget_setScissor(sint32 scissorX, sint32 scissorY, sint32 scissorWidth, sint32 scissorHeight) {
|
||||
cemuLog_logDebug(LogType::Force, "not implemented");
|
||||
}
|
||||
|
||||
LatteCachedFBO* MetalRenderer::rendertarget_createCachedFBO(uint64 key) {
|
||||
cemuLog_logDebug(LogType::Force, "not implemented");
|
||||
}
|
||||
|
||||
void MetalRenderer::rendertarget_deleteCachedFBO(LatteCachedFBO* fbo) {
|
||||
cemuLog_logDebug(LogType::Force, "not implemented");
|
||||
}
|
||||
|
||||
void MetalRenderer::rendertarget_bindFramebufferObject(LatteCachedFBO* cfbo) {
|
||||
cemuLog_logDebug(LogType::Force, "not implemented");
|
||||
}
|
||||
|
||||
void* MetalRenderer::texture_acquireTextureUploadBuffer(uint32 size) {
|
||||
cemuLog_logDebug(LogType::Force, "not implemented");
|
||||
}
|
||||
|
||||
void MetalRenderer::texture_releaseTextureUploadBuffer(uint8* mem) {
|
||||
cemuLog_logDebug(LogType::Force, "not implemented");
|
||||
}
|
||||
|
||||
TextureDecoder* MetalRenderer::texture_chooseDecodedFormat(Latte::E_GX2SURFFMT format, bool isDepth, Latte::E_DIM dim, uint32 width, uint32 height) {
|
||||
cemuLog_logDebug(LogType::Force, "not implemented");
|
||||
}
|
||||
|
||||
void MetalRenderer::texture_clearSlice(LatteTexture* hostTexture, sint32 sliceIndex, sint32 mipIndex) {
|
||||
cemuLog_logDebug(LogType::Force, "not implemented");
|
||||
}
|
||||
|
||||
void MetalRenderer::texture_loadSlice(LatteTexture* hostTexture, sint32 width, sint32 height, sint32 depth, void* pixelData, sint32 sliceIndex, sint32 mipIndex, uint32 compressedImageSize) {
|
||||
cemuLog_logDebug(LogType::Force, "not implemented");
|
||||
}
|
||||
|
||||
void MetalRenderer::texture_clearColorSlice(LatteTexture* hostTexture, sint32 sliceIndex, sint32 mipIndex, float r, float g, float b, float a) {
|
||||
cemuLog_logDebug(LogType::Force, "not implemented");
|
||||
}
|
||||
|
||||
void MetalRenderer::texture_clearDepthSlice(LatteTexture* hostTexture, uint32 sliceIndex, sint32 mipIndex, bool clearDepth, bool clearStencil, float depthValue, uint32 stencilValue) {
|
||||
cemuLog_logDebug(LogType::Force, "not implemented");
|
||||
}
|
||||
|
||||
LatteTexture* MetalRenderer::texture_createTextureEx(Latte::E_DIM dim, MPTR physAddress, MPTR physMipAddress, Latte::E_GX2SURFFMT format, uint32 width, uint32 height, uint32 depth, uint32 pitch, uint32 mipLevels, uint32 swizzle, Latte::E_HWTILEMODE tileMode, bool isDepth) {
|
||||
cemuLog_logDebug(LogType::Force, "not implemented");
|
||||
}
|
||||
|
||||
void MetalRenderer::texture_setLatteTexture(LatteTextureView* textureView, uint32 textureUnit) {
|
||||
cemuLog_logDebug(LogType::Force, "not implemented");
|
||||
}
|
||||
|
||||
void MetalRenderer::texture_copyImageSubData(LatteTexture* src, sint32 srcMip, sint32 effectiveSrcX, sint32 effectiveSrcY, sint32 srcSlice, LatteTexture* dst, sint32 dstMip, sint32 effectiveDstX, sint32 effectiveDstY, sint32 dstSlice, sint32 effectiveCopyWidth, sint32 effectiveCopyHeight, sint32 srcDepth) {
|
||||
cemuLog_logDebug(LogType::Force, "not implemented");
|
||||
}
|
||||
|
||||
LatteTextureReadbackInfo* MetalRenderer::texture_createReadback(LatteTextureView* textureView) {
|
||||
cemuLog_logDebug(LogType::Force, "not implemented");
|
||||
}
|
||||
|
||||
void MetalRenderer::surfaceCopy_copySurfaceWithFormatConversion(LatteTexture* sourceTexture, sint32 srcMip, sint32 srcSlice, LatteTexture* destinationTexture, sint32 dstMip, sint32 dstSlice, sint32 width, sint32 height) {
|
||||
cemuLog_logDebug(LogType::Force, "not implemented");
|
||||
}
|
||||
|
||||
void MetalRenderer::bufferCache_init(const sint32 bufferSize) {
|
||||
cemuLog_logDebug(LogType::Force, "not implemented");
|
||||
}
|
||||
|
||||
void MetalRenderer::bufferCache_upload(uint8* buffer, sint32 size, uint32 bufferOffset) {
|
||||
cemuLog_logDebug(LogType::Force, "not implemented");
|
||||
}
|
||||
|
||||
void MetalRenderer::bufferCache_copy(uint32 srcOffset, uint32 dstOffset, uint32 size) {
|
||||
cemuLog_logDebug(LogType::Force, "not implemented");
|
||||
}
|
||||
|
||||
void MetalRenderer::bufferCache_copyStreamoutToMainBuffer(uint32 srcOffset, uint32 dstOffset, uint32 size) {
|
||||
cemuLog_logDebug(LogType::Force, "not implemented");
|
||||
}
|
||||
|
||||
void MetalRenderer::buffer_bindVertexBuffer(uint32 bufferIndex, uint32 offset, uint32 size) {
|
||||
cemuLog_logDebug(LogType::Force, "not implemented");
|
||||
}
|
||||
|
||||
void MetalRenderer::buffer_bindUniformBuffer(LatteConst::ShaderType shaderType, uint32 bufferIndex, uint32 offset, uint32 size) {
|
||||
cemuLog_logDebug(LogType::Force, "not implemented");
|
||||
}
|
||||
|
||||
RendererShader* MetalRenderer::shader_create(RendererShader::ShaderType type, uint64 baseHash, uint64 auxHash, const std::string& source, bool compileAsync, bool isGfxPackSource) {
|
||||
cemuLog_logDebug(LogType::Force, "not implemented");
|
||||
}
|
||||
|
||||
void MetalRenderer::streamout_setupXfbBuffer(uint32 bufferIndex, sint32 ringBufferOffset, uint32 rangeAddr, uint32 rangeSize) {
|
||||
cemuLog_logDebug(LogType::Force, "not implemented");
|
||||
}
|
||||
|
||||
void MetalRenderer::streamout_begin() {
|
||||
cemuLog_logDebug(LogType::Force, "not implemented");
|
||||
}
|
||||
|
||||
void MetalRenderer::streamout_rendererFinishDrawcall() {
|
||||
cemuLog_logDebug(LogType::Force, "not implemented");
|
||||
}
|
||||
|
||||
void MetalRenderer::draw_beginSequence() {
|
||||
cemuLog_logDebug(LogType::Force, "not implemented");
|
||||
}
|
||||
|
||||
void MetalRenderer::draw_execute(uint32 baseVertex, uint32 baseInstance, uint32 instanceCount, uint32 count, MPTR indexDataMPTR, Latte::LATTE_VGT_DMA_INDEX_TYPE::E_INDEX_TYPE indexType, bool isFirst) {
|
||||
cemuLog_logDebug(LogType::Force, "not implemented");
|
||||
}
|
||||
|
||||
void MetalRenderer::draw_endSequence() {
|
||||
cemuLog_logDebug(LogType::Force, "not implemented");
|
||||
}
|
||||
|
||||
void* MetalRenderer::indexData_reserveIndexMemory(uint32 size, uint32& offset, uint32& bufferIndex) {
|
||||
cemuLog_logDebug(LogType::Force, "not implemented");
|
||||
}
|
||||
|
||||
void MetalRenderer::indexData_uploadIndexMemory(uint32 offset, uint32 size) {
|
||||
cemuLog_logDebug(LogType::Force, "not implemented");
|
||||
}
|
142
src/Cafe/HW/Latte/Renderer/Metal/MetalRenderer.h
Normal file
142
src/Cafe/HW/Latte/Renderer/Metal/MetalRenderer.h
Normal file
@ -0,0 +1,142 @@
|
||||
#pragma once
|
||||
|
||||
#include "Cafe/HW/Latte/Renderer/Renderer.h"
|
||||
|
||||
class MetalRenderer : public Renderer
|
||||
{
|
||||
public:
|
||||
~MetalRenderer() = default;
|
||||
|
||||
RendererAPI GetType() override
|
||||
{
|
||||
return RendererAPI::Metal;
|
||||
}
|
||||
|
||||
static MetalRenderer* GetInstance() {
|
||||
return static_cast<MetalRenderer*>(g_renderer.get());
|
||||
}
|
||||
|
||||
void InitializeLayer(const Vector2i& size, bool mainWindow);
|
||||
|
||||
void Initialize() override;
|
||||
void Shutdown() override;
|
||||
bool IsPadWindowActive() override;
|
||||
|
||||
bool GetVRAMInfo(int& usageInMB, int& totalInMB) const override;
|
||||
|
||||
void ClearColorbuffer(bool padView) override;
|
||||
void DrawEmptyFrame(bool mainWindow) override;
|
||||
void SwapBuffers(bool swapTV, bool swapDRC) override;
|
||||
|
||||
void HandleScreenshotRequest(LatteTextureView* texView, bool padView) override {
|
||||
cemuLog_logDebug(LogType::Force, "Screenshots are not yet supported on Metal");
|
||||
}
|
||||
|
||||
void DrawBackbufferQuad(LatteTextureView* texView, RendererOutputShader* shader, bool useLinearTexFilter,
|
||||
sint32 imageX, sint32 imageY, sint32 imageWidth, sint32 imageHeight,
|
||||
bool padView, bool clearBackground) override;
|
||||
bool BeginFrame(bool mainWindow) override;
|
||||
|
||||
// flush control
|
||||
void Flush(bool waitIdle = false) override; // called when explicit flush is required (e.g. by imgui)
|
||||
void NotifyLatteCommandProcessorIdle() override; // called when command processor has no more commands available or when stalled
|
||||
|
||||
// imgui
|
||||
bool ImguiBegin(bool mainWindow) override {
|
||||
cemuLog_logDebug(LogType::Force, "Imgui is not yet supported on Metal");
|
||||
};
|
||||
|
||||
void ImguiEnd() override {
|
||||
cemuLog_logDebug(LogType::Force, "Imgui is not yet supported on Metal");
|
||||
};
|
||||
|
||||
ImTextureID GenerateTexture(const std::vector<uint8>& data, const Vector2i& size) override {
|
||||
cemuLog_logDebug(LogType::Force, "Imgui is not yet supported on Metal");
|
||||
};
|
||||
|
||||
void DeleteTexture(ImTextureID id) override {
|
||||
cemuLog_logDebug(LogType::Force, "Imgui is not yet supported on Metal");
|
||||
};
|
||||
|
||||
void DeleteFontTextures() override {
|
||||
cemuLog_logDebug(LogType::Force, "Imgui is not yet supported on Metal");
|
||||
};
|
||||
|
||||
void AppendOverlayDebugInfo() override;
|
||||
|
||||
// rendertarget
|
||||
void renderTarget_setViewport(float x, float y, float width, float height, float nearZ, float farZ, bool halfZ = false) override;
|
||||
void renderTarget_setScissor(sint32 scissorX, sint32 scissorY, sint32 scissorWidth, sint32 scissorHeight) override;
|
||||
|
||||
LatteCachedFBO* rendertarget_createCachedFBO(uint64 key) override;
|
||||
void rendertarget_deleteCachedFBO(LatteCachedFBO* fbo) override;
|
||||
void rendertarget_bindFramebufferObject(LatteCachedFBO* cfbo) override;
|
||||
|
||||
// texture functions
|
||||
void* texture_acquireTextureUploadBuffer(uint32 size) override;
|
||||
void texture_releaseTextureUploadBuffer(uint8* mem) override;
|
||||
|
||||
TextureDecoder* texture_chooseDecodedFormat(Latte::E_GX2SURFFMT format, bool isDepth, Latte::E_DIM dim, uint32 width, uint32 height) override;
|
||||
|
||||
void texture_clearSlice(LatteTexture* hostTexture, sint32 sliceIndex, sint32 mipIndex) override;
|
||||
void texture_loadSlice(LatteTexture* hostTexture, sint32 width, sint32 height, sint32 depth, void* pixelData, sint32 sliceIndex, sint32 mipIndex, uint32 compressedImageSize) override;
|
||||
void texture_clearColorSlice(LatteTexture* hostTexture, sint32 sliceIndex, sint32 mipIndex, float r, float g, float b, float a) override;
|
||||
void texture_clearDepthSlice(LatteTexture* hostTexture, uint32 sliceIndex, sint32 mipIndex, bool clearDepth, bool clearStencil, float depthValue, uint32 stencilValue) override;
|
||||
|
||||
LatteTexture* texture_createTextureEx(Latte::E_DIM dim, MPTR physAddress, MPTR physMipAddress, Latte::E_GX2SURFFMT format, uint32 width, uint32 height, uint32 depth, uint32 pitch, uint32 mipLevels, uint32 swizzle, Latte::E_HWTILEMODE tileMode, bool isDepth) override;
|
||||
|
||||
void texture_setLatteTexture(LatteTextureView* textureView, uint32 textureUnit) override;
|
||||
void texture_copyImageSubData(LatteTexture* src, sint32 srcMip, sint32 effectiveSrcX, sint32 effectiveSrcY, sint32 srcSlice, LatteTexture* dst, sint32 dstMip, sint32 effectiveDstX, sint32 effectiveDstY, sint32 dstSlice, sint32 effectiveCopyWidth, sint32 effectiveCopyHeight, sint32 srcDepth) override;
|
||||
|
||||
LatteTextureReadbackInfo* texture_createReadback(LatteTextureView* textureView) override;
|
||||
|
||||
// surface copy
|
||||
void surfaceCopy_copySurfaceWithFormatConversion(LatteTexture* sourceTexture, sint32 srcMip, sint32 srcSlice, LatteTexture* destinationTexture, sint32 dstMip, sint32 dstSlice, sint32 width, sint32 height) override;
|
||||
|
||||
// buffer cache
|
||||
void bufferCache_init(const sint32 bufferSize) override;
|
||||
void bufferCache_upload(uint8* buffer, sint32 size, uint32 bufferOffset) override;
|
||||
void bufferCache_copy(uint32 srcOffset, uint32 dstOffset, uint32 size) override;
|
||||
void bufferCache_copyStreamoutToMainBuffer(uint32 srcOffset, uint32 dstOffset, uint32 size) override;
|
||||
|
||||
void buffer_bindVertexBuffer(uint32 bufferIndex, uint32 offset, uint32 size) override;
|
||||
void buffer_bindUniformBuffer(LatteConst::ShaderType shaderType, uint32 bufferIndex, uint32 offset, uint32 size) override;
|
||||
|
||||
// shader
|
||||
RendererShader* shader_create(RendererShader::ShaderType type, uint64 baseHash, uint64 auxHash, const std::string& source, bool compileAsync, bool isGfxPackSource) override;
|
||||
|
||||
// streamout
|
||||
void streamout_setupXfbBuffer(uint32 bufferIndex, sint32 ringBufferOffset, uint32 rangeAddr, uint32 rangeSize) override;
|
||||
void streamout_begin() override;
|
||||
void streamout_rendererFinishDrawcall() override;
|
||||
|
||||
// core drawing logic
|
||||
void draw_beginSequence() override;
|
||||
void draw_execute(uint32 baseVertex, uint32 baseInstance, uint32 instanceCount, uint32 count, MPTR indexDataMPTR, Latte::LATTE_VGT_DMA_INDEX_TYPE::E_INDEX_TYPE indexType, bool isFirst) override;
|
||||
void draw_endSequence() override;
|
||||
|
||||
// index
|
||||
void* indexData_reserveIndexMemory(uint32 size, uint32& offset, uint32& bufferIndex) override;
|
||||
void indexData_uploadIndexMemory(uint32 offset, uint32 size) override;
|
||||
|
||||
// occlusion queries
|
||||
LatteQueryObject* occlusionQuery_create() override {
|
||||
cemuLog_logDebug(LogType::Force, "Occlusion queries are not yet supported on Metal");
|
||||
}
|
||||
|
||||
void occlusionQuery_destroy(LatteQueryObject* queryObj) override {
|
||||
cemuLog_logDebug(LogType::Force, "Occlusion queries are not yet supported on Metal");
|
||||
}
|
||||
|
||||
void occlusionQuery_flush() override {
|
||||
cemuLog_logDebug(LogType::Force, "Occlusion queries are not yet supported on Metal");
|
||||
}
|
||||
|
||||
void occlusionQuery_updateState() override {
|
||||
cemuLog_logDebug(LogType::Force, "Occlusion queries are not yet supported on Metal");
|
||||
}
|
||||
|
||||
|
||||
protected:
|
||||
//CA::MetalLayer* m_metalLayer;
|
||||
};
|
@ -33,6 +33,7 @@ enum class RendererAPI
|
||||
{
|
||||
OpenGL,
|
||||
Vulkan,
|
||||
Metal,
|
||||
|
||||
MAX
|
||||
};
|
||||
@ -66,9 +67,9 @@ public:
|
||||
virtual void SwapBuffers(bool swapTV, bool swapDRC) = 0;
|
||||
|
||||
virtual void HandleScreenshotRequest(LatteTextureView* texView, bool padView){}
|
||||
|
||||
virtual void DrawBackbufferQuad(LatteTextureView* texView, RendererOutputShader* shader, bool useLinearTexFilter,
|
||||
sint32 imageX, sint32 imageY, sint32 imageWidth, sint32 imageHeight,
|
||||
|
||||
virtual void DrawBackbufferQuad(LatteTextureView* texView, RendererOutputShader* shader, bool useLinearTexFilter,
|
||||
sint32 imageX, sint32 imageY, sint32 imageWidth, sint32 imageHeight,
|
||||
bool padView, bool clearBackground) = 0;
|
||||
virtual bool BeginFrame(bool mainWindow) = 0;
|
||||
|
||||
|
@ -59,6 +59,7 @@ const std::map<LogType, std::string> g_logging_window_mapping
|
||||
{LogType::TextureReadback, "Texture readback"},
|
||||
{LogType::OpenGLLogging, "OpenGL debug output"},
|
||||
{LogType::VulkanValidation, "Vulkan validation layer"},
|
||||
{LogType::MetalLogging, "Metal debug output"},
|
||||
};
|
||||
|
||||
bool cemuLog_advancedPPCLoggingEnabled()
|
||||
@ -158,7 +159,7 @@ bool cemuLog_log(LogType type, std::string_view text)
|
||||
|
||||
bool cemuLog_log(LogType type, std::u8string_view text)
|
||||
{
|
||||
std::basic_string_view<char> s((char*)text.data(), text.size());
|
||||
std::basic_string_view<char> s((char*)text.data(), text.size());
|
||||
return cemuLog_log(type, s);
|
||||
}
|
||||
|
||||
|
@ -20,6 +20,7 @@ enum class LogType : sint32
|
||||
OpenGLLogging = 10, // OpenGL debug logging
|
||||
TextureCache = 11, // texture cache warnings and info
|
||||
VulkanValidation = 12, // Vulkan validation layer
|
||||
MetalLogging = 13, // Metal debug logging
|
||||
Patches = 14,
|
||||
CoreinitMem = 8, // coreinit memory functions
|
||||
CoreinitMP = 15,
|
||||
@ -52,7 +53,7 @@ enum class LogType : sint32
|
||||
template <>
|
||||
struct fmt::formatter<std::u8string_view> : formatter<string_view> {
|
||||
template <typename FormatContext>
|
||||
auto format(std::u8string_view v, FormatContext& ctx)
|
||||
auto format(std::u8string_view v, FormatContext& ctx)
|
||||
{
|
||||
string_view s((char*)v.data(), v.size());
|
||||
return formatter<string_view>::format(s, ctx);
|
||||
@ -96,7 +97,7 @@ bool cemuLog_log(LogType type, std::basic_string<T> formatStr, TArgs&&... args)
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
template<typename T, typename ... TArgs>
|
||||
bool cemuLog_log(LogType type, const T* format, TArgs&&... args)
|
||||
{
|
||||
|
@ -32,7 +32,7 @@ struct GameEntry
|
||||
std::wstring save_folder;
|
||||
std::wstring update_folder;
|
||||
std::wstring dlc_folder;
|
||||
|
||||
|
||||
uint64 legacy_time_played = 0;
|
||||
uint64 legacy_last_played = 0;
|
||||
|
||||
@ -74,6 +74,7 @@ enum GraphicAPI
|
||||
{
|
||||
kOpenGL = 0,
|
||||
kVulkan,
|
||||
kMetal,
|
||||
};
|
||||
|
||||
enum AudioChannels
|
||||
@ -105,7 +106,7 @@ enum class ScreenPosition
|
||||
kTopRight,
|
||||
kBottomLeft,
|
||||
kBottomCenter,
|
||||
kBottomRight,
|
||||
kBottomRight,
|
||||
};
|
||||
|
||||
enum class PrecompiledShaderOption
|
||||
@ -134,7 +135,7 @@ enum class CPUMode
|
||||
ENABLE_ENUM_ITERATORS(CPUMode, CPUMode::SinglecoreInterpreter, CPUMode::Auto);
|
||||
|
||||
|
||||
enum class CPUModeLegacy
|
||||
enum class CPUModeLegacy
|
||||
{
|
||||
SinglecoreInterpreter = 0,
|
||||
SinglecoreRecompiler = 1,
|
||||
@ -270,7 +271,7 @@ struct fmt::formatter<CafeConsoleRegion> : formatter<string_view> {
|
||||
case CafeConsoleRegion::TWN: name = wxTRANSLATE("Taiwan"); break;
|
||||
case CafeConsoleRegion::Auto: name = wxTRANSLATE("Auto"); break;
|
||||
default: name = wxTRANSLATE("many"); break;
|
||||
|
||||
|
||||
}
|
||||
return formatter<string_view>::format(name, ctx);
|
||||
}
|
||||
@ -312,7 +313,7 @@ struct fmt::formatter<CrashDump> : formatter<string_view> {
|
||||
case CrashDump::Lite: name = "Lite"; break;
|
||||
case CrashDump::Full: name = "Full"; break;
|
||||
default: name = "unknown"; break;
|
||||
|
||||
|
||||
}
|
||||
return formatter<string_view>::format(name, ctx);
|
||||
}
|
||||
@ -363,7 +364,7 @@ struct CemuConfig
|
||||
ConfigValue<bool> advanced_ppc_logging{ false };
|
||||
|
||||
ConfigValue<bool> permanent_storage{ true };
|
||||
|
||||
|
||||
ConfigValue<sint32> language{ wxLANGUAGE_DEFAULT };
|
||||
ConfigValue<bool> use_discord_presence{ true };
|
||||
ConfigValue<std::string> mlc_path{};
|
||||
@ -387,7 +388,7 @@ struct CemuConfig
|
||||
|
||||
// optimized access
|
||||
std::set<uint64> game_cache_favorites; // per titleId
|
||||
|
||||
|
||||
struct _path_hash {
|
||||
std::size_t operator()(const fs::path& path) const {
|
||||
return fs::hash_value(path);
|
||||
@ -514,7 +515,7 @@ struct CemuConfig
|
||||
|
||||
NetworkService GetAccountNetworkService(uint32 persistentId);
|
||||
void SetAccountSelectedService(uint32 persistentId, NetworkService serviceIndex);
|
||||
|
||||
|
||||
// emulated usb devices
|
||||
struct
|
||||
{
|
||||
@ -530,5 +531,3 @@ struct CemuConfig
|
||||
typedef XMLDataConfig<CemuConfig, &CemuConfig::Load, &CemuConfig::Save> XMLCemuConfig_t;
|
||||
extern XMLCemuConfig_t g_config;
|
||||
inline CemuConfig& GetConfig() { return g_config.data(); }
|
||||
|
||||
|
||||
|
@ -1,9 +1,11 @@
|
||||
add_library(CemuGui
|
||||
add_library(CemuGui
|
||||
canvas/IRenderCanvas.h
|
||||
canvas/OpenGLCanvas.cpp
|
||||
canvas/OpenGLCanvas.h
|
||||
canvas/VulkanCanvas.cpp
|
||||
canvas/VulkanCanvas.h
|
||||
canvas/MetalCanvas.cpp
|
||||
canvas/MetalCanvas.h
|
||||
CemuApp.cpp
|
||||
CemuApp.h
|
||||
CemuUpdateWindow.cpp
|
||||
|
@ -61,7 +61,7 @@ GameProfileWindow::GameProfileWindow(wxWindow* parent, uint64_t title_id)
|
||||
const sint32 m_cpu_modeNChoices = std::size(cpu_modes);
|
||||
m_cpu_mode = new wxChoice(box, wxID_ANY, wxDefaultPosition, wxDefaultSize, m_cpu_modeNChoices, cpu_modes, 0);
|
||||
m_cpu_mode->SetToolTip(_("Set the CPU emulation mode"));
|
||||
first_row->Add(m_cpu_mode, 0, wxALL, 5);
|
||||
first_row->Add(m_cpu_mode, 0, wxALL, 5);
|
||||
|
||||
first_row->Add(new wxStaticText(box, wxID_ANY, _("Thread quantum")), 0, wxALIGN_CENTER_VERTICAL | wxALL, 5);
|
||||
|
||||
@ -112,10 +112,14 @@ GameProfileWindow::GameProfileWindow(wxWindow* parent, uint64_t title_id)
|
||||
|
||||
first_row->Add(new wxStaticText(panel, wxID_ANY, _("Graphics API")), 0, wxALIGN_CENTER_VERTICAL | wxALL, 5);
|
||||
|
||||
wxString gapi_values[] = { "", "OpenGL", "Vulkan" };
|
||||
wxString gapi_values[] = { "", "OpenGL", "Vulkan",
|
||||
#ifdef __APPLE__
|
||||
"Metal"
|
||||
#endif
|
||||
};
|
||||
m_graphic_api = new wxChoice(panel, wxID_ANY, wxDefaultPosition, wxDefaultSize, (int)std::size(gapi_values), gapi_values);
|
||||
first_row->Add(m_graphic_api, 0, wxALL, 5);
|
||||
|
||||
|
||||
first_row->Add(new wxStaticText(panel, wxID_ANY, _("Shader multiplication accuracy")), 0, wxALIGN_CENTER_VERTICAL | wxALL, 5);
|
||||
|
||||
wxString mul_values[] = { _("false"), _("true")};
|
||||
@ -249,7 +253,7 @@ void GameProfileWindow::ApplyProfile()
|
||||
// general
|
||||
m_load_libs->SetValue(m_game_profile.m_loadSharedLibraries.value());
|
||||
m_start_with_padview->SetValue(m_game_profile.m_startWithPadView);
|
||||
|
||||
|
||||
// cpu
|
||||
// wxString cpu_modes[] = { _("Singlecore-Interpreter"), _("Singlecore-Recompiler"), _("Triplecore-Recompiler"), _("Auto (recommended)") };
|
||||
switch(m_game_profile.m_cpuMode.value())
|
||||
@ -258,9 +262,9 @@ void GameProfileWindow::ApplyProfile()
|
||||
case CPUMode::SinglecoreRecompiler: m_cpu_mode->SetSelection(1); break;
|
||||
case CPUMode::DualcoreRecompiler: m_cpu_mode->SetSelection(2); break;
|
||||
case CPUMode::MulticoreRecompiler: m_cpu_mode->SetSelection(2); break;
|
||||
default: m_cpu_mode->SetSelection(3);
|
||||
default: m_cpu_mode->SetSelection(3);
|
||||
}
|
||||
|
||||
|
||||
m_thread_quantum->SetStringSelection(fmt::format("{}", m_game_profile.m_threadQuantum));
|
||||
|
||||
// gpu
|
||||
@ -275,7 +279,7 @@ void GameProfileWindow::ApplyProfile()
|
||||
|
||||
// controller
|
||||
auto profiles = InputManager::get_profiles();
|
||||
|
||||
|
||||
for (const auto& cb : m_controller_profile)
|
||||
{
|
||||
cb->Clear();
|
||||
@ -293,7 +297,7 @@ void GameProfileWindow::ApplyProfile()
|
||||
const auto& v = m_game_profile.m_controllerProfile[i].value();
|
||||
m_controller_profile[i]->SetStringSelection(wxString::FromUTF8(v));
|
||||
}
|
||||
|
||||
|
||||
else
|
||||
m_controller_profile[i]->SetSelection(wxNOT_FOUND);
|
||||
}
|
||||
@ -317,7 +321,7 @@ void GameProfileWindow::SaveProfile()
|
||||
m_game_profile.m_cpuMode = CPUMode::Auto;
|
||||
}
|
||||
|
||||
|
||||
|
||||
const wxString thread_quantum = m_thread_quantum->GetStringSelection();
|
||||
if (!thread_quantum.empty())
|
||||
{
|
||||
@ -365,4 +369,4 @@ void GameProfileWindow::SetSliderValue(wxSlider* slider, sint32 new_value) const
|
||||
slider_event.SetEventObject(slider);
|
||||
slider_event.SetClientData((void*)IsFrozen());
|
||||
wxPostEvent(slider->GetEventHandler(), slider_event);
|
||||
}
|
||||
}
|
||||
|
@ -101,7 +101,7 @@ public:
|
||||
|
||||
Account& GetAccount() { return m_account; }
|
||||
const Account& GetAccount() const { return m_account; }
|
||||
|
||||
|
||||
private:
|
||||
Account m_account;
|
||||
};
|
||||
@ -165,11 +165,11 @@ wxPanel* GeneralSettings2::AddGeneralPage(wxNotebook* notebook)
|
||||
m_auto_update = new wxCheckBox(box, wxID_ANY, _("Automatically check for updates"));
|
||||
m_auto_update->SetToolTip(_("Automatically checks for new cemu versions on startup"));
|
||||
second_row->Add(m_auto_update, 0, botflag, 5);
|
||||
#if BOOST_OS_LINUX
|
||||
#if BOOST_OS_LINUX
|
||||
if (!std::getenv("APPIMAGE")) {
|
||||
m_auto_update->Disable();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
second_row->AddSpacer(10);
|
||||
m_save_screenshot = new wxCheckBox(box, wxID_ANY, _("Save screenshot"));
|
||||
m_save_screenshot->SetToolTip(_("Pressing the screenshot key (F12) will save a screenshot directly to the screenshots folder"));
|
||||
@ -276,12 +276,14 @@ wxPanel* GeneralSettings2::AddGraphicsPage(wxNotebook* notebook)
|
||||
row->Add(new wxStaticText(box, wxID_ANY, _("Graphics API")), 0, wxALIGN_CENTER_VERTICAL | wxALL, 5);
|
||||
|
||||
sint32 api_size = 1;
|
||||
wxString choices[2] = { "OpenGL" };
|
||||
wxString choices[3] = { "OpenGL" };
|
||||
if (g_vulkan_available)
|
||||
{
|
||||
choices[1] = "Vulkan";
|
||||
api_size = 2;
|
||||
choices[api_size++] = "Vulkan";
|
||||
}
|
||||
#ifdef __APPLE__
|
||||
choices[api_size++] = "Metal";
|
||||
#endif
|
||||
|
||||
m_graphic_api = new wxChoice(box, wxID_ANY, wxDefaultPosition, wxDefaultSize, api_size, choices);
|
||||
m_graphic_api->SetSelection(0);
|
||||
@ -728,7 +730,7 @@ wxPanel* GeneralSettings2::AddAccountPage(wxNotebook* notebook)
|
||||
auto* row = new wxFlexGridSizer(0, 2, 0, 0);
|
||||
row->SetFlexibleDirection(wxBOTH);
|
||||
row->SetNonFlexibleGrowMode(wxFLEX_GROWMODE_SPECIFIED);
|
||||
|
||||
|
||||
const wxImage tmp = wxBITMAP_PNG_FROM_DATA(PNG_ERROR).ConvertToImage();
|
||||
m_validate_online = new wxBitmapButton(box, wxID_ANY, tmp.Scale(16, 16));
|
||||
m_validate_online->Bind(wxEVT_BUTTON, &GeneralSettings2::OnShowOnlineValidator, this);
|
||||
@ -738,7 +740,7 @@ wxPanel* GeneralSettings2::AddAccountPage(wxNotebook* notebook)
|
||||
row->Add(m_online_status, 1, wxALL | wxALIGN_CENTRE_VERTICAL, 5);
|
||||
|
||||
box_sizer->Add(row, 1, wxEXPAND, 5);
|
||||
|
||||
|
||||
auto* tutorial_link = new wxHyperlinkCtrl(box, wxID_ANY, _("Online play tutorial"), "https://cemu.info/online-guide");
|
||||
box_sizer->Add(tutorial_link, 0, wxALL, 5);
|
||||
|
||||
@ -856,14 +858,14 @@ GeneralSettings2::GeneralSettings2(wxWindow* parent, bool game_launched)
|
||||
|
||||
notebook->AddPage(AddGeneralPage(notebook), _("General"));
|
||||
notebook->AddPage(AddGraphicsPage(notebook), _("Graphics"));
|
||||
notebook->AddPage(AddAudioPage(notebook), _("Audio"));
|
||||
notebook->AddPage(AddAudioPage(notebook), _("Audio"));
|
||||
notebook->AddPage(AddOverlayPage(notebook), _("Overlay"));
|
||||
notebook->AddPage(AddAccountPage(notebook), _("Account"));
|
||||
notebook->AddPage(AddDebugPage(notebook), _("Debug"));
|
||||
|
||||
Bind(wxEVT_CLOSE_WINDOW, &GeneralSettings2::OnClose, this);
|
||||
|
||||
//
|
||||
//
|
||||
|
||||
sizer->Add(notebook, 1, wxEXPAND | wxALL, 5);
|
||||
|
||||
@ -878,7 +880,7 @@ GeneralSettings2::GeneralSettings2(wxWindow* parent, bool game_launched)
|
||||
|
||||
ApplyConfig();
|
||||
HandleGraphicsApiSelection();
|
||||
|
||||
|
||||
DisableSettings(game_launched);
|
||||
}
|
||||
|
||||
@ -890,7 +892,7 @@ uint32 GeneralSettings2::GetSelectedAccountPersistentId()
|
||||
return dynamic_cast<wxAccountData*>(m_active_account->GetClientObject(active_account))->GetAccount().GetPersistentId();
|
||||
}
|
||||
|
||||
void GeneralSettings2::StoreConfig()
|
||||
void GeneralSettings2::StoreConfig()
|
||||
{
|
||||
auto* app = (CemuApp*)wxTheApp;
|
||||
auto& config = GetConfig();
|
||||
@ -908,7 +910,7 @@ void GeneralSettings2::StoreConfig()
|
||||
{
|
||||
ScreenSaver::SetInhibit(config.disable_screensaver);
|
||||
}
|
||||
|
||||
|
||||
// -1 is default wx widget value -> set to dummy 0 so mainwindow and padwindow will update it
|
||||
config.window_position = m_save_window_position_size->IsChecked() ? Vector2i{ 0,0 } : Vector2i{-1,-1};
|
||||
config.window_size = m_save_window_position_size->IsChecked() ? Vector2i{ 0,0 } : Vector2i{-1,-1};
|
||||
@ -951,7 +953,7 @@ void GeneralSettings2::StoreConfig()
|
||||
config.pad_channels = kStereo; // (AudioChannels)m_pad_channels->GetSelection();
|
||||
//config.input_channels = (AudioChannels)m_input_channels->GetSelection();
|
||||
config.input_channels = kMono; // (AudioChannels)m_input_channels->GetSelection();
|
||||
|
||||
|
||||
config.tv_volume = m_tv_volume->GetValue();
|
||||
config.pad_volume = m_pad_volume->GetValue();
|
||||
config.input_volume = m_input_volume->GetValue();
|
||||
@ -997,16 +999,16 @@ void GeneralSettings2::StoreConfig()
|
||||
}
|
||||
else
|
||||
config.graphic_device_uuid = {};
|
||||
|
||||
|
||||
|
||||
config.vsync = m_vsync->GetSelection();
|
||||
config.gx2drawdone_sync = m_gx2drawdone_sync->IsChecked();
|
||||
config.async_compile = m_async_compile->IsChecked();
|
||||
|
||||
|
||||
config.upscale_filter = m_upscale_filter->GetSelection();
|
||||
config.downscale_filter = m_downscale_filter->GetSelection();
|
||||
config.fullscreen_scaling = m_fullscreen_scaling->GetSelection();
|
||||
|
||||
|
||||
config.overlay.position = (ScreenPosition)m_overlay_position->GetSelection(); wxASSERT((int)config.overlay.position <= (int)ScreenPosition::kBottomRight);
|
||||
config.overlay.text_color = m_overlay_font_color->GetColour().GetRGBA();
|
||||
config.overlay.text_scale = m_overlay_scale->GetSelection() * 25 + 50;
|
||||
@ -1064,7 +1066,7 @@ void GeneralSettings2::ValidateConfig()
|
||||
|
||||
void GeneralSettings2::DisableSettings(bool game_launched)
|
||||
{
|
||||
|
||||
|
||||
}
|
||||
|
||||
void GeneralSettings2::OnAudioLatencyChanged(wxCommandEvent& event)
|
||||
@ -1075,7 +1077,7 @@ void GeneralSettings2::OnAudioLatencyChanged(wxCommandEvent& event)
|
||||
|
||||
void GeneralSettings2::OnVolumeChanged(wxCommandEvent& event)
|
||||
{
|
||||
|
||||
|
||||
if(event.GetEventObject() == m_input_volume)
|
||||
{
|
||||
std::shared_lock lock(g_audioInputMutex);
|
||||
@ -1099,7 +1101,7 @@ void GeneralSettings2::OnVolumeChanged(wxCommandEvent& event)
|
||||
g_tvAudio->SetVolume(event.GetInt());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
event.Skip();
|
||||
}
|
||||
@ -1112,7 +1114,7 @@ void GeneralSettings2::OnInputVolumeChanged(wxCommandEvent& event)
|
||||
g_padAudio->SetInputVolume(event.GetInt());
|
||||
g_padVolume = event.GetInt();
|
||||
}
|
||||
|
||||
|
||||
event.Skip();
|
||||
}
|
||||
|
||||
@ -1190,7 +1192,7 @@ void GeneralSettings2::UpdateAudioDeviceList()
|
||||
// todo reset global instance of audio device
|
||||
}
|
||||
|
||||
void GeneralSettings2::ResetAccountInformation()
|
||||
void GeneralSettings2::ResetAccountInformation()
|
||||
{
|
||||
m_account_grid->SetSplitterPosition(100);
|
||||
m_active_account->SetSelection(0);
|
||||
@ -1218,7 +1220,7 @@ void GeneralSettings2::OnAccountCreate(wxCommandEvent& event)
|
||||
Account account(dialog.GetPersistentId(), dialog.GetMiiName().ToStdWstring());
|
||||
account.Save();
|
||||
Account::RefreshAccounts();
|
||||
|
||||
|
||||
const int index = m_active_account->Append(account.ToString(), new wxAccountData(account));
|
||||
|
||||
// update ui
|
||||
@ -1227,7 +1229,7 @@ void GeneralSettings2::OnAccountCreate(wxCommandEvent& event)
|
||||
|
||||
m_create_account->Enable(m_active_account->GetCount() < 0xC);
|
||||
m_delete_account->Enable(m_active_account->GetCount() > 1);
|
||||
|
||||
|
||||
// send main window event
|
||||
wxASSERT(GetParent());
|
||||
wxCommandEvent refresh_event(wxEVT_ACCOUNTLIST_REFRESH);
|
||||
@ -1257,7 +1259,7 @@ void GeneralSettings2::OnAccountDelete(wxCommandEvent& event)
|
||||
return;
|
||||
|
||||
// todo: ask if saves should be deleted too?
|
||||
|
||||
|
||||
const fs::path path = account.GetFileName();
|
||||
try
|
||||
{
|
||||
@ -1275,7 +1277,7 @@ void GeneralSettings2::OnAccountDelete(wxCommandEvent& event)
|
||||
SystemException sys(ex);
|
||||
cemuLog_log(LogType::Force, sys.what());
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
void GeneralSettings2::OnAccountSettingsChanged(wxPropertyGridEvent& event)
|
||||
@ -1330,7 +1332,7 @@ void GeneralSettings2::OnAccountSettingsChanged(wxPropertyGridEvent& event)
|
||||
else if (property->GetName() == kPropertyEmail)
|
||||
{
|
||||
account.SetEmail(value.As<wxString>().ToStdString());
|
||||
|
||||
|
||||
}
|
||||
else if (property->GetName() == kPropertyCountry)
|
||||
{
|
||||
@ -1338,7 +1340,7 @@ void GeneralSettings2::OnAccountSettingsChanged(wxPropertyGridEvent& event)
|
||||
}
|
||||
else
|
||||
cemu_assert_debug(false);
|
||||
|
||||
|
||||
account.Save();
|
||||
Account::RefreshAccounts(); // refresh internal account list
|
||||
UpdateAccountInformation(); // refresh on invalid values
|
||||
@ -1378,7 +1380,7 @@ void GeneralSettings2::UpdateAccountInformation()
|
||||
gender_property->SetChoiceSelection(std::min(gender_property->GetChoices().GetCount() - 1, (uint32)account.GetGender()));
|
||||
|
||||
m_account_grid->GetProperty(kPropertyEmail)->SetValueFromString(std::string{ account.GetEmail() });
|
||||
|
||||
|
||||
auto* country_property = dynamic_cast<wxEnumProperty*>(m_account_grid->GetProperty(kPropertyCountry));
|
||||
wxASSERT(country_property);
|
||||
int index = (country_property)->GetIndexForValue(account.GetCountry());
|
||||
@ -1462,7 +1464,7 @@ void GeneralSettings2::HandleGraphicsApiSelection()
|
||||
int selection = m_vsync->GetSelection();
|
||||
if(selection == wxNOT_FOUND)
|
||||
selection = GetConfig().vsync;
|
||||
|
||||
|
||||
m_vsync->Clear();
|
||||
if(m_graphic_api->GetSelection() == 0)
|
||||
{
|
||||
@ -1494,7 +1496,7 @@ void GeneralSettings2::HandleGraphicsApiSelection()
|
||||
#endif
|
||||
|
||||
m_vsync->Select(selection);
|
||||
|
||||
|
||||
m_graphic_device->Enable();
|
||||
auto devices = VulkanRenderer::GetDevices();
|
||||
m_graphic_device->Clear();
|
||||
@ -1618,7 +1620,7 @@ void GeneralSettings2::ApplyConfig()
|
||||
m_pad_channels->SetSelection(0);
|
||||
//m_input_channels->SetSelection(config.pad_channels);
|
||||
m_input_channels->SetSelection(0);
|
||||
|
||||
|
||||
SendSliderEvent(m_tv_volume, config.tv_volume);
|
||||
|
||||
if (!config.tv_device.empty() && m_tv_device->HasClientObjectData())
|
||||
@ -1635,7 +1637,7 @@ void GeneralSettings2::ApplyConfig()
|
||||
}
|
||||
else
|
||||
m_tv_device->SetSelection(0);
|
||||
|
||||
|
||||
SendSliderEvent(m_pad_volume, config.pad_volume);
|
||||
if (!config.pad_device.empty() && m_pad_device->HasClientObjectData())
|
||||
{
|
||||
@ -1768,7 +1770,7 @@ void GeneralSettings2::UpdateAudioDevice()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// pad audio device
|
||||
{
|
||||
const auto selection = m_pad_device->GetSelection();
|
||||
@ -1884,14 +1886,14 @@ void GeneralSettings2::OnAudioChannelsSelected(wxCommandEvent& event)
|
||||
{
|
||||
if (config.tv_channels == (AudioChannels)obj->GetSelection())
|
||||
return;
|
||||
|
||||
|
||||
config.tv_channels = (AudioChannels)obj->GetSelection();
|
||||
}
|
||||
else if (obj == m_pad_channels)
|
||||
{
|
||||
if (config.pad_channels == (AudioChannels)obj->GetSelection())
|
||||
return;
|
||||
|
||||
|
||||
config.pad_channels = (AudioChannels)obj->GetSelection();
|
||||
}
|
||||
else
|
||||
@ -2034,23 +2036,23 @@ void GeneralSettings2::OnShowOnlineValidator(wxCommandEvent& event)
|
||||
const auto selection = m_active_account->GetSelection();
|
||||
if (selection == wxNOT_FOUND)
|
||||
return;
|
||||
|
||||
|
||||
const auto* obj = dynamic_cast<wxAccountData*>(m_active_account->GetClientObject(selection));
|
||||
wxASSERT(obj);
|
||||
const auto& account = obj->GetAccount();
|
||||
|
||||
|
||||
const auto validator = account.ValidateOnlineFiles();
|
||||
if (validator) // everything valid? shouldn't happen
|
||||
return;
|
||||
|
||||
|
||||
wxString err;
|
||||
err << _("The following error(s) have been found:") << '\n';
|
||||
|
||||
|
||||
if (validator.otp == OnlineValidator::FileState::Missing)
|
||||
err << _("otp.bin missing in Cemu directory") << '\n';
|
||||
else if(validator.otp == OnlineValidator::FileState::Corrupted)
|
||||
err << _("otp.bin is invalid") << '\n';
|
||||
|
||||
|
||||
if (validator.seeprom == OnlineValidator::FileState::Missing)
|
||||
err << _("seeprom.bin missing in Cemu directory") << '\n';
|
||||
else if(validator.seeprom == OnlineValidator::FileState::Corrupted)
|
||||
|
@ -21,7 +21,7 @@ LoggingWindow::LoggingWindow(wxFrame* parent)
|
||||
|
||||
filter_row->Add(new wxStaticText( this, wxID_ANY, _("Filter")), 0, wxALIGN_CENTER_VERTICAL|wxALL, 5 );
|
||||
|
||||
wxString choices[] = {"Unsupported APIs calls", "Coreinit Logging", "Coreinit File-Access", "Coreinit Thread-Synchronization", "Coreinit Memory", "Coreinit MP", "Coreinit Thread", "nn::nfp", "GX2", "Audio", "Input", "Socket", "Save", "H264", "Graphic pack patches", "Texture cache", "Texture readback", "OpenGL debug output", "Vulkan validation layer"};
|
||||
wxString choices[] = {"Unsupported APIs calls", "Coreinit Logging", "Coreinit File-Access", "Coreinit Thread-Synchronization", "Coreinit Memory", "Coreinit MP", "Coreinit Thread", "nn::nfp", "GX2", "Audio", "Input", "Socket", "Save", "H264", "Graphic pack patches", "Texture cache", "Texture readback", "OpenGL debug output", "Vulkan validation layer", "Metal debug output"};
|
||||
m_filter = new wxComboBox( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, std::size(choices), choices, 0 );
|
||||
m_filter->Bind(wxEVT_COMBOBOX, &LoggingWindow::OnFilterChange, this);
|
||||
m_filter->Bind(wxEVT_TEXT, &LoggingWindow::OnFilterChange, this);
|
||||
@ -83,7 +83,7 @@ void LoggingWindow::Log(std::string_view filter, std::wstring_view message)
|
||||
|
||||
void LoggingWindow::OnLogMessage(wxLogEvent& event)
|
||||
{
|
||||
m_log_list->PushEntry(event.GetFilter(), event.GetMessage());
|
||||
m_log_list->PushEntry(event.GetFilter(), event.GetMessage());
|
||||
}
|
||||
|
||||
void LoggingWindow::OnFilterChange(wxCommandEvent& event)
|
||||
@ -97,4 +97,3 @@ void LoggingWindow::OnFilterMessageChange(wxCommandEvent& event)
|
||||
m_log_list->SetFilterMessage(m_filter_message->GetValue());
|
||||
event.Skip();
|
||||
}
|
||||
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include "audio/audioDebuggerWindow.h"
|
||||
#include "gui/canvas/OpenGLCanvas.h"
|
||||
#include "gui/canvas/VulkanCanvas.h"
|
||||
#include "gui/canvas/MetalCanvas.h"
|
||||
#include "Cafe/OS/libs/nfc/nfc.h"
|
||||
#include "Cafe/OS/libs/swkbd/swkbd.h"
|
||||
#include "gui/debugger/DebuggerWindow2.h"
|
||||
@ -93,7 +94,7 @@ enum
|
||||
// options -> account
|
||||
MAINFRAME_MENU_ID_OPTIONS_ACCOUNT_1 = 20350,
|
||||
MAINFRAME_MENU_ID_OPTIONS_ACCOUNT_12 = 20350 + 11,
|
||||
|
||||
|
||||
// options -> system language
|
||||
MAINFRAME_MENU_ID_OPTIONS_LANGUAGE_JAPANESE = 20500,
|
||||
MAINFRAME_MENU_ID_OPTIONS_LANGUAGE_ENGLISH,
|
||||
@ -243,7 +244,7 @@ public:
|
||||
{
|
||||
if(!m_window->IsGameLaunched() && filenames.GetCount() == 1)
|
||||
return m_window->FileLoad(_utf8ToPath(filenames[0].utf8_string()), wxLaunchGameEvent::INITIATED_BY::DRAG_AND_DROP);
|
||||
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -455,7 +456,7 @@ bool MainWindow::InstallUpdate(const fs::path& metaFilePath)
|
||||
{
|
||||
throw std::runtime_error(frame.GetExceptionMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch(const AbortException&)
|
||||
{
|
||||
@ -639,13 +640,13 @@ void MainWindow::OnFileMenu(wxCommandEvent& event)
|
||||
_("Wii U executable (*.rpx, *.elf)"),
|
||||
_("All files (*.*)")
|
||||
);
|
||||
|
||||
|
||||
wxFileDialog openFileDialog(this, _("Open file to launch"), wxEmptyString, wxEmptyString, wildcard, wxFD_OPEN | wxFD_FILE_MUST_EXIST);
|
||||
|
||||
if (openFileDialog.ShowModal() == wxID_CANCEL || openFileDialog.GetPath().IsEmpty())
|
||||
return;
|
||||
|
||||
const wxString wxStrFilePath = openFileDialog.GetPath();
|
||||
const wxString wxStrFilePath = openFileDialog.GetPath();
|
||||
FileLoad(_utf8ToPath(wxStrFilePath.utf8_string()), wxLaunchGameEvent::INITIATED_BY::MENU);
|
||||
}
|
||||
else if (menuId >= MAINFRAME_MENU_ID_FILE_RECENT_0 && menuId <= MAINFRAME_MENU_ID_FILE_RECENT_LAST)
|
||||
@ -784,7 +785,7 @@ void MainWindow::TogglePadView()
|
||||
{
|
||||
if (m_padView)
|
||||
return;
|
||||
|
||||
|
||||
m_padView = new PadViewFrame(this);
|
||||
|
||||
m_padView->Bind(wxEVT_CLOSE_WINDOW, &MainWindow::OnPadClose, this);
|
||||
@ -992,7 +993,7 @@ void MainWindow::OnConsoleLanguage(wxCommandEvent& event)
|
||||
// GetConfig().cpu_mode = CPUMode::TriplecoreRecompiler;
|
||||
// else
|
||||
// cemu_assert_debug(false);
|
||||
//
|
||||
//
|
||||
// g_config.Save();
|
||||
//}
|
||||
|
||||
@ -1056,7 +1057,7 @@ void MainWindow::OnDebugSetting(wxCommandEvent& event)
|
||||
ActiveSettings::SetTimerShiftFactor(6);
|
||||
else
|
||||
cemu_assert_debug(false);
|
||||
|
||||
|
||||
g_config.Save();
|
||||
}
|
||||
|
||||
@ -1132,7 +1133,7 @@ void MainWindow::OnLoggingWindow(wxCommandEvent& event)
|
||||
return;
|
||||
|
||||
m_logging_window = new LoggingWindow(this);
|
||||
m_logging_window->Bind(wxEVT_CLOSE_WINDOW,
|
||||
m_logging_window->Bind(wxEVT_CLOSE_WINDOW,
|
||||
[this](wxCloseEvent& event) {
|
||||
m_logging_window = nullptr;
|
||||
event.Skip();
|
||||
@ -1307,7 +1308,7 @@ void MainWindow::SaveSettings()
|
||||
{
|
||||
auto lock = g_config.Lock();
|
||||
auto& config = GetConfig();
|
||||
|
||||
|
||||
if (config.window_position != Vector2i{ -1,-1 })
|
||||
{
|
||||
config.window_position.x = m_restored_position.x;
|
||||
@ -1344,7 +1345,7 @@ void MainWindow::SaveSettings()
|
||||
|
||||
if(m_game_list)
|
||||
m_game_list->SaveConfig();
|
||||
|
||||
|
||||
g_config.Save();
|
||||
}
|
||||
|
||||
@ -1374,14 +1375,14 @@ void MainWindow::OnMouseMove(wxMouseEvent& event)
|
||||
void MainWindow::OnMouseLeft(wxMouseEvent& event)
|
||||
{
|
||||
auto& instance = InputManager::instance();
|
||||
|
||||
|
||||
std::scoped_lock lock(instance.m_main_mouse.m_mutex);
|
||||
instance.m_main_mouse.left_down = event.ButtonDown(wxMOUSE_BTN_LEFT);
|
||||
auto physPos = ToPhys(event.GetPosition());
|
||||
instance.m_main_mouse.position = { physPos.x, physPos.y };
|
||||
if (event.ButtonDown(wxMOUSE_BTN_LEFT))
|
||||
instance.m_main_mouse.left_down_toggle = true;
|
||||
|
||||
|
||||
event.Skip();
|
||||
}
|
||||
|
||||
@ -1395,7 +1396,7 @@ void MainWindow::OnMouseRight(wxMouseEvent& event)
|
||||
instance.m_main_mouse.position = { physPos.x, physPos.y };
|
||||
if(event.ButtonDown(wxMOUSE_BTN_RIGHT))
|
||||
instance.m_main_mouse.right_down_toggle = true;
|
||||
|
||||
|
||||
event.Skip();
|
||||
}
|
||||
|
||||
@ -1443,7 +1444,7 @@ void MainWindow::OnKeyUp(wxKeyEvent& event)
|
||||
|
||||
void MainWindow::OnKeyDown(wxKeyEvent& event)
|
||||
{
|
||||
if ((event.AltDown() && event.GetKeyCode() == WXK_F4) ||
|
||||
if ((event.AltDown() && event.GetKeyCode() == WXK_F4) ||
|
||||
(event.CmdDown() && event.GetKeyCode() == 'Q'))
|
||||
{
|
||||
Close(true);
|
||||
@ -1458,7 +1459,7 @@ void MainWindow::OnChar(wxKeyEvent& event)
|
||||
{
|
||||
if (swkbd_hasKeyboardInputHook())
|
||||
swkbd_keyInput(event.GetUnicodeKey());
|
||||
|
||||
|
||||
// event.Skip();
|
||||
}
|
||||
|
||||
@ -1483,7 +1484,7 @@ void MainWindow::OnToolsInput(wxCommandEvent& event)
|
||||
case MAINFRAME_MENU_ID_TOOLS_DOWNLOAD_MANAGER:
|
||||
{
|
||||
const auto default_tab = id == MAINFRAME_MENU_ID_TOOLS_TITLE_MANAGER ? TitleManagerPage::TitleManager : TitleManagerPage::DownloadManager;
|
||||
|
||||
|
||||
if (m_title_manager)
|
||||
m_title_manager->SetFocusAndTab(default_tab);
|
||||
else
|
||||
@ -1533,7 +1534,7 @@ void MainWindow::OnGesturePan(wxPanGestureEvent& event)
|
||||
instance.m_main_touch.left_down = event.IsGestureStart() || !event.IsGestureEnd();
|
||||
if (event.IsGestureStart() || !event.IsGestureEnd())
|
||||
instance.m_main_touch.left_down_toggle = true;
|
||||
|
||||
|
||||
|
||||
event.Skip();
|
||||
}
|
||||
@ -1567,8 +1568,10 @@ void MainWindow::CreateCanvas()
|
||||
// create canvas
|
||||
if (ActiveSettings::GetGraphicsAPI() == kVulkan)
|
||||
m_render_canvas = new VulkanCanvas(m_game_panel, wxSize(1280, 720), true);
|
||||
else
|
||||
else if (ActiveSettings::GetGraphicsAPI() == kOpenGL)
|
||||
m_render_canvas = GLCanvas_Create(m_game_panel, wxSize(1280, 720), true);
|
||||
else
|
||||
m_render_canvas = new MetalCanvas(m_game_panel, wxSize(1280, 720), true);
|
||||
|
||||
// mouse events
|
||||
m_render_canvas->Bind(wxEVT_MOTION, &MainWindow::OnMouseMove, this);
|
||||
@ -1748,10 +1751,10 @@ void MainWindow::UpdateNFCMenu()
|
||||
const auto& entry = config.recent_nfc_files[i];
|
||||
if (entry.empty())
|
||||
continue;
|
||||
|
||||
|
||||
if (!fs::exists(_utf8ToPath(entry)))
|
||||
continue;
|
||||
|
||||
|
||||
if (recentFileIndex == 0)
|
||||
m_nfcMenuSeparator0 = m_nfcMenu->AppendSeparator();
|
||||
|
||||
@ -1802,7 +1805,7 @@ void MainWindow::OnTimer(wxTimerEvent& event)
|
||||
{
|
||||
ShowCursor(false);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
#define BUILD_DATE __DATE__ " " __TIME__
|
||||
@ -2061,9 +2064,9 @@ void MainWindow::RecreateMenu()
|
||||
m_menuBar->Destroy();
|
||||
m_menuBar = nullptr;
|
||||
}
|
||||
|
||||
|
||||
auto& config = GetConfig();
|
||||
|
||||
|
||||
m_menuBar = new wxMenuBar();
|
||||
// file submenu
|
||||
m_fileMenu = new wxMenu();
|
||||
@ -2115,7 +2118,7 @@ void MainWindow::RecreateMenu()
|
||||
item->Check(account_id == account.GetPersistentId());
|
||||
if (m_game_launched || LaunchSettings::GetPersistentId().has_value())
|
||||
item->Enable(false);
|
||||
|
||||
|
||||
++index;
|
||||
}
|
||||
|
||||
@ -2145,8 +2148,8 @@ void MainWindow::RecreateMenu()
|
||||
// options submenu
|
||||
wxMenu* optionsMenu = new wxMenu();
|
||||
m_fullscreenMenuItem = optionsMenu->AppendCheckItem(MAINFRAME_MENU_ID_OPTIONS_FULLSCREEN, _("&Fullscreen"), wxEmptyString);
|
||||
m_fullscreenMenuItem->Check(ActiveSettings::FullscreenEnabled());
|
||||
|
||||
m_fullscreenMenuItem->Check(ActiveSettings::FullscreenEnabled());
|
||||
|
||||
optionsMenu->Append(MAINFRAME_MENU_ID_OPTIONS_GRAPHIC_PACKS2, _("&Graphic packs"));
|
||||
m_padViewMenuItem = optionsMenu->AppendCheckItem(MAINFRAME_MENU_ID_OPTIONS_SECOND_WINDOW_PADVIEW, _("&Separate GamePad view"), wxEmptyString);
|
||||
m_padViewMenuItem->Check(GetConfig().pad_open);
|
||||
@ -2227,6 +2230,7 @@ void MainWindow::RecreateMenu()
|
||||
debugLoggingMenu->AppendSeparator();
|
||||
debugLoggingMenu->AppendCheckItem(MAINFRAME_MENU_ID_DEBUG_LOGGING0 + stdx::to_underlying(LogType::OpenGLLogging), _("&OpenGL debug output"), wxEmptyString)->Check(cemuLog_isLoggingEnabled(LogType::OpenGLLogging));
|
||||
debugLoggingMenu->AppendCheckItem(MAINFRAME_MENU_ID_DEBUG_LOGGING0 + stdx::to_underlying(LogType::VulkanValidation), _("&Vulkan validation layer (slow)"), wxEmptyString)->Check(cemuLog_isLoggingEnabled(LogType::VulkanValidation));
|
||||
debugLoggingMenu->AppendCheckItem(MAINFRAME_MENU_ID_DEBUG_LOGGING0 + stdx::to_underlying(LogType::MetalLogging), _("&Metal debug output"), wxEmptyString)->Check(cemuLog_isLoggingEnabled(LogType::MetalLogging));
|
||||
debugLoggingMenu->AppendCheckItem(MAINFRAME_MENU_ID_DEBUG_ADVANCED_PPC_INFO, _("&Log PPC context for API"), wxEmptyString)->Check(cemuLog_advancedPPCLoggingEnabled());
|
||||
m_loggingSubmenu = debugLoggingMenu;
|
||||
// debug->dump submenu
|
||||
@ -2240,7 +2244,7 @@ void MainWindow::RecreateMenu()
|
||||
debugMenu->AppendSubMenu(debugLoggingMenu, _("&Logging"));
|
||||
debugMenu->AppendSubMenu(debugDumpMenu, _("&Dump"));
|
||||
debugMenu->AppendSeparator();
|
||||
|
||||
|
||||
auto upsidedownItem = debugMenu->AppendCheckItem(MAINFRAME_MENU_ID_DEBUG_RENDER_UPSIDE_DOWN, _("&Render upside-down"), wxEmptyString);
|
||||
upsidedownItem->Check(ActiveSettings::RenderUpsideDownEnabled());
|
||||
if(LaunchSettings::RenderUpsideDownEnabled().has_value())
|
||||
@ -2296,6 +2300,7 @@ void MainWindow::RecreateMenu()
|
||||
// these options cant be toggled after the renderer backend is initialized:
|
||||
m_loggingSubmenu->Enable(MAINFRAME_MENU_ID_DEBUG_LOGGING0 + stdx::to_underlying(LogType::OpenGLLogging), false);
|
||||
m_loggingSubmenu->Enable(MAINFRAME_MENU_ID_DEBUG_LOGGING0 + stdx::to_underlying(LogType::VulkanValidation), false);
|
||||
m_loggingSubmenu->Enable(MAINFRAME_MENU_ID_DEBUG_LOGGING0 + stdx::to_underlying(LogType::MetalLogging), false);
|
||||
|
||||
UpdateNFCMenu();
|
||||
}
|
||||
|
@ -8,6 +8,7 @@
|
||||
#include "Cafe/OS/libs/swkbd/swkbd.h"
|
||||
#include "gui/canvas/OpenGLCanvas.h"
|
||||
#include "gui/canvas/VulkanCanvas.h"
|
||||
#include "gui/canvas/MetalCanvas.h"
|
||||
#include "config/CemuConfig.h"
|
||||
#include "gui/MainWindow.h"
|
||||
#include "gui/helpers/wxHelpers.h"
|
||||
@ -74,8 +75,10 @@ void PadViewFrame::InitializeRenderCanvas()
|
||||
{
|
||||
if (ActiveSettings::GetGraphicsAPI() == kVulkan)
|
||||
m_render_canvas = new VulkanCanvas(this, wxSize(854, 480), false);
|
||||
else
|
||||
else if (ActiveSettings::GetGraphicsAPI() == kOpenGL)
|
||||
m_render_canvas = GLCanvas_Create(this, wxSize(854, 480), false);
|
||||
else
|
||||
m_render_canvas = new MetalCanvas(this, wxSize(854, 480), false);
|
||||
sizer->Add(m_render_canvas, 1, wxEXPAND, 0, nullptr);
|
||||
}
|
||||
SetSizer(sizer);
|
||||
@ -173,7 +176,7 @@ void PadViewFrame::OnChar(wxKeyEvent& event)
|
||||
{
|
||||
if (swkbd_hasKeyboardInputHook())
|
||||
swkbd_keyInput(event.GetUnicodeKey());
|
||||
|
||||
|
||||
event.Skip();
|
||||
}
|
||||
|
||||
@ -198,7 +201,7 @@ void PadViewFrame::OnMouseLeft(wxMouseEvent& event)
|
||||
instance.m_pad_mouse.position = { physPos.x, physPos.y };
|
||||
if (event.ButtonDown(wxMOUSE_BTN_LEFT))
|
||||
instance.m_pad_mouse.left_down_toggle = true;
|
||||
|
||||
|
||||
}
|
||||
|
||||
void PadViewFrame::OnMouseRight(wxMouseEvent& event)
|
||||
|
63
src/gui/canvas/MetalCanvas.cpp
Normal file
63
src/gui/canvas/MetalCanvas.cpp
Normal file
@ -0,0 +1,63 @@
|
||||
#include "gui/canvas/MetalCanvas.h"
|
||||
#include "Cafe/HW/Latte/Renderer/Metal/MetalRenderer.h"
|
||||
#include "gui/guiWrapper.h"
|
||||
|
||||
#include <wx/msgdlg.h>
|
||||
#include <helpers/wxHelpers.h>
|
||||
|
||||
MetalCanvas::MetalCanvas(wxWindow* parent, const wxSize& size, bool is_main_window)
|
||||
: IRenderCanvas(is_main_window), wxWindow(parent, wxID_ANY, wxDefaultPosition, size, wxNO_FULL_REPAINT_ON_RESIZE | wxWANTS_CHARS)
|
||||
{
|
||||
Bind(wxEVT_PAINT, &MetalCanvas::OnPaint, this);
|
||||
Bind(wxEVT_SIZE, &MetalCanvas::OnResize, this);
|
||||
|
||||
WindowHandleInfo& canvas = is_main_window ? gui_getWindowInfo().canvas_main : gui_getWindowInfo().canvas_pad;
|
||||
gui_initHandleContextFromWxWidgetsWindow(canvas, this);
|
||||
|
||||
try
|
||||
{
|
||||
if (is_main_window)
|
||||
g_renderer = std::make_unique<MetalRenderer>();
|
||||
|
||||
auto metal_renderer = MetalRenderer::GetInstance();
|
||||
metal_renderer->InitializeLayer({size.x, size.y}, is_main_window);
|
||||
}
|
||||
catch(const std::exception& ex)
|
||||
{
|
||||
cemuLog_log(LogType::Force, "Error when initializing Metal renderer: {}", ex.what());
|
||||
auto msg = formatWxString(_("Error when initializing Metal renderer:\n{}"), ex.what());
|
||||
wxMessageDialog dialog(this, msg, _("Error"), wxOK | wxCENTRE | wxICON_ERROR);
|
||||
dialog.ShowModal();
|
||||
exit(0);
|
||||
}
|
||||
|
||||
wxWindow::EnableTouchEvents(wxTOUCH_PAN_GESTURES);
|
||||
}
|
||||
|
||||
MetalCanvas::~MetalCanvas()
|
||||
{
|
||||
Unbind(wxEVT_PAINT, &MetalCanvas::OnPaint, this);
|
||||
Unbind(wxEVT_SIZE, &MetalCanvas::OnResize, this);
|
||||
|
||||
if(!m_is_main_window)
|
||||
{
|
||||
// TODO
|
||||
//MetalRenderer* vkr = (MetalRenderer*)g_renderer.get();
|
||||
//if(vkr)
|
||||
// vkr->StopUsingPadAndWait();
|
||||
}
|
||||
}
|
||||
|
||||
void MetalCanvas::OnPaint(wxPaintEvent& event)
|
||||
{
|
||||
}
|
||||
|
||||
void MetalCanvas::OnResize(wxSizeEvent& event)
|
||||
{
|
||||
const wxSize size = GetSize();
|
||||
if (size.GetWidth() == 0 || size.GetHeight() == 0)
|
||||
return;
|
||||
|
||||
const wxRect refreshRect(size);
|
||||
RefreshRect(refreshRect, false);
|
||||
}
|
19
src/gui/canvas/MetalCanvas.h
Normal file
19
src/gui/canvas/MetalCanvas.h
Normal file
@ -0,0 +1,19 @@
|
||||
#pragma once
|
||||
|
||||
#include "gui/canvas/IRenderCanvas.h"
|
||||
|
||||
#include <wx/frame.h>
|
||||
|
||||
#include <set>
|
||||
|
||||
class MetalCanvas : public IRenderCanvas, public wxWindow
|
||||
{
|
||||
public:
|
||||
MetalCanvas(wxWindow* parent, const wxSize& size, bool is_main_window);
|
||||
~MetalCanvas();
|
||||
|
||||
private:
|
||||
|
||||
void OnPaint(wxPaintEvent& event);
|
||||
void OnResize(wxSizeEvent& event);
|
||||
};
|
@ -82,11 +82,14 @@ void gui_updateWindowTitles(bool isIdle, bool isLoading, double fps)
|
||||
case RendererAPI::OpenGL:
|
||||
renderer = "[OpenGL]";
|
||||
break;
|
||||
case RendererAPI::Vulkan:
|
||||
case RendererAPI::Vulkan:
|
||||
renderer = "[Vulkan]";
|
||||
break;
|
||||
case RendererAPI::Metal:
|
||||
renderer = "[Metal]";
|
||||
break;
|
||||
default: ;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// get GPU vendor/mode
|
||||
@ -217,7 +220,7 @@ void gui_initHandleContextFromWxWidgetsWindow(WindowHandleInfo& handleInfoOut, c
|
||||
cemuLog_log(LogType::Force, "Unable to get xlib display");
|
||||
}
|
||||
}
|
||||
else
|
||||
else
|
||||
#ifdef HAS_WAYLAND
|
||||
if(GDK_IS_WAYLAND_WINDOW(gdkWindow))
|
||||
{
|
||||
|
@ -7,6 +7,8 @@ add_library(imguiImpl
|
||||
imgui_extension.h
|
||||
)
|
||||
|
||||
# TODO: add Metal
|
||||
|
||||
set_property(TARGET imguiImpl PROPERTY MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")
|
||||
|
||||
target_include_directories(imguiImpl PUBLIC "../")
|
||||
|
Loading…
Reference in New Issue
Block a user