This commit is contained in:
Emma 2026-04-23 17:07:26 +00:00 committed by GitHub
commit 1d4675a4b5
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
49 changed files with 875 additions and 506 deletions

View File

@ -244,7 +244,7 @@ Example usage: `cmake -S . -B build -DCMAKE_BUILD_TYPE=release -DENABLE_SDL=ON -
| CEMU_CXX_FLAGS | | Flags passed straight to the compiler, e.g. `-march=native`, `-Wall`, `/W3` | "" | |
| ENABLE_CUBEB | | Enable cubeb audio backend | ON | |
| ENABLE_DISCORD_RPC | | Enable Discord Rich presence support | ON | |
| ENABLE_OPENGL | | Enable OpenGL graphics backend | ON | Currently required |
| ENABLE_OPENGL | | Enable OpenGL graphics backend | ON | |
| ENABLE_HIDAPI | | Enable HIDAPI (used for Wiimote controller API) | ON | |
| ENABLE_SDL | | Enable SDLController controller API | ON | Currently required |
| ENABLE_VCPKG | | Use VCPKG package manager to obtain dependencies | ON | |

View File

@ -110,11 +110,13 @@ endif()
if (APPLE)
set(ENABLE_METAL_DEFAULT ON)
set(ENABLE_OPENGL_DEFAULT OFF)
else()
set(ENABLE_METAL_DEFAULT OFF)
set(ENABLE_OPENGL_DEFAULT ON)
endif()
option(ENABLE_OPENGL "Enables the OpenGL backend" ON)
option(ENABLE_OPENGL "Enables the OpenGL backend" ${ENABLE_OPENGL_DEFAULT})
option(ENABLE_VULKAN "Enables the Vulkan backend" ON)
option(ENABLE_METAL "Enables the Metal backend" ${ENABLE_METAL_DEFAULT})
option(ENABLE_DISCORD_RPC "Enables the Discord Rich Presence feature" ON)
@ -189,16 +191,18 @@ endif()
if (ENABLE_VULKAN)
include_directories("dependencies/Vulkan-Headers/include")
add_compile_definitions(ENABLE_VULKAN)
endif()
if (ENABLE_OPENGL)
find_package(OpenGL REQUIRED)
add_compile_definitions(ENABLE_OPENGL)
endif()
if (ENABLE_METAL)
include_directories(${CMAKE_SOURCE_DIR}/dependencies/metal-cpp)
add_definitions(-DENABLE_METAL=1)
add_compile_definitions(ENABLE_METAL)
endif()
if (ENABLE_DISCORD_RPC)

View File

@ -13,18 +13,24 @@ if(MSVC)
add_compile_definitions(WIN32_LEAN_AND_MEAN CURL_STATICLIB)
elseif(UNIX)
if(APPLE)
add_compile_definitions(
_XOPEN_SOURCE
VK_USE_PLATFORM_MACOS_MVK
VK_USE_PLATFORM_METAL_EXT
)
if (ENABLE_VULKAN)
add_compile_definitions(
_XOPEN_SOURCE
VK_USE_PLATFORM_MACOS_MVK
VK_USE_PLATFORM_METAL_EXT
)
else()
add_compile_definitions(_XOPEN_SOURCE)
endif()
else()
add_compile_definitions(
VK_USE_PLATFORM_XLIB_KHR # legacy. Do we need to support XLIB surfaces?
VK_USE_PLATFORM_XCB_KHR
)
if (ENABLE_WAYLAND)
add_compile_definitions(VK_USE_PLATFORM_WAYLAND_KHR)
if (ENABLE_VULKAN)
add_compile_definitions(
VK_USE_PLATFORM_XLIB_KHR # legacy. Do we need to support XLIB surfaces?
VK_USE_PLATFORM_XCB_KHR
)
if (ENABLE_WAYLAND)
add_compile_definitions(VK_USE_PLATFORM_WAYLAND_KHR)
endif()
endif()
endif()
# warnings
@ -35,7 +41,9 @@ elseif(UNIX)
add_compile_options(-Wno-multichar -Wno-invalid-offsetof -Wno-switch -Wno-ignored-attributes -Wno-deprecated-enum-enum-conversion)
endif()
add_compile_definitions(VK_NO_PROTOTYPES)
if (ENABLE_VULKAN)
add_compile_definitions(VK_NO_PROTOTYPES)
endif()
set(CMAKE_INCLUDE_CURRENT_DIR ON)
@ -119,29 +127,27 @@ if (MACOS_BUNDLE)
COMMAND ${CMAKE_COMMAND} ARGS -E copy_directory "${CMAKE_SOURCE_DIR}/bin/${folder}" "$<TARGET_BUNDLE_DIR:CemuBin>/Contents/SharedSupport/${folder}")
endforeach(folder)
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
set(LIBUSB_PATH "${CMAKE_BINARY_DIR}/vcpkg_installed/${VCPKG_TARGET_TRIPLET}/debug/lib/libusb-1.0.0.dylib")
else()
set(LIBUSB_PATH "${CMAKE_BINARY_DIR}/vcpkg_installed/${VCPKG_TARGET_TRIPLET}/lib/libusb-1.0.0.dylib")
endif()
if (ENABLE_VULKAN)
if (EXISTS "/usr/local/lib/libMoltenVK.dylib")
set(MOLTENVK_PATH "/usr/local/lib/libMoltenVK.dylib")
elseif (EXISTS "/opt/homebrew/lib/libMoltenVK.dylib")
set(MOLTENVK_PATH "/opt/homebrew/lib/libMoltenVK.dylib")
else()
message(FATAL_ERROR "failed to find libMoltenVK.dylib")
endif ()
endif()
if (EXISTS "/usr/local/lib/libMoltenVK.dylib")
set(MOLTENVK_PATH "/usr/local/lib/libMoltenVK.dylib")
elseif (EXISTS "/opt/homebrew/lib/libMoltenVK.dylib")
set(MOLTENVK_PATH "/opt/homebrew/lib/libMoltenVK.dylib")
else()
message(FATAL_ERROR "failed to find libMoltenVK.dylib")
endif ()
set(UPDATE_SH_PATH "${CMAKE_SOURCE_DIR}/src/resource/update.sh")
set(APP_BUNDLE_DIR "$<TARGET_BUNDLE_DIR:CemuBin>")
set(FRAMEWORKS_DIR "${APP_BUNDLE_DIR}/Contents/Frameworks")
set(RESOURCES_DIR "${APP_BUNDLE_DIR}/Contents/Resources")
add_custom_command(TARGET CemuBin POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy
"${MOLTENVK_PATH}"
"${FRAMEWORKS_DIR}/libMoltenVK.dylib"
if (ENABLE_VULKAN)
COMMAND ${CMAKE_COMMAND} -E copy
"${MOLTENVK_PATH}"
"${FRAMEWORKS_DIR}/libMoltenVK.dylib"
endif()
COMMAND ${CMAKE_COMMAND} -E copy
"${LIBUSB_PATH}"
"${FRAMEWORKS_DIR}/libusb-1.0.0.dylib"
@ -165,20 +171,22 @@ if (MACOS_BUNDLE)
)
else()
if(APPLE)
find_library(MOLTENVK_LIBRARY
NAMES MoltenVK moltenvk libMoltenVK.dylib
PATHS /usr/local/lib /opt/homebrew/lib
)
if(MOLTENVK_LIBRARY)
message(STATUS "Found MoltenVK: ${MOLTENVK_LIBRARY}")
target_link_libraries(CemuBin PRIVATE ${MOLTENVK_LIBRARY})
else()
message(WARNING "libMoltenVK.dylib not found")
endif()
set_target_properties(CemuBin PROPERTIES
BUILD_WITH_INSTALL_RPATH TRUE
INSTALL_RPATH "/usr/local/lib;/opt/homebrew/lib"
)
if (ENABLE_VULKAN)
find_library(MOLTENVK_LIBRARY
NAMES MoltenVK moltenvk libMoltenVK.dylib
PATHS /usr/local/lib /opt/homebrew/lib
)
if(MOLTENVK_LIBRARY)
message(STATUS "Found MoltenVK: ${MOLTENVK_LIBRARY}")
target_link_libraries(CemuBin PRIVATE ${MOLTENVK_LIBRARY})
else()
message(WARNING "libMoltenVK.dylib not found")
endif()
set_target_properties(CemuBin PROPERTIES
BUILD_WITH_INSTALL_RPATH TRUE
INSTALL_RPATH "/usr/local/lib;/opt/homebrew/lib"
)
endif()
endif()
endif()

View File

@ -106,8 +106,6 @@ add_library(CemuCafe
HW/Latte/Core/LatteCachedFBO.h
HW/Latte/Core/LatteCommandProcessor.cpp
HW/Latte/Core/LatteConst.h
HW/Latte/Core/LatteDefaultShaders.cpp
HW/Latte/Core/LatteDefaultShaders.h
HW/Latte/Core/LatteDraw.h
HW/Latte/Core/LatteGSCopyShaderParser.cpp
HW/Latte/Core/Latte.h
@ -127,7 +125,6 @@ add_library(CemuCafe
HW/Latte/Core/LatteShaderCache.cpp
HW/Latte/Core/LatteShaderCache.h
HW/Latte/Core/LatteShader.cpp
HW/Latte/Core/LatteShaderGL.cpp
HW/Latte/Core/LatteShader.h
HW/Latte/Core/LatteSoftware.cpp
HW/Latte/Core/LatteSoftware.h
@ -162,58 +159,14 @@ add_library(CemuCafe
HW/Latte/LegacyShaderDecompiler/LatteDecompilerInstructions.h
HW/Latte/LegacyShaderDecompiler/LatteDecompilerInternal.h
HW/Latte/LegacyShaderDecompiler/LatteDecompilerRegisterDataTypeTracker.cpp
HW/Latte/Renderer/OpenGL/CachedFBOGL.h
HW/Latte/Renderer/OpenGL/LatteTextureGL.cpp
HW/Latte/Renderer/OpenGL/LatteTextureGL.h
HW/Latte/Renderer/OpenGL/LatteTextureViewGL.cpp
HW/Latte/Renderer/OpenGL/LatteTextureViewGL.h
HW/Latte/Renderer/OpenGL/OpenGLQuery.cpp
HW/Latte/Renderer/OpenGL/OpenGLRendererCore.cpp
HW/Latte/Renderer/OpenGL/OpenGLRenderer.cpp
HW/Latte/Renderer/OpenGL/OpenGLRenderer.h
HW/Latte/Renderer/OpenGL/OpenGLRendererStreamout.cpp
HW/Latte/Renderer/OpenGL/OpenGLRendererUniformData.cpp
HW/Latte/Renderer/OpenGL/OpenGLSurfaceCopy.cpp
HW/Latte/Renderer/OpenGL/OpenGLTextureReadback.h
HW/Latte/Renderer/OpenGL/RendererShaderGL.cpp
HW/Latte/Renderer/OpenGL/RendererShaderGL.h
HW/Latte/Renderer/OpenGL/TextureReadbackGL.cpp
HW/Latte/Renderer/Renderer.cpp
HW/Latte/Renderer/Renderer.h
HW/Latte/Renderer/RendererCore.cpp
HW/Latte/Renderer/RendererCore.h
HW/Latte/Renderer/RendererOuputShader.cpp
HW/Latte/Renderer/RendererOuputShader.h
HW/Latte/Renderer/RendererShader.cpp
HW/Latte/Renderer/RendererShader.h
HW/Latte/Renderer/Vulkan/CachedFBOVk.cpp
HW/Latte/Renderer/Vulkan/CachedFBOVk.h
HW/Latte/Renderer/Vulkan/CocoaSurface.h
HW/Latte/Renderer/Vulkan/LatteTextureViewVk.cpp
HW/Latte/Renderer/Vulkan/LatteTextureViewVk.h
HW/Latte/Renderer/Vulkan/LatteTextureVk.cpp
HW/Latte/Renderer/Vulkan/LatteTextureVk.h
HW/Latte/Renderer/Vulkan/RendererShaderVk.cpp
HW/Latte/Renderer/Vulkan/RendererShaderVk.h
HW/Latte/Renderer/Vulkan/SwapchainInfoVk.cpp
HW/Latte/Renderer/Vulkan/SwapchainInfoVk.h
HW/Latte/Renderer/Vulkan/TextureReadbackVk.cpp
HW/Latte/Renderer/Vulkan/VKRBase.h
HW/Latte/Renderer/Vulkan/VKRMemoryManager.cpp
HW/Latte/Renderer/Vulkan/VKRMemoryManager.h
HW/Latte/Renderer/Vulkan/VKRPipelineInfo.cpp
HW/Latte/Renderer/Vulkan/VsyncDriver.cpp
HW/Latte/Renderer/Vulkan/VsyncDriver.h
HW/Latte/Renderer/Vulkan/VulkanAPI.cpp
HW/Latte/Renderer/Vulkan/VulkanAPI.h
HW/Latte/Renderer/Vulkan/VulkanPipelineCompiler.cpp
HW/Latte/Renderer/Vulkan/VulkanPipelineCompiler.h
HW/Latte/Renderer/Vulkan/VulkanPipelineStableCache.cpp
HW/Latte/Renderer/Vulkan/VulkanPipelineStableCache.h
HW/Latte/Renderer/Vulkan/VulkanQuery.cpp
HW/Latte/Renderer/Vulkan/VulkanRendererCore.cpp
HW/Latte/Renderer/Vulkan/VulkanRenderer.cpp
HW/Latte/Renderer/Vulkan/VulkanRenderer.h
HW/Latte/Renderer/Vulkan/VulkanSurfaceCopy.cpp
HW/Latte/Renderer/Vulkan/VulkanTextureReadback.h
HW/Latte/ShaderInfo/ShaderDescription.cpp
HW/Latte/ShaderInfo/ShaderInfo.h
HW/Latte/ShaderInfo/ShaderInstanceInfo.cpp
@ -539,12 +492,73 @@ add_library(CemuCafe
TitleList/TitleList.h
)
if (ENABLE_OPENGL)
target_sources(CemuCafe PRIVATE
HW/Latte/Renderer/OpenGL/CachedFBOGL.h
HW/Latte/Renderer/OpenGL/LatteShaderGL.cpp
HW/Latte/Renderer/OpenGL/LatteTextureGL.cpp
HW/Latte/Renderer/OpenGL/LatteTextureGL.h
HW/Latte/Renderer/OpenGL/LatteTextureViewGL.cpp
HW/Latte/Renderer/OpenGL/LatteTextureViewGL.h
HW/Latte/Renderer/OpenGL/OpenGLQuery.cpp
HW/Latte/Renderer/OpenGL/OpenGLRendererCore.cpp
HW/Latte/Renderer/OpenGL/OpenGLRenderer.cpp
HW/Latte/Renderer/OpenGL/OpenGLRenderer.h
HW/Latte/Renderer/OpenGL/OpenGLRendererStreamout.cpp
HW/Latte/Renderer/OpenGL/OpenGLRendererUniformData.cpp
HW/Latte/Renderer/OpenGL/OpenGLSurfaceCopy.cpp
HW/Latte/Renderer/OpenGL/OpenGLTextureReadback.h
HW/Latte/Renderer/OpenGL/RendererShaderGL.cpp
HW/Latte/Renderer/OpenGL/RendererShaderGL.h
HW/Latte/Renderer/OpenGL/TextureReadbackGL.cpp
)
endif()
if (ENABLE_VULKAN)
target_sources(CemuCafe PRIVATE
HW/Latte/Renderer/Vulkan/CachedFBOVk.cpp
HW/Latte/Renderer/Vulkan/CachedFBOVk.h
HW/Latte/Renderer/Vulkan/CocoaSurface.h
HW/Latte/Renderer/Vulkan/LatteTextureViewVk.cpp
HW/Latte/Renderer/Vulkan/LatteTextureViewVk.h
HW/Latte/Renderer/Vulkan/LatteTextureVk.cpp
HW/Latte/Renderer/Vulkan/LatteTextureVk.h
HW/Latte/Renderer/Vulkan/RendererShaderVk.cpp
HW/Latte/Renderer/Vulkan/RendererShaderVk.h
HW/Latte/Renderer/Vulkan/SwapchainInfoVk.cpp
HW/Latte/Renderer/Vulkan/SwapchainInfoVk.h
HW/Latte/Renderer/Vulkan/TextureReadbackVk.cpp
HW/Latte/Renderer/Vulkan/VKRBase.h
HW/Latte/Renderer/Vulkan/VKRMemoryManager.cpp
HW/Latte/Renderer/Vulkan/VKRMemoryManager.h
HW/Latte/Renderer/Vulkan/VKRPipelineInfo.cpp
HW/Latte/Renderer/Vulkan/VsyncDriver.cpp
HW/Latte/Renderer/Vulkan/VsyncDriver.h
HW/Latte/Renderer/Vulkan/VulkanAPI.cpp
HW/Latte/Renderer/Vulkan/VulkanAPI.h
HW/Latte/Renderer/Vulkan/VulkanPipelineCompiler.cpp
HW/Latte/Renderer/Vulkan/VulkanPipelineCompiler.h
HW/Latte/Renderer/Vulkan/VulkanPipelineStableCache.cpp
HW/Latte/Renderer/Vulkan/VulkanPipelineStableCache.h
HW/Latte/Renderer/Vulkan/VulkanQuery.cpp
HW/Latte/Renderer/Vulkan/VulkanRendererCore.cpp
HW/Latte/Renderer/Vulkan/VulkanRenderer.cpp
HW/Latte/Renderer/Vulkan/VulkanRenderer.h
HW/Latte/Renderer/Vulkan/VulkanSurfaceCopy.cpp
HW/Latte/Renderer/Vulkan/VulkanTextureReadback.h
)
endif()
if(APPLE)
target_sources(CemuCafe PRIVATE
HW/Latte/Renderer/Vulkan/CocoaSurface.mm
HW/Latte/Renderer/MetalView.mm
HW/Latte/Renderer/MetalView.h
)
if (ENABLE_VULKAN)
target_sources(CemuCafe PRIVATE
HW/Latte/Renderer/Vulkan/CocoaSurface.mm
)
endif()
endif()
if(ENABLE_METAL)

View File

@ -251,7 +251,7 @@ void InfoLog_PrintActiveSettings()
if (!GetConfig().vk_accurate_barriers.GetValue())
cemuLog_log(LogType::Force, "Accurate barriers are disabled!");
}
#if ENABLE_METAL
#ifdef ENABLE_METAL
else if (ActiveSettings::GetGraphicsAPI() == GraphicAPI::kMetal)
{
cemuLog_log(LogType::Force, "Async compile: {}", GetConfig().async_compile.GetValue() ? "true" : "false");

View File

@ -226,7 +226,7 @@ bool GameProfile::Load(uint64_t title_id)
m_graphics_api = (GraphicAPI)graphicsApi.value;
gameProfile_loadEnumOption(iniParser, "accurateShaderMul", m_accurateShaderMul);
#if ENABLE_METAL
#ifdef ENABLE_METAL
gameProfile_loadBooleanOption2(iniParser, "shaderFastMath", m_shaderFastMath);
gameProfile_loadEnumOption(iniParser, "metalBufferCacheMode2", m_metalBufferCacheMode);
gameProfile_loadEnumOption(iniParser, "positionInvariance2", m_positionInvariance);
@ -311,7 +311,7 @@ void GameProfile::Save(uint64_t title_id)
fs->writeLine("[Graphics]");
WRITE_ENTRY(accurateShaderMul);
#if ENABLE_METAL
#ifdef ENABLE_METAL
WRITE_ENTRY(shaderFastMath);
WRITE_ENTRY_NUMBERED(metalBufferCacheMode, 2);
WRITE_ENTRY_NUMBERED(positionInvariance, 2);
@ -346,7 +346,7 @@ void GameProfile::ResetOptional()
// graphic settings
m_accurateShaderMul = AccurateShaderMulOption::True;
#if ENABLE_METAL
#ifdef ENABLE_METAL
m_shaderFastMath = true;
m_metalBufferCacheMode = MetalBufferCacheMode::Auto;
m_positionInvariance = PositionInvariance::Auto;
@ -371,7 +371,7 @@ void GameProfile::Reset()
// graphic settings
m_accurateShaderMul = AccurateShaderMulOption::True;
#if ENABLE_METAL
#ifdef ENABLE_METAL
m_shaderFastMath = true;
m_metalBufferCacheMode = MetalBufferCacheMode::Auto;
m_positionInvariance = PositionInvariance::Auto;

View File

@ -29,7 +29,7 @@ public:
[[nodiscard]] const std::optional<GraphicAPI>& GetGraphicsAPI() const { return m_graphics_api; }
[[nodiscard]] const AccurateShaderMulOption& GetAccurateShaderMul() const { return m_accurateShaderMul; }
#if ENABLE_METAL
#ifdef ENABLE_METAL
[[nodiscard]] bool GetShaderFastMath() const { return m_shaderFastMath; }
[[nodiscard]] MetalBufferCacheMode GetBufferCacheMode() const { return m_metalBufferCacheMode; }
[[nodiscard]] PositionInvariance GetPositionInvariance() const { return m_positionInvariance; }
@ -57,7 +57,7 @@ private:
// graphic settings
std::optional<GraphicAPI> m_graphics_api{};
AccurateShaderMulOption m_accurateShaderMul = AccurateShaderMulOption::True;
#if ENABLE_METAL
#ifdef ENABLE_METAL
bool m_shaderFastMath = true;
MetalBufferCacheMode m_metalBufferCacheMode = MetalBufferCacheMode::Auto;
PositionInvariance m_positionInvariance = PositionInvariance::Auto;

View File

@ -11,7 +11,7 @@
#include "HW/Latte/Renderer/Renderer.h"
#include "util/containers/LookupTableL3.h"
#include "util/helpers/fspinlock.h"
#if ENABLE_METAL
#ifdef ENABLE_METAL
#include "Cafe/HW/Latte/Renderer/Metal/LatteToMtl.h"
#endif
#include <openssl/sha.h> /* SHA1_DIGEST_LENGTH */
@ -108,21 +108,28 @@ void LatteShader_calculateFSKey(LatteFetchShader* fetchShader)
key = std::rotl<uint64>(key, 8);
key += (uint64)attrib->semanticId;
key = std::rotl<uint64>(key, 8);
if (g_renderer->GetType() == RendererAPI::Metal)
switch(g_renderer->GetType())
{
#ifdef ENABLE_METAL
case RendererAPI::Metal:
{
key += (uint64)attrib->offset;
key = std::rotl<uint64>(key, 7);
break;
}
else
#endif
default:
{
key += (uint64)(attrib->offset & 3);
key = std::rotl<uint64>(key, 2);
break;
}
}
}
}
// todo - also hash invalid buffer groups?
#if ENABLE_METAL
#ifdef ENABLE_METAL
if (g_renderer->GetType() == RendererAPI::Metal)
{
for (sint32 g = 0; g < fetchShader->bufferGroups.size(); g++)
@ -171,7 +178,7 @@ void LatteFetchShader::CalculateFetchShaderVkHash()
this->vkPipelineHashFragment = h;
}
#if ENABLE_METAL
#ifdef ENABLE_METAL
void LatteFetchShader::CheckIfVerticesNeedManualFetchMtl(uint32* contextRegister)
{
for (sint32 g = 0; g < bufferGroups.size(); g++)
@ -376,7 +383,7 @@ LatteFetchShader* LatteShaderRecompiler_createFetchShader(LatteFetchShader::Cach
// these only make sense when vertex shader does not call FS?
LatteShader_calculateFSKey(newFetchShader);
newFetchShader->CalculateFetchShaderVkHash();
#if ENABLE_METAL
#ifdef ENABLE_METAL
newFetchShader->CheckIfVerticesNeedManualFetchMtl(contextRegister);
#endif
return newFetchShader;
@ -438,7 +445,7 @@ LatteFetchShader* LatteShaderRecompiler_createFetchShader(LatteFetchShader::Cach
}
LatteShader_calculateFSKey(newFetchShader);
newFetchShader->CalculateFetchShaderVkHash();
#if ENABLE_METAL
#ifdef ENABLE_METAL
newFetchShader->CheckIfVerticesNeedManualFetchMtl(contextRegister);
#endif

View File

@ -55,7 +55,7 @@ struct LatteFetchShader
void CalculateFetchShaderVkHash();
#if ENABLE_METAL
#ifdef ENABLE_METAL
void CheckIfVerticesNeedManualFetchMtl(uint32* contextRegister);
#endif

View File

@ -9,7 +9,9 @@
#include "Cafe/GameProfile/GameProfile.h"
#include "Cafe/HW/Latte/Core/LatteBufferCache.h"
#ifdef ENABLE_VULKAN
#include "Cafe/HW/Latte/Renderer/Vulkan/VulkanRenderer.h"
#endif
template<int vectorLen>
void rectGenerate4thVertex(uint32be* output, uint32be* input0, uint32be* input1, uint32be* input2)
@ -196,7 +198,7 @@ bool LatteBufferCache_Sync(uint32 minIndex, uint32 maxIndex, uint32 baseInstance
fixedBufferSize += 128;
#if BOOST_OS_MACOS
#if BOOST_OS_MACOS && defined(ENABLE_VULKAN)
if(bufferStride % 4 != 0)
{
if (g_renderer->GetType() == RendererAPI::Vulkan)

View File

@ -1,87 +0,0 @@
#include "Cafe/HW/Latte/Core/Latte.h"
#include "Cafe/HW/Latte/Core/LatteDraw.h"
#include "Cafe/HW/Latte/Core/LatteShader.h"
#include "Cafe/HW/Latte/Core/LatteDefaultShaders.h"
#include "util/helpers/StringBuf.h"
LatteDefaultShader_t* _copyShader_depthToColor;
LatteDefaultShader_t* _copyShader_colorToDepth;
void LatteDefaultShader_pixelCopyShader_generateVSBody(StringBuf* vs)
{
vs->add("#version 420\r\n");
vs->add("out vec2 passUV;\r\n");
vs->add("uniform vec4 uf_vertexOffsets[4];\r\n");
vs->add("\r\n");
vs->add("void main(){\r\n");
vs->add("int vID = gl_VertexID;\r\n");
vs->add("passUV = uf_vertexOffsets[vID].zw;\r\n");
vs->add("gl_Position = vec4(uf_vertexOffsets[vID].xy, 0.0, 1.0);\r\n");
vs->add("}\r\n");
}
GLuint gxShaderDepr_compileRaw(StringBuf* strSourceVS, StringBuf* strSourceFS);
GLuint gxShaderDepr_compileRaw(const std::string& vertex_source, const std::string& fragment_source);
LatteDefaultShader_t* LatteDefaultShader_getPixelCopyShader_depthToColor()
{
if (_copyShader_depthToColor != 0)
return _copyShader_depthToColor;
catchOpenGLError();
LatteDefaultShader_t* defaultShader = (LatteDefaultShader_t*)malloc(sizeof(LatteDefaultShader_t));
memset(defaultShader, 0, sizeof(LatteDefaultShader_t));
StringBuf fCStr_vertexShader(1024 * 16);
LatteDefaultShader_pixelCopyShader_generateVSBody(&fCStr_vertexShader);
StringBuf fCStr_defaultFragShader(1024 * 16);
fCStr_defaultFragShader.add("#version 420\r\n");
fCStr_defaultFragShader.add("in vec2 passUV;\r\n");
fCStr_defaultFragShader.add("uniform sampler2D textureSrc;\r\n");
fCStr_defaultFragShader.add("layout(location = 0) out vec4 colorOut0;\r\n");
fCStr_defaultFragShader.add("\r\n");
fCStr_defaultFragShader.add("void main(){\r\n");
fCStr_defaultFragShader.add("colorOut0 = vec4(texture(textureSrc, passUV).r,0.0,0.0,1.0);\r\n");
fCStr_defaultFragShader.add("}\r\n");
defaultShader->glProgamId = gxShaderDepr_compileRaw(&fCStr_vertexShader, &fCStr_defaultFragShader);
catchOpenGLError();
defaultShader->copyShaderUniforms.uniformLoc_textureSrc = glGetUniformLocation(defaultShader->glProgamId, "textureSrc");
defaultShader->copyShaderUniforms.uniformLoc_vertexOffsets = glGetUniformLocation(defaultShader->glProgamId, "uf_vertexOffsets");
_copyShader_depthToColor = defaultShader;
catchOpenGLError();
return defaultShader;
}
LatteDefaultShader_t* LatteDefaultShader_getPixelCopyShader_colorToDepth()
{
if (_copyShader_colorToDepth != 0)
return _copyShader_colorToDepth;
catchOpenGLError();
LatteDefaultShader_t* defaultShader = (LatteDefaultShader_t*)malloc(sizeof(LatteDefaultShader_t));
memset(defaultShader, 0, sizeof(LatteDefaultShader_t));
StringBuf fCStr_vertexShader(1024 * 16);
LatteDefaultShader_pixelCopyShader_generateVSBody(&fCStr_vertexShader);
StringBuf fCStr_defaultFragShader(1024 * 16);
fCStr_defaultFragShader.add("#version 420\r\n");
fCStr_defaultFragShader.add("in vec2 passUV;\r\n");
fCStr_defaultFragShader.add("uniform sampler2D textureSrc;\r\n");
fCStr_defaultFragShader.add("layout(location = 0) out vec4 colorOut0;\r\n");
fCStr_defaultFragShader.add("\r\n");
fCStr_defaultFragShader.add("void main(){\r\n");
fCStr_defaultFragShader.add("gl_FragDepth = texture(textureSrc, passUV).r;\r\n");
fCStr_defaultFragShader.add("}\r\n");
defaultShader->glProgamId = gxShaderDepr_compileRaw(&fCStr_vertexShader, &fCStr_defaultFragShader);
defaultShader->copyShaderUniforms.uniformLoc_textureSrc = glGetUniformLocation(defaultShader->glProgamId, "textureSrc");
defaultShader->copyShaderUniforms.uniformLoc_vertexOffsets = glGetUniformLocation(defaultShader->glProgamId, "uf_vertexOffsets");
_copyShader_colorToDepth = defaultShader;
catchOpenGLError();
return defaultShader;
}

View File

@ -1,13 +0,0 @@
typedef struct
{
GLuint glProgamId;
struct
{
GLuint uniformLoc_textureSrc;
GLuint uniformLoc_vertexOffsets;
}copyShaderUniforms;
}LatteDefaultShader_t;
LatteDefaultShader_t* LatteDefaultShader_getPixelCopyShader_depthToColor();
LatteDefaultShader_t* LatteDefaultShader_getPixelCopyShader_colorToDepth();

View File

@ -10,6 +10,7 @@
#include "Cafe/HW/Latte/Renderer/Renderer.h"
#include "Cafe/HW/Latte/Core/LattePerformanceMonitor.h"
#include "Cafe/GraphicPack/GraphicPack2.h"
#include "HW/Latte/Renderer/RendererCore.h"
#include "config/ActiveSettings.h"
#include "WindowSystem.h"
#include "Cafe/OS/libs/erreula/erreula.h"
@ -694,7 +695,9 @@ void LatteRenderTarget_itHLESwapScanBuffer()
performanceMonitor.gpuTime_frameTime.beginMeasuring();
LatteTC_CleanupUnusedTextures();
#ifdef ENABLE_OPENGL
LatteDraw_cleanupAfterFrame();
#endif
LatteQuery_CancelActiveGPU7Queries();
LatteBufferCache_notifySwapTVScanBuffer();
LattePerformanceMonitor_frameBegin();

View File

@ -1,3 +1,4 @@
#pragma once
typedef struct
{

View File

@ -6,7 +6,9 @@
#include "Cafe/HW/Latte/LegacyShaderDecompiler/LatteDecompiler.h"
#include "Cafe/HW/Latte/Core/FetchShader.h"
#include "Cafe/HW/Latte/Core/LattePerformanceMonitor.h"
#ifdef ENABLE_VULKAN
#include "Cafe/HW/Latte/Renderer/Vulkan/VulkanRenderer.h"
#endif
#include "Cafe/OS/libs/gx2/GX2.h" // todo - remove dependency
#include "Cafe/GraphicPack/GraphicPack2.h"
#include "HW/Latte/Core/Latte.h"
@ -15,7 +17,7 @@
#include "config/ActiveSettings.h"
#include "Cafe/GameProfile/GameProfile.h"
#include "util/containers/flat_hash_map.hpp"
#if ENABLE_METAL
#ifdef ENABLE_METAL
#include "Cafe/HW/Latte/Renderer/Metal/LatteToMtl.h"
#endif
#include <cinttypes>
@ -376,7 +378,9 @@ void LatteShader_FinishCompilation(LatteDecompilerShader* shader)
}
shader->shader->WaitForCompiled();
#ifdef ENABLE_OPENGL
LatteShader_prepareSeparableUniforms(shader);
#endif
LatteShader_CleanupAfterCompile(shader);
}
@ -525,7 +529,7 @@ void LatteSHRC_UpdateVSBaseHash(uint8* vertexShaderPtr, uint32 vertexShaderSize,
if (LatteGPUState.contextNew.PA_CL_CLIP_CNTL.get_DX_CLIP_SPACE_DEF())
vsHash += 0x1537;
#if ENABLE_METAL
#ifdef ENABLE_METAL
if (g_renderer->GetType() == RendererAPI::Metal)
{
bool isRectVertexShader = (primitiveType == Latte::LATTE_VGT_PRIMITIVE_TYPE::E_PRIMITIVE_TYPE::RECTS);
@ -550,7 +554,7 @@ void LatteSHRC_UpdateVSBaseHash(uint8* vertexShaderPtr, uint32 vertexShaderSize,
vsHash += 51ULL;
// Vertex fetch
if (_activeFetchShader->mtlFetchVertexManually)
if (_activeFetchShader->mtlFetchVertexManually)
vsHash += 349ULL;
}
}
@ -650,7 +654,7 @@ uint64 LatteSHRC_CalcPSAuxHash(LatteDecompilerShader* pixelShader, uint32* conte
auxHash += (uint64)dim;
}
#if ENABLE_METAL
#ifdef ENABLE_METAL
if (g_renderer->GetType() == RendererAPI::Metal)
{
// Textures as render targets
@ -683,20 +687,69 @@ uint64 LatteSHRC_CalcPSAuxHash(LatteDecompilerShader* pixelShader, uint32* conte
return auxHash;
}
void InitUniformLayoutFromDecompiler(
LatteDecompilerShader* shader,
const LatteDecompilerOutput_t& decompilerOutput
)
{
const auto& offsets = decompilerOutput.uniformOffsetsVK;
shader->uniform.loc_remapped = offsets.offset_remapped;
shader->uniform.loc_uniformRegister = offsets.offset_uniformRegister;
shader->uniform.count_uniformRegister = offsets.count_uniformRegister;
shader->uniform.loc_windowSpaceToClipSpaceTransform = offsets.offset_windowSpaceToClipSpaceTransform;
shader->uniform.loc_alphaTestRef = offsets.offset_alphaTestRef;
shader->uniform.loc_pointSize = offsets.offset_pointSize;
shader->uniform.loc_fragCoordScale = offsets.offset_fragCoordScale;
// Texture scale uniforms
shader->uniform.list_ufTexRescale.clear();
for (sint32 t = 0; t < LATTE_NUM_MAX_TEX_UNITS; t++)
{
if (offsets.offset_texScale[t] >= 0)
{
LatteUniformTextureScaleEntry_t entry{};
entry.texUnit = t;
entry.uniformLocation = offsets.offset_texScale[t];
shader->uniform.list_ufTexRescale.push_back(entry);
}
}
shader->uniform.loc_verticesPerInstance = offsets.offset_verticesPerInstance;
// Streamout buffers
for (sint32 t = 0; t < LATTE_NUM_STREAMOUT_BUFFER; t++)
{
shader->uniform.loc_streamoutBufferBase[t] = offsets.offset_streamoutBufferBase[t];
}
shader->uniform.uniformRangeSize = offsets.offset_endOfBlock;
}
LatteDecompilerShader* LatteShader_CreateShaderFromDecompilerOutput(LatteDecompilerOutput_t& decompilerOutput, uint64 baseHash, bool calculateAuxHash, uint64 optionalAuxHash, uint32* contextRegister)
{
LatteDecompilerShader* shader = decompilerOutput.shader;
shader->baseHash = baseHash;
// copy resource mapping
// HACK
if (g_renderer->GetType() == RendererAPI::OpenGL)
switch (g_renderer->GetType())
{
#ifdef ENABLE_OPENGL
case RendererAPI::OpenGL:
shader->resourceMapping = decompilerOutput.resourceMappingGL;
else if (g_renderer->GetType() == RendererAPI::Vulkan)
shader->resourceMapping = decompilerOutput.resourceMappingVK;
#if ENABLE_METAL
else
shader->resourceMapping = decompilerOutput.resourceMappingMTL;
break;
#endif
#ifdef ENABLE_VULKAN
case RendererAPI::Vulkan:
shader->resourceMapping = decompilerOutput.resourceMappingVK;
break;
#endif
#ifdef ENABLE_METAL
case RendererAPI::Metal:
shader->resourceMapping = decompilerOutput.resourceMappingMTL;
break;
#endif
}
// copy texture info
shader->textureUnitMask2 = decompilerOutput.textureUnitMask;
// copy streamout info
@ -705,33 +758,23 @@ LatteDecompilerShader* LatteShader_CreateShaderFromDecompilerOutput(LatteDecompi
// copy uniform offsets
// for OpenGL these are retrieved in _prepareSeparableUniforms()
// HACK
if (g_renderer->GetType() == RendererAPI::Vulkan || g_renderer->GetType() == RendererAPI::Metal)
{
shader->uniform.loc_remapped = decompilerOutput.uniformOffsetsVK.offset_remapped;
shader->uniform.loc_uniformRegister = decompilerOutput.uniformOffsetsVK.offset_uniformRegister;
shader->uniform.count_uniformRegister = decompilerOutput.uniformOffsetsVK.count_uniformRegister;
shader->uniform.loc_windowSpaceToClipSpaceTransform = decompilerOutput.uniformOffsetsVK.offset_windowSpaceToClipSpaceTransform;
shader->uniform.loc_alphaTestRef = decompilerOutput.uniformOffsetsVK.offset_alphaTestRef;
shader->uniform.loc_pointSize = decompilerOutput.uniformOffsetsVK.offset_pointSize;
shader->uniform.loc_fragCoordScale = decompilerOutput.uniformOffsetsVK.offset_fragCoordScale;
for (sint32 t = 0; t < LATTE_NUM_MAX_TEX_UNITS; t++)
{
if (decompilerOutput.uniformOffsetsVK.offset_texScale[t] >= 0)
{
LatteUniformTextureScaleEntry_t entry = { 0 };
entry.texUnit = t;
entry.uniformLocation = decompilerOutput.uniformOffsetsVK.offset_texScale[t];
shader->uniform.list_ufTexRescale.push_back(entry);
}
}
shader->uniform.loc_verticesPerInstance = decompilerOutput.uniformOffsetsVK.offset_verticesPerInstance;
for (sint32 t = 0; t < LATTE_NUM_STREAMOUT_BUFFER; t++)
shader->uniform.loc_streamoutBufferBase[t] = decompilerOutput.uniformOffsetsVK.offset_streamoutBufferBase[t];
shader->uniform.uniformRangeSize = decompilerOutput.uniformOffsetsVK.offset_endOfBlock;
}
else
switch (g_renderer->GetType())
{
#ifdef ENABLE_OPENGL
case RendererAPI::OpenGL:
shader->uniform.count_uniformRegister = decompilerOutput.uniformOffsetsGL.count_uniformRegister;
break;
#endif
#ifdef ENABLE_VULKAN
case RendererAPI::Vulkan:
InitUniformLayoutFromDecompiler(shader, decompilerOutput);
break;
#endif
#ifdef ENABLE_METAL
case RendererAPI::Metal:
InitUniformLayoutFromDecompiler(shader, decompilerOutput);
break;
#endif
}
// calculate aux hash
if (calculateAuxHash)
@ -766,10 +809,12 @@ void LatteShader_GetDecompilerOptions(LatteDecompilerOptions& options, LatteCons
options.usesGeometryShader = geometryShaderEnabled;
options.spirvInstrinsics.hasRoundingModeRTEFloat32 = false;
options.useTFViaSSBO = g_renderer->UseTFViaSSBO();
#ifdef ENABLE_VULKAN
if (g_renderer->GetType() == RendererAPI::Vulkan)
{
options.spirvInstrinsics.hasRoundingModeRTEFloat32 = VulkanRenderer::GetInstance()->HasSPRIVRoundingModeRTE32();
}
#endif
options.strictMul = g_current_game_profile->GetAccurateShaderMul() != AccurateShaderMulOption::False;
}
@ -845,12 +890,14 @@ LatteDecompilerShader* LatteShader_CompileSeparableVertexShader(uint64 baseHash,
LatteShader_CreateRendererShader(vertexShader, false);
performanceMonitor.numCompiledVS++;
#ifdef ENABLE_OPENGL
if (g_renderer->GetType() == RendererAPI::OpenGL)
{
if (vertexShader->shader)
vertexShader->shader->PreponeCompilation(true);
LatteShader_FinishCompilation(vertexShader);
}
#endif
LatteSHRC_RegisterShader(vertexShader, vertexShader->baseHash, vertexShader->auxHash);
return vertexShader;
@ -874,12 +921,14 @@ LatteDecompilerShader* LatteShader_CompileSeparableGeometryShader(uint64 baseHas
LatteShader_CreateRendererShader(geometryShader, false);
performanceMonitor.numCompiledGS++;
#ifdef ENABLE_OPENGL
if (g_renderer->GetType() == RendererAPI::OpenGL)
{
if (geometryShader->shader)
geometryShader->shader->PreponeCompilation(true);
LatteShader_FinishCompilation(geometryShader);
}
#endif
LatteSHRC_RegisterShader(geometryShader, geometryShader->baseHash, geometryShader->auxHash);
return geometryShader;
@ -903,12 +952,14 @@ LatteDecompilerShader* LatteShader_CompileSeparablePixelShader(uint64 baseHash,
LatteShaderCache_writeSeparablePixelShader(_shaderBaseHash_ps, psAuxHash, pixelShaderPtr, pixelShaderSize, LatteGPUState.contextRegister, usesGeometryShader);
}
#ifdef ENABLE_OPENGL
if (g_renderer->GetType() == RendererAPI::OpenGL)
{
if (pixelShader->shader)
pixelShader->shader->PreponeCompilation(true);
LatteShader_FinishCompilation(pixelShader);
}
#endif
LatteSHRC_RegisterShader(pixelShader, _shaderBaseHash_ps, psAuxHash);
return pixelShader;

View File

@ -9,13 +9,17 @@
#include "WindowSystem.h"
#include "Cafe/HW/Latte/Renderer/Renderer.h"
#ifdef ENABLE_OPENGL
#include "Cafe/HW/Latte/Renderer/OpenGL/RendererShaderGL.h"
#endif
#ifdef ENABLE_VULKAN
#include "Cafe/HW/Latte/Renderer/Vulkan/RendererShaderVk.h"
#if ENABLE_METAL
#include "Cafe/HW/Latte/Renderer/Vulkan/VulkanPipelineStableCache.h"
#endif
#ifdef ENABLE_METAL
#include "Cafe/HW/Latte/Renderer/Metal/RendererShaderMtl.h"
#include "Cafe/HW/Latte/Renderer/Metal/MetalPipelineCache.h"
#endif
#include "Cafe/HW/Latte/Renderer/Vulkan/VulkanPipelineStableCache.h"
#include <imgui.h>
#include "imgui/imgui_extension.h"
@ -273,14 +277,24 @@ static BootSoundPlayer g_bootSndPlayer;
void LatteShaderCache_finish()
{
if (g_renderer->GetType() == RendererAPI::Vulkan)
switch (g_renderer->GetType())
{
#ifdef ENABLE_VULKAN
case RendererAPI::Vulkan:
RendererShaderVk::ShaderCacheLoading_end();
else if (g_renderer->GetType() == RendererAPI::OpenGL)
RendererShaderGL::ShaderCacheLoading_end();
#if ENABLE_METAL
else if (g_renderer->GetType() == RendererAPI::Metal)
RendererShaderMtl::ShaderCacheLoading_end();
return;
#endif
#ifdef ENABLE_OPENGL
case RendererAPI::OpenGL:
RendererShaderGL::ShaderCacheLoading_end();
return;
#endif
#ifdef ENABLE_METAL
case RendererAPI::Metal:
RendererShaderMtl::ShaderCacheLoading_end();
return;
#endif
}
}
uint32 LatteShaderCache_getShaderCacheExtraVersion(uint64 titleId)
@ -359,21 +373,38 @@ void LatteShaderCache_Load()
fs::create_directories(ActiveSettings::GetCachePath("shaderCache/transferable"), ec);
fs::create_directories(ActiveSettings::GetCachePath("shaderCache/precompiled"), ec);
// initialize renderer specific caches
if (g_renderer->GetType() == RendererAPI::Vulkan)
switch(g_renderer->GetType())
{
#ifdef ENABLE_VULKAN
case RendererAPI::Vulkan:
RendererShaderVk::ShaderCacheLoading_begin(cacheTitleId);
else if (g_renderer->GetType() == RendererAPI::OpenGL)
RendererShaderGL::ShaderCacheLoading_begin(cacheTitleId);
#if ENABLE_METAL
else if (g_renderer->GetType() == RendererAPI::Metal)
RendererShaderMtl::ShaderCacheLoading_begin(cacheTitleId);
break;
#endif
#ifdef ENABLE_OPENGL
case RendererAPI::OpenGL:
RendererShaderGL::ShaderCacheLoading_begin(cacheTitleId);
break;
#endif
#ifdef ENABLE_METAL
case RendererAPI::Metal:
RendererShaderMtl::ShaderCacheLoading_begin(cacheTitleId);
break;
#endif
}
// get cache file name
fs::path pathGeneric;
if (g_renderer->GetType() == RendererAPI::Metal)
switch(g_renderer->GetType())
{
#ifdef ENABLE_METAL
case RendererAPI::Metal:
pathGeneric = ActiveSettings::GetCachePath("shaderCache/transferable/{:016x}_mtlshaders.bin", cacheTitleId);
else
break;
#endif
default:
pathGeneric = ActiveSettings::GetCachePath("shaderCache/transferable/{:016x}_shaders.bin", cacheTitleId);
break;
}
// calculate extraVersion for transferable and precompiled shader cache
uint32 transferableExtraVersion = SHADER_CACHE_GENERIC_EXTRA_VERSION;
@ -471,8 +502,10 @@ void LatteShaderCache_Load()
#endif
LatteShaderCache_finish();
// if Vulkan or Metal then also load pipeline cache
#if defined(ENABLE_VULKAN) || defined(ENABLE_METAL)
if (g_renderer->GetType() == RendererAPI::Vulkan || g_renderer->GetType() == RendererAPI::Metal)
LatteShaderCache_LoadPipelineCache(cacheTitleId);
#endif
g_renderer->BeginFrame(true);
@ -634,31 +667,52 @@ void LatteShaderCache_ShowProgress(const std::function <bool(void)>& loadUpdateF
void LatteShaderCache_LoadPipelineCache(uint64 cacheTitleId)
{
if (g_renderer->GetType() == RendererAPI::Vulkan)
switch(g_renderer->GetType())
{
#ifdef ENABLE_VULKAN
case RendererAPI::Vulkan:
g_shaderCacheLoaderState.pipelineFileCount = VulkanPipelineStableCache::GetInstance().BeginLoading(cacheTitleId);
#if ENABLE_METAL
else if (g_renderer->GetType() == RendererAPI::Metal)
break;
#endif
#ifdef ENABLE_METAL
case RendererAPI::Metal:
g_shaderCacheLoaderState.pipelineFileCount = MetalPipelineCache::GetInstance().BeginLoading(cacheTitleId);
break;
#endif
}
g_shaderCacheLoaderState.loadedPipelines = 0;
LatteShaderCache_ShowProgress(LatteShaderCache_updatePipelineLoadingProgress, true);
if (g_renderer->GetType() == RendererAPI::Vulkan)
switch(g_renderer->GetType())
{
#ifdef ENABLE_VULKAN
case RendererAPI::Vulkan:
VulkanPipelineStableCache::GetInstance().EndLoading();
#if ENABLE_METAL
else if (g_renderer->GetType() == RendererAPI::Metal)
MetalPipelineCache::GetInstance().EndLoading();
break;
#endif
#ifdef ENABLE_METAL
case RendererAPI::Metal:
MetalPipelineCache::GetInstance().EndLoading();
break;
#endif
}
}
bool LatteShaderCache_updatePipelineLoadingProgress()
{
uint32 pipelinesMissingShaders = 0;
if (g_renderer->GetType() == RendererAPI::Vulkan)
switch(g_renderer->GetType())
{
#ifdef ENABLE_VULKAN
case RendererAPI::Vulkan:
return VulkanPipelineStableCache::GetInstance().UpdateLoading(g_shaderCacheLoaderState.loadedPipelines, pipelinesMissingShaders);
#if ENABLE_METAL
else if (g_renderer->GetType() == RendererAPI::Metal)
#endif
#ifdef ENABLE_METAL
case RendererAPI::Metal:
return MetalPipelineCache::GetInstance().UpdateLoading(g_shaderCacheLoaderState.loadedPipelines, pipelinesMissingShaders);
#endif
}
return false;
}
@ -918,20 +972,37 @@ void LatteShaderCache_Close()
delete s_shaderCacheGeneric;
s_shaderCacheGeneric = nullptr;
}
if (g_renderer->GetType() == RendererAPI::Vulkan)
switch(g_renderer->GetType())
{
#ifdef ENABLE_VULKAN
case RendererAPI::Vulkan:
RendererShaderVk::ShaderCacheLoading_Close();
else if (g_renderer->GetType() == RendererAPI::OpenGL)
RendererShaderGL::ShaderCacheLoading_Close();
#if ENABLE_METAL
else if (g_renderer->GetType() == RendererAPI::Metal)
RendererShaderMtl::ShaderCacheLoading_Close();
break;
#endif
#ifdef ENABLE_OPENGL
case RendererAPI::OpenGL:
RendererShaderGL::ShaderCacheLoading_Close();
break;
#endif
#ifdef ENABLE_METAL
case RendererAPI::Metal:
RendererShaderMtl::ShaderCacheLoading_Close();
break;
#endif
}
// if Vulkan or Metal then also close pipeline cache
if (g_renderer->GetType() == RendererAPI::Vulkan)
VulkanPipelineStableCache::GetInstance().Close();
#if ENABLE_METAL
else if (g_renderer->GetType() == RendererAPI::Metal)
MetalPipelineCache::GetInstance().Close();
switch(g_renderer->GetType())
{
#ifdef ENABLE_VULKAN
case RendererAPI::Vulkan:
VulkanPipelineStableCache::GetInstance().Close();
break;
#endif
#ifdef ENABLE_METAL
case RendererAPI::Metal:
MetalPipelineCache::GetInstance().Close();
break;
#endif
}
}

View File

@ -1,7 +1,6 @@
#include "Cafe/HW/Latte/Core/Latte.h"
#include "Cafe/HW/Latte/Core/LatteDraw.h"
#include "Cafe/HW/Latte/Core/LatteShader.h"
#include "Cafe/HW/Latte/Core/LatteDefaultShaders.h"
#include "Cafe/HW/Latte/Core/LatteTexture.h"
#include "Cafe/HW/Latte/Renderer/Renderer.h"

View File

@ -567,6 +567,8 @@ bool __LatteTexture_IsBlockedFormatRelation(LatteTexture* texture1, LatteTexture
if (texture1->format == Latte::E_GX2SURFFMT::D32_FLOAT && Latte::GetHWFormat(texture2->format) == Latte::E_HWSURFFMT::HWFMT_8_8_8_8)
return true;
}
#ifdef ENABLE_VULKAN
// Vulkan has stricter rules
if (g_renderer->GetType() == RendererAPI::Vulkan)
{
@ -574,6 +576,7 @@ bool __LatteTexture_IsBlockedFormatRelation(LatteTexture* texture1, LatteTexture
if (texture1->format == Latte::E_GX2SURFFMT::D32_FLOAT && Latte::GetHWFormat(texture2->format) == Latte::E_HWSURFFMT::HWFMT_8_24)
return true;
}
#endif
return false;
}

View File

@ -4,9 +4,11 @@
#include "Cafe/HW/Latte/Renderer/Renderer.h"
#ifdef ENABLE_OPENGL
#include "Cafe/HW/Latte/Renderer/OpenGL/OpenGLRenderer.h"
#include "Cafe/HW/Latte/Renderer/OpenGL/LatteTextureGL.h"
#include "Cafe/HW/Latte/Renderer/OpenGL/LatteTextureViewGL.h"
#endif
struct TexScaleXY
{
@ -192,6 +194,7 @@ void LatteTexture_updateTexturesForStage(LatteDecompilerShader* shaderContext, u
LatteGPUState.repeatTextureInitialization = true;
}
#ifdef ENABLE_OPENGL
if (g_renderer->GetType() == RendererAPI::OpenGL)
{
// on OpenGL, texture views and sampler parameters are tied together (we are avoiding sampler objects due to driver bugs)
@ -214,6 +217,8 @@ void LatteTexture_updateTexturesForStage(LatteDecompilerShader* shaderContext, u
textureView->lastTextureBindIndex = LatteGPUState.textureBindCounter;
rendererGL->renderstate_updateTextureSettingsGL(shaderContext, textureView, textureIndex + glBackendBaseTexUnit, word4, textureIndex, isDepthSampler);
}
#endif
g_renderer->texture_setLatteTexture(textureView, textureIndex + glBackendBaseTexUnit);
// update if data changed
bool swizzleChanged = false;

View File

@ -6,7 +6,9 @@
#include "Cafe/HW/Latte/Renderer/Renderer.h"
#include "Cafe/HW/Latte/Core/LatteTexture.h"
#ifdef ENABLE_OPENGL
#include "Cafe/HW/Latte/Renderer/OpenGL/LatteTextureViewGL.h"
#endif
#define LOG_READBACK_TIME

View File

@ -1,6 +1,8 @@
#include "Cafe/HW/Latte/Core/Latte.h"
#include "Cafe/OS/libs/gx2/GX2_Event.h"
#ifdef ENABLE_VULKAN
#include "Cafe/HW/Latte/Renderer/Vulkan/VsyncDriver.h"
#endif
#include "util/highresolutiontimer/HighResolutionTimer.h"
#include "config/CemuConfig.h"
#include "Cafe/CafeSystem.h"
@ -55,8 +57,10 @@ void LatteTiming_EnableHostDrivenVSync()
{
if (s_usingHostDrivenVSync)
return;
#ifdef ENABLE_VULKAN
VsyncDriver_startThread(LatteTiming_NotifyHostVSync);
s_usingHostDrivenVSync = true;
#endif
}
bool LatteTiming_IsUsingHostDrivenVSync()

View File

@ -10,7 +10,9 @@
#include "Cafe/HW/Latte/Core/FetchShader.h"
#include "Cafe/HW/Latte/Core/LattePerformanceMonitor.h"
#include "Cafe/HW/Latte/Renderer/Renderer.h"
#ifdef ENABLE_VULKAN
#include "Cafe/HW/Latte/Renderer/Vulkan/VulkanRenderer.h"
#endif
#include "util/helpers/helpers.h"
// parse instruction and if valid append it to instructionList
@ -1069,12 +1071,24 @@ void _LatteDecompiler_Process(LatteDecompilerShaderContext* shaderContext, uint8
// emit code
if (shaderContext->shader->hasError == false)
{
if (g_renderer->GetType() == RendererAPI::OpenGL || g_renderer->GetType() == RendererAPI::Vulkan)
LatteDecompiler_emitGLSLShader(shaderContext, shaderContext->shader);
#if ENABLE_METAL
else
LatteDecompiler_emitMSLShader(shaderContext, shaderContext->shader);
switch(g_renderer->GetType())
{
#ifdef ENABLE_OPENGL
case RendererAPI::OpenGL:
LatteDecompiler_emitGLSLShader(shaderContext, shaderContext->shader);
break;
#endif
#ifdef ENABLE_VULKAN
case RendererAPI::Vulkan:
LatteDecompiler_emitGLSLShader(shaderContext, shaderContext->shader);
break;
#endif
#ifdef ENABLE_METAL
case RendererAPI::Metal:
LatteDecompiler_emitMSLShader(shaderContext, shaderContext->shader);
break;
#endif
}
}
LatteDecompiler_cleanup(shaderContext);
// fast access

View File

@ -10,7 +10,7 @@
#include "Cafe/HW/Latte/Renderer/Renderer.h"
#include "Common/MemPtr.h"
#include "HW/Latte/ISA/LatteReg.h"
#if ENABLE_METAL
#ifdef ENABLE_METAL
#include "HW/Latte/Renderer/Metal/MetalCommon.h"
#endif
@ -403,11 +403,9 @@ void LatteDecompiler_analyzeExport(LatteDecompilerShaderContext* shaderContext,
}
else if (cfInstruction->exportType == 0 && cfInstruction->exportArrayBase == 61)
{
#if ENABLE_METAL
// Only check for depth buffer mask on Metal, as its not in the PS hash on other backends
if (g_renderer->GetType() != RendererAPI::Metal || LatteMRT::GetActiveDepthBufferMask(*shaderContext->contextRegistersNew))
shader->depthMask = true;
#endif
}
else
debugBreakpoint();
@ -512,7 +510,7 @@ namespace LatteDecompiler
}
}
#if ENABLE_METAL
#ifdef ENABLE_METAL
void _initTextureBindingPointsMTL(LatteDecompilerShaderContext* decompilerContext)
{
// for Vulkan we use consecutive indices
@ -563,7 +561,7 @@ namespace LatteDecompiler
{
decompilerContext->hasUniformVarBlock = true; // uf_verticesPerInstance and uf_streamoutBufferBase*
}
#if ENABLE_METAL
#ifdef ENABLE_METAL
if (g_renderer->GetType() == RendererAPI::Metal)
{
bool usesGeometryShader = UseGeometryShader(*decompilerContext->contextRegistersNew, decompilerContext->options->usesGeometryShader);
@ -1113,7 +1111,7 @@ void LatteDecompiler_analyze(LatteDecompilerShaderContext* shaderContext, LatteD
shaderContext->output->resourceMappingVK.setIndex = 2;
LatteDecompiler::_initTextureBindingPointsGL(shaderContext);
LatteDecompiler::_initTextureBindingPointsVK(shaderContext);
#if ENABLE_METAL
#ifdef ENABLE_METAL
LatteDecompiler::_initTextureBindingPointsMTL(shaderContext);
#endif
LatteDecompiler::_initUniformBindingPoints(shaderContext);

View File

@ -266,7 +266,7 @@ struct LatteDecompilerShaderContext
void LatteDecompiler_analyze(LatteDecompilerShaderContext* shaderContext, LatteDecompilerShader* shader);
void LatteDecompiler_analyzeDataTypes(LatteDecompilerShaderContext* shaderContext);
void LatteDecompiler_emitGLSLShader(LatteDecompilerShaderContext* shaderContext, LatteDecompilerShader* shader);
#if ENABLE_METAL
#ifdef ENABLE_METAL
void LatteDecompiler_emitMSLShader(LatteDecompilerShaderContext* shaderContext, LatteDecompilerShader* shader);
#endif

View File

@ -33,7 +33,7 @@ extern bool hasValidFramebufferAttached;
float supportBufferData[512 * 4];
// Defined in the OpenGL renderer
// Defined in the Common renderer
void LatteDraw_handleSpecialState8_clearAsDepth();
std::vector<MetalRenderer::DeviceInfo> MetalRenderer::GetDevices()

View File

@ -17,6 +17,7 @@
#include "Cafe/OS/libs/gx2/GX2.h"
#include "Cafe/GameProfile/GameProfile.h"
#include "HW/Latte/Renderer/RendererCore.h"
#include "config/ActiveSettings.h"
@ -52,7 +53,7 @@ struct
uint32 maxIndex;
uint32 minIndex;
uint8* indexData;
// buffer
// buffer
GLuint glIndexCacheBuffer;
VirtualBufferHeap_t* indexBufferVirtualHeap;
uint8* mappedIndexBuffer;
@ -371,6 +372,8 @@ void _decodeAndUploadIndexData(indexDataCacheEntry2_t* cacheEntry)
void LatteDraw_cleanupAfterFrame()
{
if (g_renderer->GetType() != RendererAPI::OpenGL)
return;
// drop everything from cache that is older than 30 frames
uint32 frameCounter = LatteGPUState.frameCounter;
while (indexDataCacheFirst)
@ -524,70 +527,6 @@ void LatteDrawGL_prepareIndicesWithGPUCache(MPTR indexDataMPTR, _INDEX_TYPE inde
indexState.indexData = (uint8*)(size_t)cacheEntry->heapEntry->startOffset;
}
void LatteDraw_handleSpecialState8_clearAsDepth()
{
if (LatteGPUState.contextNew.GetSpecialStateValues()[0] == 0)
cemuLog_logDebug(LogType::Force, "Special state 8 requires special state 0 but it is not set?");
// get depth buffer information
uint32 regDepthBuffer = LatteGPUState.contextRegister[mmDB_HTILE_DATA_BASE];
uint32 regDepthSize = LatteGPUState.contextRegister[mmDB_DEPTH_SIZE];
uint32 regDepthBufferInfo = LatteGPUState.contextRegister[mmDB_DEPTH_INFO];
// get format and tileMode from info reg
uint32 depthBufferTileMode = (regDepthBufferInfo >> 15) & 0xF;
MPTR depthBufferPhysMem = regDepthBuffer << 8;
uint32 depthBufferPitch = (((regDepthSize >> 0) & 0x3FF) + 1);
uint32 depthBufferHeight = ((((regDepthSize >> 10) & 0xFFFFF) + 1) / depthBufferPitch);
depthBufferPitch <<= 3;
depthBufferHeight <<= 3;
uint32 depthBufferWidth = depthBufferPitch;
sint32 sliceIndex = 0; // todo
sint32 mipIndex = 0;
// clear all color buffers that match the format of the depth buffer
sint32 searchIndex = 0;
bool targetFound = false;
while (true)
{
LatteTextureView* view = LatteTC_LookupTextureByData(depthBufferPhysMem, depthBufferWidth, depthBufferHeight, depthBufferPitch, 0, 1, sliceIndex, 1, &searchIndex);
if (!view)
{
// should we clear in RAM instead?
break;
}
sint32 effectiveClearWidth = view->baseTexture->width;
sint32 effectiveClearHeight = view->baseTexture->height;
LatteTexture_scaleToEffectiveSize(view->baseTexture, &effectiveClearWidth, &effectiveClearHeight, 0);
// hacky way to get clear color
float* regClearColor = (float*)(LatteGPUState.contextRegister + 0xC000 + 0); // REG_BASE_ALU_CONST
uint8 clearColor[4] = { 0 };
clearColor[0] = (uint8)(regClearColor[0] * 255.0f);
clearColor[1] = (uint8)(regClearColor[1] * 255.0f);
clearColor[2] = (uint8)(regClearColor[2] * 255.0f);
clearColor[3] = (uint8)(regClearColor[3] * 255.0f);
// todo - use fragment shader software emulation (evoke for one pixel) to determine clear color
// todo - dont clear entire slice, use effectiveClearWidth, effectiveClearHeight
if (g_renderer->GetType() == RendererAPI::OpenGL)
{
//cemu_assert_debug(false); // implement g_renderer->texture_clearColorSlice properly for OpenGL renderer
if (glClearTexSubImage)
glClearTexSubImage(((LatteTextureViewGL*)view)->glTexId, mipIndex, 0, 0, 0, effectiveClearWidth, effectiveClearHeight, 1, GL_RGBA, GL_UNSIGNED_BYTE, clearColor);
}
else
{
if (view->baseTexture->isDepth)
g_renderer->texture_clearDepthSlice(view->baseTexture, sliceIndex + view->firstSlice, mipIndex + view->firstMip, true, view->baseTexture->hasStencil, 0.0f, 0);
else
g_renderer->texture_clearColorSlice(view->baseTexture, sliceIndex + view->firstSlice, mipIndex + view->firstMip, clearColor[0], clearColor[1], clearColor[2], clearColor[3]);
}
}
}
void LatteDrawGL_doDraw(_INDEX_TYPE indexType, uint32 baseVertex, uint32 baseInstance, uint32 instanceCount, uint32 count)
{
if (indexType == _INDEX_TYPE::U16_BE)
@ -755,10 +694,6 @@ void OpenGLRenderer::_setupVertexAttributes()
}
}
void rectsEmulationGS_outputSingleVertex(std::string& gsSrc, LatteDecompilerShader* vertexShader, LatteShaderPSInputTable* psInputTable, sint32 vIdx);
void rectsEmulationGS_outputGeneratedVertex(std::string& gsSrc, LatteDecompilerShader* vertexShader, LatteShaderPSInputTable* psInputTable, const char* variant);
void rectsEmulationGS_outputVerticesCode(std::string& gsSrc, LatteDecompilerShader* vertexShader, LatteShaderPSInputTable* psInputTable, sint32 p0, sint32 p1, sint32 p2, sint32 p3, const char* variant, const LatteContextRegister& latteRegister);
std::map<uint64, RendererShaderGL*> g_mapGLRectEmulationGS;
RendererShaderGL* rectsEmulationGS_generateShaderGL(LatteDecompilerShader* vertexShader)

View File

@ -1,6 +1,7 @@
#include "Cafe/HW/Latte/Renderer/OpenGL/OpenGLRenderer.h"
#include "Cafe/HW/Latte/Renderer/OpenGL/RendererShaderGL.h"
#include "Cafe/HW/Latte/Renderer/OpenGL/CachedFBOGL.h"
#include "Cafe/HW/Latte/Renderer/OpenGL/OpenGLSurfaceCopy.h"
#include "Cafe/HW/Latte/Renderer/OpenGL/LatteTextureGL.h"
#include "Cafe/HW/Latte/Renderer/OpenGL/LatteTextureViewGL.h"
@ -8,7 +9,7 @@
#include "Cafe/HW/Latte/Core/LatteShader.h"
#include "Cafe/HW/Latte/Core/LatteDraw.h"
#include "Cafe/HW/Latte/Core/LatteDefaultShaders.h"
#include "util/helpers/StringBuf.h"
void LatteDraw_resetAttributePointerCache();
@ -66,9 +67,9 @@ void OpenGLRenderer::surfaceCopy_copySurfaceWithFormatConversion(LatteTexture* s
if (destinationTexture->isDepth)
renderstate_setAlwaysWriteDepth();
// bind format specific copy shader
LatteDefaultShader_t* copyShader = LatteDefaultShader_getPixelCopyShader_depthToColor();
LatteGLDefaultShader_t* copyShader = LatteGLDefaultShader_getPixelCopyShader_depthToColor();
if (destinationTexture->isDepth)
copyShader = LatteDefaultShader_getPixelCopyShader_colorToDepth();
copyShader = LatteGLDefaultShader_getPixelCopyShader_colorToDepth();
glUseProgram(copyShader->glProgamId);
catchOpenGLError();
// setup uniforms
@ -113,4 +114,86 @@ void OpenGLRenderer::surfaceCopy_copySurfaceWithFormatConversion(LatteTexture* s
LatteGPUState.repeatTextureInitialization = true;
glUseProgram(0);
}
LatteGLDefaultShader_t* _copyShader_depthToColor;
LatteGLDefaultShader_t* _copyShader_colorToDepth;
void LatteGLDefaultShader_pixelCopyShader_generateVSBody(StringBuf* vs)
{
vs->add("#version 420\r\n");
vs->add("out vec2 passUV;\r\n");
vs->add("uniform vec4 uf_vertexOffsets[4];\r\n");
vs->add("\r\n");
vs->add("void main(){\r\n");
vs->add("int vID = gl_VertexID;\r\n");
vs->add("passUV = uf_vertexOffsets[vID].zw;\r\n");
vs->add("gl_Position = vec4(uf_vertexOffsets[vID].xy, 0.0, 1.0);\r\n");
vs->add("}\r\n");
}
GLuint gxShaderDepr_compileRaw(StringBuf* strSourceVS, StringBuf* strSourceFS);
GLuint gxShaderDepr_compileRaw(const std::string& vertex_source, const std::string& fragment_source);
LatteGLDefaultShader_t* LatteGLDefaultShader_getPixelCopyShader_depthToColor()
{
if (_copyShader_depthToColor != 0)
return _copyShader_depthToColor;
catchOpenGLError();
LatteGLDefaultShader_t* defaultShader = (LatteGLDefaultShader_t*)malloc(sizeof(LatteGLDefaultShader_t));
memset(defaultShader, 0, sizeof(LatteGLDefaultShader_t));
StringBuf fCStr_vertexShader(1024 * 16);
LatteGLDefaultShader_pixelCopyShader_generateVSBody(&fCStr_vertexShader);
StringBuf fCStr_defaultFragShader(1024 * 16);
fCStr_defaultFragShader.add("#version 420\r\n");
fCStr_defaultFragShader.add("in vec2 passUV;\r\n");
fCStr_defaultFragShader.add("uniform sampler2D textureSrc;\r\n");
fCStr_defaultFragShader.add("layout(location = 0) out vec4 colorOut0;\r\n");
fCStr_defaultFragShader.add("\r\n");
fCStr_defaultFragShader.add("void main(){\r\n");
fCStr_defaultFragShader.add("colorOut0 = vec4(texture(textureSrc, passUV).r,0.0,0.0,1.0);\r\n");
fCStr_defaultFragShader.add("}\r\n");
defaultShader->glProgamId = gxShaderDepr_compileRaw(&fCStr_vertexShader, &fCStr_defaultFragShader);
catchOpenGLError();
defaultShader->copyShaderUniforms.uniformLoc_textureSrc = glGetUniformLocation(defaultShader->glProgamId, "textureSrc");
defaultShader->copyShaderUniforms.uniformLoc_vertexOffsets = glGetUniformLocation(defaultShader->glProgamId, "uf_vertexOffsets");
_copyShader_depthToColor = defaultShader;
catchOpenGLError();
return defaultShader;
}
LatteGLDefaultShader_t* LatteGLDefaultShader_getPixelCopyShader_colorToDepth()
{
if (_copyShader_colorToDepth != 0)
return _copyShader_colorToDepth;
catchOpenGLError();
LatteGLDefaultShader_t* defaultShader = (LatteGLDefaultShader_t*)malloc(sizeof(LatteGLDefaultShader_t));
memset(defaultShader, 0, sizeof(LatteGLDefaultShader_t));
StringBuf fCStr_vertexShader(1024 * 16);
LatteGLDefaultShader_pixelCopyShader_generateVSBody(&fCStr_vertexShader);
StringBuf fCStr_defaultFragShader(1024 * 16);
fCStr_defaultFragShader.add("#version 420\r\n");
fCStr_defaultFragShader.add("in vec2 passUV;\r\n");
fCStr_defaultFragShader.add("uniform sampler2D textureSrc;\r\n");
fCStr_defaultFragShader.add("layout(location = 0) out vec4 colorOut0;\r\n");
fCStr_defaultFragShader.add("\r\n");
fCStr_defaultFragShader.add("void main(){\r\n");
fCStr_defaultFragShader.add("gl_FragDepth = texture(textureSrc, passUV).r;\r\n");
fCStr_defaultFragShader.add("}\r\n");
defaultShader->glProgamId = gxShaderDepr_compileRaw(&fCStr_vertexShader, &fCStr_defaultFragShader);
defaultShader->copyShaderUniforms.uniformLoc_textureSrc = glGetUniformLocation(defaultShader->glProgamId, "textureSrc");
defaultShader->copyShaderUniforms.uniformLoc_vertexOffsets = glGetUniformLocation(defaultShader->glProgamId, "uf_vertexOffsets");
_copyShader_colorToDepth = defaultShader;
catchOpenGLError();
return defaultShader;
}

View File

@ -0,0 +1,14 @@
#pragma once
typedef struct
{
GLuint glProgamId;
struct
{
GLuint uniformLoc_textureSrc;
GLuint uniformLoc_vertexOffsets;
}copyShaderUniforms;
}LatteGLDefaultShader_t;
LatteGLDefaultShader_t* LatteGLDefaultShader_getPixelCopyShader_depthToColor();
LatteGLDefaultShader_t* LatteGLDefaultShader_getPixelCopyShader_colorToDepth();

View File

@ -0,0 +1,132 @@
#include "RendererCore.h"
#include "Cafe/HW/Latte/Renderer/Renderer.h"
#include "Cafe/HW/Latte/ISA/RegDefines.h"
#include "HW/Latte/Core/LatteShader.h"
#include "config/CemuConfig.h"
#ifdef ENABLE_OPENGL
#include "Common/GLInclude/GLInclude.h"
#include "Cafe/HW/Latte/Renderer/OpenGL/LatteTextureViewGL.h"
#endif
void LatteDraw_handleSpecialState8_clearAsDepth()
{
if (LatteGPUState.contextNew.GetSpecialStateValues()[0] == 0)
cemuLog_logDebug(LogType::Force, "Special state 8 requires special state 0 but it is not set?");
// get depth buffer information
uint32 regDepthBuffer = LatteGPUState.contextRegister[mmDB_HTILE_DATA_BASE];
uint32 regDepthSize = LatteGPUState.contextRegister[mmDB_DEPTH_SIZE];
uint32 regDepthBufferInfo = LatteGPUState.contextRegister[mmDB_DEPTH_INFO];
// get format and tileMode from info reg
uint32 depthBufferTileMode = (regDepthBufferInfo >> 15) & 0xF;
MPTR depthBufferPhysMem = regDepthBuffer << 8;
uint32 depthBufferPitch = (((regDepthSize >> 0) & 0x3FF) + 1);
uint32 depthBufferHeight = ((((regDepthSize >> 10) & 0xFFFFF) + 1) / depthBufferPitch);
depthBufferPitch <<= 3;
depthBufferHeight <<= 3;
uint32 depthBufferWidth = depthBufferPitch;
sint32 sliceIndex = 0; // todo
sint32 mipIndex = 0;
// clear all color buffers that match the format of the depth buffer
sint32 searchIndex = 0;
bool targetFound = false;
while (true)
{
LatteTextureView* view = LatteTC_LookupTextureByData(depthBufferPhysMem, depthBufferWidth, depthBufferHeight, depthBufferPitch, 0, 1, sliceIndex, 1, &searchIndex);
if (!view)
{
// should we clear in RAM instead?
break;
}
sint32 effectiveClearWidth = view->baseTexture->width;
sint32 effectiveClearHeight = view->baseTexture->height;
LatteTexture_scaleToEffectiveSize(view->baseTexture, &effectiveClearWidth, &effectiveClearHeight, 0);
// hacky way to get clear color
float* regClearColor = (float*)(LatteGPUState.contextRegister + 0xC000 + 0); // REG_BASE_ALU_CONST
uint8 clearColor[4] = { 0 };
clearColor[0] = (uint8)(regClearColor[0] * 255.0f);
clearColor[1] = (uint8)(regClearColor[1] * 255.0f);
clearColor[2] = (uint8)(regClearColor[2] * 255.0f);
clearColor[3] = (uint8)(regClearColor[3] * 255.0f);
// todo - use fragment shader software emulation (evoke for one pixel) to determine clear color
// todo - dont clear entire slice, use effectiveClearWidth, effectiveClearHeight
switch (g_renderer->GetType())
{
#ifdef ENABLE_OPENGL
case RendererAPI::OpenGL:
{
//cemu_assert_debug(false); // implement g_renderer->texture_clearColorSlice properly for OpenGL renderer
if (glClearTexSubImage)
glClearTexSubImage(((LatteTextureViewGL*)view)->glTexId, mipIndex, 0, 0, 0, effectiveClearWidth, effectiveClearHeight, 1, GL_RGBA, GL_UNSIGNED_BYTE, clearColor);
break;
}
#endif
default:
{
if (view->baseTexture->isDepth)
g_renderer->texture_clearDepthSlice(view->baseTexture, sliceIndex + view->firstSlice, mipIndex + view->firstMip, true, view->baseTexture->hasStencil, 0.0f, 0);
else
g_renderer->texture_clearColorSlice(view->baseTexture, sliceIndex + view->firstSlice, mipIndex + view->firstMip, clearColor[0], clearColor[1], clearColor[2], clearColor[3]);
}
}
}
}
/* rects emulation */
void rectsEmulationGS_outputSingleVertex(std::string& gsSrc, LatteDecompilerShader* vertexShader, LatteShaderPSInputTable* psInputTable, sint32 vIdx, const LatteContextRegister& latteRegister)
{
auto parameterMask = vertexShader->outputParameterMask;
for (uint32 i = 0; i < 32; i++)
{
if ((parameterMask & (1 << i)) == 0)
continue;
sint32 vsSemanticId = psInputTable->getVertexShaderOutParamSemanticId(latteRegister.GetRawView(), i);
if (vsSemanticId < 0)
continue;
// make sure PS has matching input
if (!psInputTable->hasPSImportForSemanticId(vsSemanticId))
continue;
gsSrc.append(fmt::format("passParameterSem{}Out = passParameterSem{}In[{}];\r\n", vsSemanticId, vsSemanticId, vIdx));
}
gsSrc.append(fmt::format("gl_Position = gl_in[{}].gl_Position;\r\n", vIdx));
gsSrc.append("EmitVertex();\r\n");
}
void rectsEmulationGS_outputGeneratedVertex(std::string& gsSrc, LatteDecompilerShader* vertexShader, LatteShaderPSInputTable* psInputTable, const char* variant, const LatteContextRegister& latteRegister)
{
auto parameterMask = vertexShader->outputParameterMask;
for (uint32 i = 0; i < 32; i++)
{
if ((parameterMask & (1 << i)) == 0)
continue;
sint32 vsSemanticId = psInputTable->getVertexShaderOutParamSemanticId(latteRegister.GetRawView(), i);
if (vsSemanticId < 0)
continue;
// make sure PS has matching input
if (!psInputTable->hasPSImportForSemanticId(vsSemanticId))
continue;
gsSrc.append(fmt::format("passParameterSem{}Out = gen4thVertex{}(passParameterSem{}In[0], passParameterSem{}In[1], passParameterSem{}In[2]);\r\n", vsSemanticId, variant, vsSemanticId, vsSemanticId, vsSemanticId));
}
gsSrc.append(fmt::format("gl_Position = gen4thVertex{}(gl_in[0].gl_Position, gl_in[1].gl_Position, gl_in[2].gl_Position);\r\n", variant));
gsSrc.append("EmitVertex();\r\n");
}
void rectsEmulationGS_outputVerticesCode(std::string& gsSrc, LatteDecompilerShader* vertexShader, LatteShaderPSInputTable* psInputTable, sint32 p0, sint32 p1, sint32 p2, sint32 p3, const char* variant, const LatteContextRegister& latteRegister)
{
sint32 pList[4] = { p0, p1, p2, p3 };
for (sint32 i = 0; i < 4; i++)
{
if (pList[i] == 3)
rectsEmulationGS_outputGeneratedVertex(gsSrc, vertexShader, psInputTable, variant, latteRegister);
else
rectsEmulationGS_outputSingleVertex(gsSrc, vertexShader, psInputTable, pList[i], latteRegister);
}
}

View File

@ -0,0 +1,11 @@
#pragma once
#include "Cafe/HW/Latte/Core/LatteRingBuffer.h"
#include "Cafe/HW/Latte/Core/Latte.h"
void LatteDraw_handleSpecialState8_clearAsDepth();
class LatteShaderPSInputTable;
void rectsEmulationGS_outputSingleVertex(std::string& gsSrc, LatteDecompilerShader* vertexShader, LatteShaderPSInputTable* psInputTable, sint32 vIdx);
void rectsEmulationGS_outputGeneratedVertex(std::string& gsSrc, LatteDecompilerShader* vertexShader, LatteShaderPSInputTable* psInputTable, const char* variant);
void rectsEmulationGS_outputVerticesCode(std::string& gsSrc, LatteDecompilerShader* vertexShader, LatteShaderPSInputTable* psInputTable, sint32 p0, sint32 p1, sint32 p2, sint32 p3, const char* variant, const LatteContextRegister& latteRegister);

View File

@ -1,5 +1,9 @@
#include "Cafe/HW/Latte/Renderer/RendererOuputShader.h"
#include "Cafe/HW/Latte/Renderer/Renderer.h"
#include "Cafe/HW/Latte/Core/Latte.h"
#ifdef ENABLE_OPENGL
#include "Cafe/HW/Latte/Renderer/OpenGL/OpenGLRenderer.h"
#endif
#include "config/ActiveSettings.h"
const std::string RendererOutputShader::s_copy_shader_source =
@ -246,10 +250,17 @@ fragment float4 main0(VertexOut in [[stage_in]], texture2d<float> textureSrc [[t
RendererOutputShader::RendererOutputShader(const std::string& vertex_source, const std::string& fragment_source)
{
std::string finalFragmentSrc;
if (g_renderer->GetType() == RendererAPI::Metal)
finalFragmentSrc = fragment_source;
else
finalFragmentSrc = PrependFragmentPreamble(fragment_source);
switch(g_renderer->GetType())
{
#ifdef ENABLE_METAL
case RendererAPI::Metal:
finalFragmentSrc = fragment_source;
break;
#endif
default:
finalFragmentSrc = PrependFragmentPreamble(fragment_source);
break;
}
m_vertex_shader.reset(g_renderer->shader_create(RendererShader::ShaderType::kVertex, 0, 0, vertex_source, false, false));
m_fragment_shader.reset(g_renderer->shader_create(RendererShader::ShaderType::kFragment, 0, 0, finalFragmentSrc, false, false));
@ -484,7 +495,10 @@ void main()
}
void RendererOutputShader::InitializeStatic()
{
if (g_renderer->GetType() == RendererAPI::Metal)
switch(g_renderer->GetType())
{
#ifdef ENABLE_METAL
case RendererAPI::Metal:
{
std::string vertex_source = GetMetalVertexSource(false);
std::string vertex_source_ud = GetMetalVertexSource(true);
@ -497,21 +511,17 @@ void RendererOutputShader::InitializeStatic()
s_hermit_shader = new RendererOutputShader(vertex_source, s_hermite_shader_source_mtl);
s_hermit_shader_ud = new RendererOutputShader(vertex_source_ud, s_hermite_shader_source_mtl);
break;
}
else
#endif
#ifdef ENABLE_OPENGL
case RendererAPI::OpenGL:
{
std::string vertex_source, vertex_source_ud;
// vertex shader
if (g_renderer->GetType() == RendererAPI::OpenGL)
{
vertex_source = GetOpenGlVertexSource(false);
vertex_source_ud = GetOpenGlVertexSource(true);
}
else if (g_renderer->GetType() == RendererAPI::Vulkan)
{
vertex_source = GetVulkanVertexSource(false);
vertex_source_ud = GetVulkanVertexSource(true);
}
vertex_source = GetOpenGlVertexSource(false);
vertex_source_ud = GetOpenGlVertexSource(true);
s_copy_shader = new RendererOutputShader(vertex_source, s_copy_shader_source);
s_copy_shader_ud = new RendererOutputShader(vertex_source_ud, s_copy_shader_source);
@ -520,7 +530,29 @@ void RendererOutputShader::InitializeStatic()
s_hermit_shader = new RendererOutputShader(vertex_source, s_hermite_shader_source);
s_hermit_shader_ud = new RendererOutputShader(vertex_source_ud, s_hermite_shader_source);
break;
}
#endif
#ifdef ENABLE_VULKAN
case RendererAPI::Vulkan:
{
std::string vertex_source, vertex_source_ud;
// vertex shader
vertex_source = GetVulkanVertexSource(false);
vertex_source_ud = GetVulkanVertexSource(true);
s_copy_shader = new RendererOutputShader(vertex_source, s_copy_shader_source);
s_copy_shader_ud = new RendererOutputShader(vertex_source_ud, s_copy_shader_source);
s_bicubic_shader = new RendererOutputShader(vertex_source, s_bicubic_shader_source);
s_bicubic_shader_ud = new RendererOutputShader(vertex_source_ud, s_bicubic_shader_source);
s_hermit_shader = new RendererOutputShader(vertex_source, s_hermite_shader_source);
s_hermit_shader_ud = new RendererOutputShader(vertex_source_ud, s_hermite_shader_source);
break;
}
#endif
}
}
void RendererOutputShader::ShutdownStatic()

View File

@ -9,58 +9,7 @@
#include "util/helpers/helpers.h"
#include "util/helpers/Serializer.h"
#include "Cafe/HW/Latte/Common/RegisterSerializer.h"
/* rects emulation */
void rectsEmulationGS_outputSingleVertex(std::string& gsSrc, LatteDecompilerShader* vertexShader, LatteShaderPSInputTable* psInputTable, sint32 vIdx, const LatteContextRegister& latteRegister)
{
auto parameterMask = vertexShader->outputParameterMask;
for (uint32 i = 0; i < 32; i++)
{
if ((parameterMask & (1 << i)) == 0)
continue;
sint32 vsSemanticId = psInputTable->getVertexShaderOutParamSemanticId(latteRegister.GetRawView(), i);
if (vsSemanticId < 0)
continue;
// make sure PS has matching input
if (!psInputTable->hasPSImportForSemanticId(vsSemanticId))
continue;
gsSrc.append(fmt::format("passParameterSem{}Out = passParameterSem{}In[{}];\r\n", vsSemanticId, vsSemanticId, vIdx));
}
gsSrc.append(fmt::format("gl_Position = gl_in[{}].gl_Position;\r\n", vIdx));
gsSrc.append("EmitVertex();\r\n");
}
void rectsEmulationGS_outputGeneratedVertex(std::string& gsSrc, LatteDecompilerShader* vertexShader, LatteShaderPSInputTable* psInputTable, const char* variant, const LatteContextRegister& latteRegister)
{
auto parameterMask = vertexShader->outputParameterMask;
for (uint32 i = 0; i < 32; i++)
{
if ((parameterMask & (1 << i)) == 0)
continue;
sint32 vsSemanticId = psInputTable->getVertexShaderOutParamSemanticId(latteRegister.GetRawView(), i);
if (vsSemanticId < 0)
continue;
// make sure PS has matching input
if (!psInputTable->hasPSImportForSemanticId(vsSemanticId))
continue;
gsSrc.append(fmt::format("passParameterSem{}Out = gen4thVertex{}(passParameterSem{}In[0], passParameterSem{}In[1], passParameterSem{}In[2]);\r\n", vsSemanticId, variant, vsSemanticId, vsSemanticId, vsSemanticId));
}
gsSrc.append(fmt::format("gl_Position = gen4thVertex{}(gl_in[0].gl_Position, gl_in[1].gl_Position, gl_in[2].gl_Position);\r\n", variant));
gsSrc.append("EmitVertex();\r\n");
}
void rectsEmulationGS_outputVerticesCode(std::string& gsSrc, LatteDecompilerShader* vertexShader, LatteShaderPSInputTable* psInputTable, sint32 p0, sint32 p1, sint32 p2, sint32 p3, const char* variant, const LatteContextRegister& latteRegister)
{
sint32 pList[4] = { p0, p1, p2, p3 };
for (sint32 i = 0; i < 4; i++)
{
if (pList[i] == 3)
rectsEmulationGS_outputGeneratedVertex(gsSrc, vertexShader, psInputTable, variant, latteRegister);
else
rectsEmulationGS_outputSingleVertex(gsSrc, vertexShader, psInputTable, pList[i], latteRegister);
}
}
#include "HW/Latte/Renderer/RendererCore.h"
RendererShaderVk* rectsEmulationGS_generate(LatteDecompilerShader* vertexShader, const LatteContextRegister& latteRegister)
{

View File

@ -1221,6 +1221,7 @@ void VulkanRenderer::draw_endRenderPass()
m_state.activeRenderpassFBO = nullptr;
}
// Defined in the Common renderer
void LatteDraw_handleSpecialState8_clearAsDepth();
// transfer depth buffer data to color buffer

View File

@ -1,7 +1,9 @@
#include "Cafe/GameProfile/GameProfile.h"
#include "Cafe/IOSU/legacy/iosu_crypto.h"
#include "Cafe/HW/Latte/Core/Latte.h"
#ifdef ENABLE_VULKAN
#include "Cafe/HW/Latte/Renderer/Vulkan/VulkanAPI.h"
#endif
#include "Cafe/CafeSystem.h"
#include "Cemu/Logging/CemuLogging.h"
#include "config/ActiveSettings.h"
@ -107,9 +109,12 @@ bool ActiveSettings::WaitForGX2DrawDoneEnabled()
GraphicAPI ActiveSettings::GetGraphicsAPI()
{
GraphicAPI api = g_current_game_profile->GetGraphicsAPI().value_or(GetConfig().graphic_api);
#if defined(ENABLE_VULKAN) && defined(ENABLE_OPENGL)
// check if vulkan even available
if (api == kVulkan && !g_vulkan_available)
api = kOpenGL;
#endif
return api;
}

View File

@ -144,7 +144,7 @@ XMLConfigParser CemuConfig::Load(XMLConfigParser& parser)
fullscreen_scaling = graphic.get("FullscreenScaling", kKeepAspectRatio);
async_compile = graphic.get("AsyncCompile", async_compile);
vk_accurate_barriers = graphic.get("vkAccurateBarriers", true); // this used to be "VulkanAccurateBarriers" but because we changed the default to true in 1.27.1 the option name had to be changed
#if ENABLE_METAL
#ifdef ENABLE_METAL
force_mesh_shaders = graphic.get("ForceMeshShaders", false);
#endif
@ -273,7 +273,7 @@ XMLConfigParser CemuConfig::Load(XMLConfigParser& parser)
crash_dump = debug.get("CrashDumpUnix", crash_dump);
#endif
gdb_port = debug.get("GDBPort", 1337);
#if ENABLE_METAL
#ifdef ENABLE_METAL
gpu_capture_dir = debug.get("GPUCaptureDir", "");
framebuffer_fetch = debug.get("FramebufferFetch", true);
#endif
@ -368,7 +368,7 @@ XMLConfigParser CemuConfig::Save(XMLConfigParser& parser)
graphic.set("OverrideGammaValue", overrideGammaValue);
graphic.set("UserDisplayGamma", userDisplayGamma);
graphic.set("GX2DrawdoneSync", gx2drawdone_sync);
#if ENABLE_METAL
#ifdef ENABLE_METAL
graphic.set("ForceMeshShaders", force_mesh_shaders);
#endif
//graphic.set("PrecompiledShaders", precompiled_shaders.GetValue());
@ -437,7 +437,7 @@ XMLConfigParser CemuConfig::Save(XMLConfigParser& parser)
debug.set("CrashDumpUnix", crash_dump.GetValue());
#endif
debug.set("GDBPort", gdb_port);
#if ENABLE_METAL
#ifdef ENABLE_METAL
debug.set("GPUCaptureDir", gpu_capture_dir);
debug.set("FramebufferFetch", framebuffer_fetch);
#endif

View File

@ -65,6 +65,7 @@ struct GraphicPackEntry
bool enabled = true;
};
#define GRAPHIC_API_COUNT 3
enum GraphicAPI
{
kOpenGL = 0,
@ -429,7 +430,13 @@ struct CemuConfig
ConfigValueBounds<CafeConsoleLanguage> console_language{ CafeConsoleLanguage::EN };
// graphics
#if defined(ENABLE_VULKAN)
ConfigValue<GraphicAPI> graphic_api{ kVulkan };
#elif defined(ENABLE_METAL)
ConfigValue<GraphicAPI> graphic_api{ kMetal };
#elif defined(ENABLE_OPENGL)
ConfigValue<GraphicAPI> graphic_api{ kOpenGL };
#endif
std::array<uint8, 16> legacy_graphic_device_uuid{}; // placeholder option for backwards compatibility with settings from 2.6 and before (renamed to "vkDevice")
std::array<uint8, 16> vk_graphic_device_uuid;
uint64 mtl_graphic_device_uuid{ 0 };
@ -437,7 +444,7 @@ struct CemuConfig
ConfigValue<bool> gx2drawdone_sync { true };
ConfigValue<bool> render_upside_down{ false };
ConfigValue<bool> async_compile{ true };
#if ENABLE_METAL
#ifdef ENABLE_METAL
ConfigValue<bool> force_mesh_shaders{ false };
#endif
@ -503,7 +510,7 @@ struct CemuConfig
// debug
ConfigValueBounds<CrashDump> crash_dump{ CrashDump::Disabled };
ConfigValue<uint16> gdb_port{ 1337 };
#if ENABLE_METAL
#ifdef ENABLE_METAL
ConfigValue<std::string> gpu_capture_dir{ "" };
ConfigValue<bool> framebuffer_fetch{ true };
#endif

View File

@ -1,9 +1,5 @@
add_library(CemuWxGui STATIC
canvas/IRenderCanvas.h
canvas/OpenGLCanvas.cpp
canvas/OpenGLCanvas.h
canvas/VulkanCanvas.cpp
canvas/VulkanCanvas.h
CemuApp.cpp
CemuApp.h
CemuUpdateWindow.cpp
@ -118,6 +114,20 @@ add_library(CemuWxGui STATIC
wxHelper.h
)
if (ENABLE_OPENGL)
target_sources(CemuWxGui PRIVATE
canvas/OpenGLCanvas.cpp
canvas/OpenGLCanvas.h
)
endif()
if (ENABLE_VULKAN)
target_sources(CemuWxGui PRIVATE
canvas/VulkanCanvas.cpp
canvas/VulkanCanvas.h
)
endif()
if (ENABLE_METAL)
target_sources(CemuWxGui PRIVATE
canvas/MetalCanvas.cpp

View File

@ -3,7 +3,9 @@
#include "wxgui/MainWindow.h"
#include "wxgui/wxgui.h"
#include "config/CemuConfig.h"
#ifdef ENABLE_VULKAN
#include "Cafe/HW/Latte/Renderer/Vulkan/VulkanAPI.h"
#endif
#include "Cafe/HW/Latte/Core/LatteOverlay.h"
#include "config/ActiveSettings.h"
#include "config/LaunchSettings.h"
@ -349,7 +351,9 @@ bool CemuApp::OnInit()
__fastfail(0);
}
#endif
#ifdef ENABLE_VULKAN
InitializeGlobalVulkan();
#endif
Bind(wxEVT_ACTIVATE_APP, &CemuApp::ActivateApp, this);

View File

@ -113,7 +113,7 @@ 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",
#if ENABLE_METAL
#ifdef ENABLE_METAL
"Metal"
#endif
};
@ -127,7 +127,7 @@ GameProfileWindow::GameProfileWindow(wxWindow* parent, uint64_t title_id)
m_shader_mul_accuracy->SetToolTip(_("EXPERT OPTION\nControls the accuracy of floating point multiplication in shaders.\n\nRecommended: true"));
first_row->Add(m_shader_mul_accuracy, 0, wxALL, 5);
#if ENABLE_METAL
#ifdef ENABLE_METAL
first_row->Add(new wxStaticText(panel, wxID_ANY, _("Shader fast math")), 0, wxALIGN_CENTER_VERTICAL | wxALL, 5);
wxString math_values[] = { _("false"), _("true") };
@ -296,7 +296,7 @@ void GameProfileWindow::ApplyProfile()
else
m_graphic_api->SetSelection(1 + m_game_profile.m_graphics_api.value()); // "", OpenGL, Vulkan, Metal
m_shader_mul_accuracy->SetSelection((int)m_game_profile.m_accurateShaderMul);
#if ENABLE_METAL
#ifdef ENABLE_METAL
m_shader_fast_math->SetSelection((int)m_game_profile.m_shaderFastMath);
m_metal_buffer_cache_mode->SetSelection((int)m_game_profile.m_metalBufferCacheMode);
m_position_invariance->SetSelection((int)m_game_profile.m_positionInvariance);
@ -362,7 +362,7 @@ void GameProfileWindow::SaveProfile()
m_game_profile.m_accurateShaderMul = (AccurateShaderMulOption)m_shader_mul_accuracy->GetSelection();
if (m_game_profile.m_accurateShaderMul != AccurateShaderMulOption::False && m_game_profile.m_accurateShaderMul != AccurateShaderMulOption::True)
m_game_profile.m_accurateShaderMul = AccurateShaderMulOption::True; // force a legal value
#if ENABLE_METAL
#ifdef ENABLE_METAL
m_game_profile.m_shaderFastMath = (bool)m_shader_fast_math->GetSelection();
m_game_profile.m_metalBufferCacheMode = (MetalBufferCacheMode)m_metal_buffer_cache_mode->GetSelection();
m_game_profile.m_positionInvariance = (PositionInvariance)m_position_invariance->GetSelection();

View File

@ -40,7 +40,7 @@ private:
wxChoice* m_graphic_api;
wxChoice* m_shader_mul_accuracy;
#if ENABLE_METAL
#ifdef ENABLE_METAL
wxChoice* m_shader_fast_math;
wxChoice* m_metal_buffer_cache_mode;
wxChoice* m_position_invariance;

View File

@ -27,9 +27,11 @@
#include "audio/IAudioInputAPI.h"
#ifdef ENABLE_VULKAN
#include "Cafe/HW/Latte/Renderer/Vulkan/VulkanAPI.h"
#include "Cafe/HW/Latte/Renderer/Vulkan/VulkanRenderer.h"
#if ENABLE_METAL
#endif
#ifdef ENABLE_METAL
#include "Cafe/HW/Latte/Renderer/Metal/MetalRenderer.h"
#endif
#include "Cafe/Account/Account.h"
@ -87,6 +89,7 @@ private:
IAudioInputAPI::DeviceDescriptionPtr m_description;
};
#ifdef ENABLE_VULKAN
class wxVulkanUUID : public wxClientData
{
public:
@ -97,8 +100,9 @@ public:
private:
VulkanRenderer::DeviceInfo m_device_info;
};
#endif
#if ENABLE_METAL
#ifdef ENABLE_METAL
class wxMetalUUID : public wxClientData
{
public:
@ -352,15 +356,25 @@ 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[3] = { "OpenGL" };
sint32 api_size = 0;
wxString choices[GRAPHIC_API_COUNT];
#ifdef ENABLE_OPENGL
choices[api_size++] = "OpenGL";
m_api_map.push_back(GraphicAPI::kOpenGL);
#endif
#ifdef ENABLE_VULKAN
if (g_vulkan_available)
{
choices[api_size++] = "Vulkan";
m_api_map.push_back(GraphicAPI::kVulkan);
}
#if ENABLE_METAL
choices[api_size++] = "Metal";
#endif
#ifdef ENABLE_METAL
choices[api_size++] = "Metal";
m_api_map.push_back(GraphicAPI::kMetal);
#endif
wxASSERT(api_size > 0);
m_graphic_api = new wxChoice(box, wxID_ANY, wxDefaultPosition, wxDefaultSize, api_size, choices);
m_graphic_api->SetSelection(0);
@ -400,7 +414,7 @@ wxPanel* GeneralSettings2::AddGraphicsPage(wxNotebook* notebook)
m_gx2drawdone_sync->SetToolTip(_("If synchronization is requested by the game, the emulated CPU will wait for the GPU to finish all operations.\nThis is more accurate behavior, but may cause lower performance"));
graphic_misc_row->Add(m_gx2drawdone_sync, 0, wxALL, 5);
#if ENABLE_METAL
#ifdef ENABLE_METAL
m_force_mesh_shaders = new wxCheckBox(box, wxID_ANY, _("Force mesh shaders"));
m_force_mesh_shaders->SetToolTip(_("Force mesh shaders on all GPUs that support them. Mesh shaders are disabled by default on Intel GPUs due to potential stability issues.\nMetal only"));
graphic_misc_row->Add(m_force_mesh_shaders, 0, wxALL, 5);
@ -1028,7 +1042,7 @@ wxPanel* GeneralSettings2::AddDebugPage(wxNotebook* notebook)
debug_panel_sizer->Add(debug_row, 0, wxALL | wxEXPAND, 5);
}
#if ENABLE_METAL
#ifdef ENABLE_METAL
{
auto* debug_row = new wxFlexGridSizer(0, 2, 0, 0);
debug_row->SetFlexibleDirection(wxBOTH);
@ -1216,9 +1230,10 @@ void GeneralSettings2::StoreConfig()
}
// graphics
config.graphic_api = (GraphicAPI)m_graphic_api->GetSelection();
config.graphic_api = m_api_map[m_graphic_api->GetSelection()];
selection = m_graphic_device->GetSelection();
#ifdef ENABLE_VULKAN
if (config.graphic_api == GraphicAPI::kVulkan)
{
if (selection != wxNOT_FOUND)
@ -1232,25 +1247,26 @@ void GeneralSettings2::StoreConfig()
else
config.vk_graphic_device_uuid = {};
}
#if ENABLE_METAL
else if (config.graphic_api == GraphicAPI::kMetal)
#endif
#ifdef ENABLE_METAL
if (config.graphic_api == GraphicAPI::kMetal)
{
if (selection != wxNOT_FOUND)
{
const auto* info = (wxMetalUUID*)m_graphic_device->GetClientObject(selection);
if (info)
config.mtl_graphic_device_uuid = info->GetDeviceInfo().uuid;
else
config.mtl_graphic_device_uuid = {};
}
else
config.mtl_graphic_device_uuid = {};
if (selection != wxNOT_FOUND)
{
const auto* info = (wxMetalUUID*)m_graphic_device->GetClientObject(selection);
if (info)
config.mtl_graphic_device_uuid = info->GetDeviceInfo().uuid;
else
config.mtl_graphic_device_uuid = {};
}
else
config.mtl_graphic_device_uuid = {};
}
#endif
config.gx2drawdone_sync = m_gx2drawdone_sync->IsChecked();
#if ENABLE_METAL
#ifdef ENABLE_METAL
config.force_mesh_shaders = m_force_mesh_shaders->IsChecked();
#endif
config.async_compile = m_async_compile->IsChecked();
@ -1281,7 +1297,7 @@ void GeneralSettings2::StoreConfig()
// debug
config.crash_dump = (CrashDump)m_crash_dump->GetSelection();
config.gdb_port = m_gdb_port->GetValue();
#if ENABLE_METAL
#ifdef ENABLE_METAL
config.gpu_capture_dir = m_gpu_capture_dir->GetValue().utf8_string();
config.framebuffer_fetch = m_framebuffer_fetch->IsChecked();
#endif
@ -1721,7 +1737,12 @@ void GeneralSettings2::HandleGraphicsApiSelection()
selection = GetConfig().vsync;
m_vsync->Clear();
if (m_graphic_api->GetSelection() == 0)
auto api = m_api_map[m_graphic_api->GetSelection()];
switch (api)
{
#ifdef ENABLE_OPENGL
case GraphicAPI::kOpenGL:
{
// OpenGL
m_vsync->AppendString(_("Off"));
@ -1736,16 +1757,19 @@ void GeneralSettings2::HandleGraphicsApiSelection()
m_gx2drawdone_sync->Enable();
m_async_compile->Disable();
#if ENABLE_METAL
#ifdef ENABLE_METAL
m_force_mesh_shaders->Disable();
#endif
break;
}
else if (m_graphic_api->GetSelection() == 1)
#endif
#ifdef ENABLE_VULKAN
case GraphicAPI::kVulkan:
{
// Vulkan
m_gx2drawdone_sync->Disable();
m_async_compile->Enable();
#if ENABLE_METAL
#ifdef ENABLE_METAL
m_force_mesh_shaders->Disable();
#endif
@ -1779,9 +1803,11 @@ void GeneralSettings2::HandleGraphicsApiSelection()
}
}
}
break;
}
#if ENABLE_METAL
else
#endif
#ifdef ENABLE_METAL
case GraphicAPI::kMetal:
{
// Metal
m_gx2drawdone_sync->Disable();
@ -1815,8 +1841,10 @@ void GeneralSettings2::HandleGraphicsApiSelection()
}
}
}
break;
}
#endif
}
}
void GeneralSettings2::ApplyConfig()
@ -1870,7 +1898,14 @@ void GeneralSettings2::ApplyConfig()
}
// graphics
m_graphic_api->SetSelection(config.graphic_api);
for (int i = 0; i < (int)m_api_map.size(); ++i)
{
if (m_api_map[i] == config.graphic_api)
{
m_graphic_api->SetSelection(i);
break;
}
}
m_vsync->SetSelection(config.vsync);
m_overrideGamma->SetValue(config.overrideAppGammaPreference);
m_overrideGammaValue->SetValue(config.overrideGammaValue);
@ -1883,7 +1918,7 @@ void GeneralSettings2::ApplyConfig()
}
m_async_compile->SetValue(config.async_compile);
m_gx2drawdone_sync->SetValue(config.gx2drawdone_sync);
#if ENABLE_METAL
#ifdef ENABLE_METAL
m_force_mesh_shaders->SetValue(config.force_mesh_shaders);
#endif
m_upscale_filter->SetSelection(config.upscale_filter);
@ -2022,7 +2057,7 @@ void GeneralSettings2::ApplyConfig()
// debug
m_crash_dump->SetSelection((int)config.crash_dump.GetValue());
m_gdb_port->SetValue(config.gdb_port.GetValue());
#if ENABLE_METAL
#ifdef ENABLE_METAL
m_gpu_capture_dir->SetValue(wxString::FromUTF8(config.gpu_capture_dir.GetValue()));
m_framebuffer_fetch->SetValue(config.framebuffer_fetch);
#endif

View File

@ -1,4 +1,5 @@
#pragma once
#include "config/CemuConfig.h"
#include <wx/collpane.h>
#include <wx/propgrid/propgrid.h>
#include <Cafe/Account/Account.h>
@ -36,6 +37,7 @@ private:
bool m_game_launched;
bool m_has_account_change = false; // keep track of dirty state of accounts
std::vector<GraphicAPI> m_api_map; // map from dropdown index to GraphicsAPISetting, used in HandleGraphicsApiSelection
wxPanel* AddGeneralPage(wxNotebook* notebook);
@ -71,7 +73,7 @@ private:
wxCheckBox* m_userDisplayisSRGB;
wxCheckBox *m_async_compile, *m_gx2drawdone_sync;
#if ENABLE_METAL
#ifdef ENABLE_METAL
wxCheckBox *m_force_mesh_shaders;
#endif
wxRadioBox* m_upscale_filter, *m_downscale_filter, *m_fullscreen_scaling;
@ -99,7 +101,7 @@ private:
// Debug
wxChoice* m_crash_dump;
wxSpinCtrl* m_gdb_port;
#if ENABLE_METAL
#ifdef ENABLE_METAL
wxTextCtrl* m_gpu_capture_dir;
wxCheckBox* m_framebuffer_fetch;
#endif

View File

@ -11,9 +11,13 @@
#include "wxgui/windows/TextureRelationViewer/TextureRelationWindow.h"
#include "wxgui/windows/PPCThreadsViewer/DebugPPCThreadsWindow.h"
#include "AudioDebuggerWindow.h"
#ifdef ENABLE_OPENGL
#include "wxgui/canvas/OpenGLCanvas.h"
#endif
#ifdef ENABLE_VULKAN
#include "wxgui/canvas/VulkanCanvas.h"
#if ENABLE_METAL
#endif
#ifdef ENABLE_METAL
#include "wxgui/canvas/MetalCanvas.h"
#endif
#include "Cafe/OS/libs/nfc/nfc.h"
@ -42,7 +46,9 @@
#include "wxgui/DownloadGraphicPacksWindow.h"
#include "wxgui/GettingStartedDialog.h"
#include "wxgui/helpers/wxHelpers.h"
#ifdef ENABLE_VULKAN
#include "Cafe/HW/Latte/Renderer/Vulkan/VsyncDriver.h"
#endif
#include "wxgui/input/InputSettings2.h"
#include "wxgui/input/HotkeySettings.h"
#include "input/InputManager.h"
@ -66,7 +72,7 @@
#include "gamemode_client.h"
#endif
#if ENABLE_METAL
#ifdef ENABLE_METAL
#include "Cafe/HW/Latte/Renderer/Metal/MetalRenderer.h"
#endif
@ -1037,7 +1043,7 @@ void MainWindow::OnDebugSetting(wxCommandEvent& event)
if(!GetConfig().vk_accurate_barriers)
wxMessageBox(_("Warning: Disabling the accurate barriers option will lead to flickering graphics but may improve performance. It is highly recommended to leave it turned on."), _("Accurate barriers are off"), wxOK);
}
#if ENABLE_METAL
#ifdef ENABLE_METAL
else if (event.GetId() == MAINFRAME_MENU_ID_DEBUG_GPU_CAPTURE)
{
cemu_assert_debug(g_renderer->GetType() == RendererAPI::Metal);
@ -1601,14 +1607,29 @@ void MainWindow::CreateCanvas()
this->GetSizer()->Add(m_game_panel, 1, wxEXPAND);
// create canvas
if (ActiveSettings::GetGraphicsAPI() == kVulkan)
m_render_canvas = new VulkanCanvas(m_game_panel, wxSize(1280, 720), true);
else if (ActiveSettings::GetGraphicsAPI() == kOpenGL)
switch (ActiveSettings::GetGraphicsAPI())
{
case kOpenGL:
#ifdef ENABLE_OPENGL
m_render_canvas = GLCanvas_Create(m_game_panel, wxSize(1280, 720), true);
#if ENABLE_METAL
else
m_render_canvas = new MetalCanvas(m_game_panel, wxSize(1280, 720), true);
break;
#endif
case kVulkan:
#ifdef ENABLE_VULKAN
m_render_canvas = new VulkanCanvas(m_game_panel, wxSize(1280, 720), true);
break;
#endif
case kMetal:
#ifdef ENABLE_METAL
m_render_canvas = new MetalCanvas(m_game_panel, wxSize(1280, 720), true);
break;
#endif
default:
cemu_assert(false && "Invalid graphics API selected");
break;
}
cemu_assert(m_render_canvas != nullptr);
// mouse events
m_render_canvas->Bind(wxEVT_MOTION, &MainWindow::OnMouseMove, this);
@ -1670,7 +1691,9 @@ void MainWindow::OnSizeEvent(wxSizeEvent& event)
event.Skip();
#ifdef ENABLE_VULKAN
VsyncDriver_notifyWindowPosChanged();
#endif
}
void MainWindow::OnDPIChangedEvent(wxDPIChangedEvent& event)
@ -1691,7 +1714,9 @@ void MainWindow::OnMove(wxMoveEvent& event)
if (m_debugger_window && m_debugger_window->IsShown())
m_debugger_window->OnParentMove(GetPosition(), GetSize());
#ifdef ENABLE_VULKAN
VsyncDriver_notifyWindowPosChanged();
#endif
}
void MainWindow::OnDebuggerClose(wxCloseEvent& event)
@ -2345,7 +2370,7 @@ void MainWindow::RecreateMenu()
auto accurateBarriers = debugMenu->AppendCheckItem(MAINFRAME_MENU_ID_DEBUG_VK_ACCURATE_BARRIERS, _("&Accurate barriers (Vulkan)"));
accurateBarriers->Check(GetConfig().vk_accurate_barriers);
#if ENABLE_METAL
#ifdef ENABLE_METAL
auto gpuCapture = debugMenu->Append(MAINFRAME_MENU_ID_DEBUG_GPU_CAPTURE, _("&GPU capture (Metal)"));
gpuCapture->Enable(m_game_launched && g_renderer->GetType() == RendererAPI::Metal);
#endif

View File

@ -6,9 +6,13 @@
#include "config/ActiveSettings.h"
#include "Cafe/OS/libs/swkbd/swkbd.h"
#ifdef ENABLE_OPENGL
#include "wxgui/canvas/OpenGLCanvas.h"
#endif
#ifdef ENABLE_VULKAN
#include "wxgui/canvas/VulkanCanvas.h"
#if ENABLE_METAL
#endif
#ifdef ENABLE_METAL
#include "wxgui/canvas/MetalCanvas.h"
#endif
#include "config/CemuConfig.h"
@ -76,15 +80,24 @@ void PadViewFrame::InitializeRenderCanvas()
auto sizer = new wxBoxSizer(wxVERTICAL);
{
if (ActiveSettings::GetGraphicsAPI() == kVulkan)
{
#ifdef ENABLE_VULKAN
m_render_canvas = new VulkanCanvas(this, wxSize(854, 480), false);
#endif
}
else if (ActiveSettings::GetGraphicsAPI() == kOpenGL)
{
#ifdef ENABLE_OPENGL
m_render_canvas = GLCanvas_Create(this, wxSize(854, 480), false);
#if ENABLE_METAL
#endif
}
#ifdef ENABLE_METAL
else
m_render_canvas = new MetalCanvas(this, wxSize(854, 480), false);
#endif
sizer->Add(m_render_canvas, 1, wxEXPAND, 0, nullptr);
}
cemu_assert(m_render_canvas != nullptr);
SetSizer(sizer);
Layout();

View File

@ -95,13 +95,17 @@ void WindowSystem::UpdateWindowTitles(bool isIdle, bool isLoading, double fps)
{
switch (g_renderer->GetType())
{
#ifdef ENABLE_OPENGL
case RendererAPI::OpenGL:
renderer = "[OpenGL]";
break;
#endif
#ifdef ENABLE_VULKAN
case RendererAPI::Vulkan:
renderer = "[Vulkan]";
break;
#if ENABLE_METAL
#endif
#ifdef ENABLE_METAL
case RendererAPI::Metal:
renderer = "[Metal]";
break;

View File

@ -1,12 +1,22 @@
add_library(imguiImpl
imgui_impl_opengl3.cpp
imgui_impl_opengl3.h
imgui_impl_vulkan.cpp
imgui_impl_vulkan.h
imgui_extension.cpp
imgui_extension.h
)
if (ENABLE_OPENGL)
target_sources(imguiImpl PRIVATE
imgui_impl_opengl3.cpp
imgui_impl_opengl3.h
)
endif()
if (ENABLE_VULKAN)
target_sources(imguiImpl PRIVATE
imgui_impl_vulkan.cpp
imgui_impl_vulkan.h
)
endif()
if (ENABLE_METAL)
target_sources(imguiImpl PRIVATE
imgui_impl_metal.mm

View File

@ -2,9 +2,13 @@
#include "WindowSystem.h"
#include "Cafe/HW/Latte/Renderer/Renderer.h"
#include "resource/IconsFontAwesome5.h"
#include "imgui_impl_opengl3.h"
#include "resource/resource.h"
#ifdef ENABLE_OPENGL
#include "imgui_impl_opengl3.h"
#endif
#ifdef ENABLE_VULKAN
#include "imgui_impl_vulkan.h"
#endif
#include "input/InputManager.h"
// <imgui_internal.h>

View File

@ -19,7 +19,6 @@
#include "util/helpers/helpers.h"
#include "config/ActiveSettings.h"
#include "Cafe/HW/Latte/Renderer/Vulkan/VsyncDriver.h"
#include "Cafe/IOSU/legacy/iosu_crypto.h"
#include "Cafe/OS/libs/vpad/vpad.h"
@ -65,6 +64,7 @@ void _putenvSafe(const char* c)
_putenv(s->c_str());
}
#ifdef ENABLE_OPENGL
void reconfigureGLDrivers()
{
// reconfigure GL drivers to store
@ -85,12 +85,15 @@ void reconfigureGLDrivers()
_putenvSafe("__GL_SHADER_DISK_CACHE_SKIP_CLEANUP=1");
}
#endif
#ifdef ENABLE_VULKAN
void reconfigureVkDrivers()
{
_putenvSafe("DISABLE_LAYER_AMD_SWITCHABLE_GRAPHICS_1=1");
_putenvSafe("DISABLE_VK_LAYER_VALVE_steam_fossilize_1=1");
}
#endif
void WindowsInitCwd()
{
@ -109,8 +112,12 @@ void WindowsInitCwd()
void CemuCommonInit()
{
#ifdef ENABLE_OPENGL
reconfigureGLDrivers();
#endif
#ifdef ENABLE_VULKAN
reconfigureVkDrivers();
#endif
// crypto init
AES128_init();
// init PPC timer
@ -258,7 +265,7 @@ int main(int argc, char* argv[])
int BreathOfTheWildChildProcessMain();
int main(int argc, char *argv[])
{
#if BOOST_OS_LINUX
#if BOOST_OS_LINUX && defined(ENABLE_VULKAN)
if (getenv("CEMU_DETECT_RADV") != nullptr)
return BreathOfTheWildChildProcessMain();
#endif