diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/core/core_timing_util.cpp | 8 | ||||
| -rw-r--r-- | src/core/frontend/emu_window.h | 3 | ||||
| -rw-r--r-- | src/core/loader/nso.cpp | 2 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_device.cpp | 1 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_shader_cache.cpp | 3 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_shader_decompiler.cpp | 30 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_shader_gen.cpp | 9 | ||||
| -rw-r--r-- | src/video_core/renderer_vulkan/vk_shader_decompiler.cpp | 18 | ||||
| -rw-r--r-- | src/video_core/shader/decode/other.cpp | 42 | ||||
| -rw-r--r-- | src/video_core/shader/shader_ir.h | 8 | ||||
| -rw-r--r-- | src/yuzu/bootmanager.cpp | 3 | ||||
| -rw-r--r-- | src/yuzu/bootmanager.h | 3 | ||||
| -rw-r--r-- | src/yuzu_cmd/CMakeLists.txt | 2 | ||||
| -rw-r--r-- | src/yuzu_cmd/emu_window/emu_window_sdl2.cpp | 174 | ||||
| -rw-r--r-- | src/yuzu_cmd/emu_window/emu_window_sdl2.h | 26 | ||||
| -rw-r--r-- | src/yuzu_cmd/emu_window/emu_window_sdl2_gl.cpp | 154 | ||||
| -rw-r--r-- | src/yuzu_cmd/emu_window/emu_window_sdl2_gl.h | 34 | ||||
| -rw-r--r-- | src/yuzu_cmd/yuzu.cpp | 3 |
18 files changed, 303 insertions, 220 deletions
diff --git a/src/core/core_timing_util.cpp b/src/core/core_timing_util.cpp index 7942f30d6..c0f08cddb 100644 --- a/src/core/core_timing_util.cpp +++ b/src/core/core_timing_util.cpp | |||
| @@ -14,11 +14,11 @@ namespace Core::Timing { | |||
| 14 | constexpr u64 MAX_VALUE_TO_MULTIPLY = std::numeric_limits<s64>::max() / BASE_CLOCK_RATE; | 14 | constexpr u64 MAX_VALUE_TO_MULTIPLY = std::numeric_limits<s64>::max() / BASE_CLOCK_RATE; |
| 15 | 15 | ||
| 16 | s64 usToCycles(s64 us) { | 16 | s64 usToCycles(s64 us) { |
| 17 | if (us / 1000000 > MAX_VALUE_TO_MULTIPLY) { | 17 | if (static_cast<u64>(us / 1000000) > MAX_VALUE_TO_MULTIPLY) { |
| 18 | LOG_ERROR(Core_Timing, "Integer overflow, use max value"); | 18 | LOG_ERROR(Core_Timing, "Integer overflow, use max value"); |
| 19 | return std::numeric_limits<s64>::max(); | 19 | return std::numeric_limits<s64>::max(); |
| 20 | } | 20 | } |
| 21 | if (us > MAX_VALUE_TO_MULTIPLY) { | 21 | if (static_cast<u64>(us) > MAX_VALUE_TO_MULTIPLY) { |
| 22 | LOG_DEBUG(Core_Timing, "Time very big, do rounding"); | 22 | LOG_DEBUG(Core_Timing, "Time very big, do rounding"); |
| 23 | return BASE_CLOCK_RATE * (us / 1000000); | 23 | return BASE_CLOCK_RATE * (us / 1000000); |
| 24 | } | 24 | } |
| @@ -38,11 +38,11 @@ s64 usToCycles(u64 us) { | |||
| 38 | } | 38 | } |
| 39 | 39 | ||
| 40 | s64 nsToCycles(s64 ns) { | 40 | s64 nsToCycles(s64 ns) { |
| 41 | if (ns / 1000000000 > MAX_VALUE_TO_MULTIPLY) { | 41 | if (static_cast<u64>(ns / 1000000000) > MAX_VALUE_TO_MULTIPLY) { |
| 42 | LOG_ERROR(Core_Timing, "Integer overflow, use max value"); | 42 | LOG_ERROR(Core_Timing, "Integer overflow, use max value"); |
| 43 | return std::numeric_limits<s64>::max(); | 43 | return std::numeric_limits<s64>::max(); |
| 44 | } | 44 | } |
| 45 | if (ns > MAX_VALUE_TO_MULTIPLY) { | 45 | if (static_cast<u64>(ns) > MAX_VALUE_TO_MULTIPLY) { |
| 46 | LOG_DEBUG(Core_Timing, "Time very big, do rounding"); | 46 | LOG_DEBUG(Core_Timing, "Time very big, do rounding"); |
| 47 | return BASE_CLOCK_RATE * (ns / 1000000000); | 47 | return BASE_CLOCK_RATE * (ns / 1000000000); |
| 48 | } | 48 | } |
diff --git a/src/core/frontend/emu_window.h b/src/core/frontend/emu_window.h index e2c290dc1..4a9912641 100644 --- a/src/core/frontend/emu_window.h +++ b/src/core/frontend/emu_window.h | |||
| @@ -169,8 +169,7 @@ private: | |||
| 169 | * For the request to be honored, EmuWindow implementations will usually reimplement this | 169 | * For the request to be honored, EmuWindow implementations will usually reimplement this |
| 170 | * function. | 170 | * function. |
| 171 | */ | 171 | */ |
| 172 | virtual void OnMinimalClientAreaChangeRequest( | 172 | virtual void OnMinimalClientAreaChangeRequest(std::pair<unsigned, unsigned>) { |
| 173 | const std::pair<unsigned, unsigned>& minimal_size) { | ||
| 174 | // By default, ignore this request and do nothing. | 173 | // By default, ignore this request and do nothing. |
| 175 | } | 174 | } |
| 176 | 175 | ||
diff --git a/src/core/loader/nso.cpp b/src/core/loader/nso.cpp index 8592b1f44..62c090353 100644 --- a/src/core/loader/nso.cpp +++ b/src/core/loader/nso.cpp | |||
| @@ -39,7 +39,7 @@ std::vector<u8> DecompressSegment(const std::vector<u8>& compressed_data, | |||
| 39 | const std::vector<u8> uncompressed_data = | 39 | const std::vector<u8> uncompressed_data = |
| 40 | Common::Compression::DecompressDataLZ4(compressed_data, header.size); | 40 | Common::Compression::DecompressDataLZ4(compressed_data, header.size); |
| 41 | 41 | ||
| 42 | ASSERT_MSG(uncompressed_data.size() == static_cast<int>(header.size), "{} != {}", header.size, | 42 | ASSERT_MSG(uncompressed_data.size() == header.size, "{} != {}", header.size, |
| 43 | uncompressed_data.size()); | 43 | uncompressed_data.size()); |
| 44 | 44 | ||
| 45 | return uncompressed_data; | 45 | return uncompressed_data; |
diff --git a/src/video_core/renderer_opengl/gl_device.cpp b/src/video_core/renderer_opengl/gl_device.cpp index 38497678a..1d1581f49 100644 --- a/src/video_core/renderer_opengl/gl_device.cpp +++ b/src/video_core/renderer_opengl/gl_device.cpp | |||
| @@ -35,6 +35,7 @@ Device::Device(std::nullptr_t) { | |||
| 35 | 35 | ||
| 36 | bool Device::TestVariableAoffi() { | 36 | bool Device::TestVariableAoffi() { |
| 37 | const GLchar* AOFFI_TEST = R"(#version 430 core | 37 | const GLchar* AOFFI_TEST = R"(#version 430 core |
| 38 | // This is a unit test, please ignore me on apitrace bug reports. | ||
| 38 | uniform sampler2D tex; | 39 | uniform sampler2D tex; |
| 39 | uniform ivec2 variable_offset; | 40 | uniform ivec2 variable_offset; |
| 40 | void main() { | 41 | void main() { |
diff --git a/src/video_core/renderer_opengl/gl_shader_cache.cpp b/src/video_core/renderer_opengl/gl_shader_cache.cpp index 7ee1c99c0..d66252224 100644 --- a/src/video_core/renderer_opengl/gl_shader_cache.cpp +++ b/src/video_core/renderer_opengl/gl_shader_cache.cpp | |||
| @@ -170,7 +170,8 @@ GLShader::ProgramResult CreateProgram(const Device& device, Maxwell::ShaderProgr | |||
| 170 | CachedProgram SpecializeShader(const std::string& code, const GLShader::ShaderEntries& entries, | 170 | CachedProgram SpecializeShader(const std::string& code, const GLShader::ShaderEntries& entries, |
| 171 | Maxwell::ShaderProgram program_type, BaseBindings base_bindings, | 171 | Maxwell::ShaderProgram program_type, BaseBindings base_bindings, |
| 172 | GLenum primitive_mode, bool hint_retrievable = false) { | 172 | GLenum primitive_mode, bool hint_retrievable = false) { |
| 173 | std::string source = "#version 430 core\n"; | 173 | std::string source = "#version 430 core\n" |
| 174 | "#extension GL_ARB_separate_shader_objects : enable\n\n"; | ||
| 174 | source += fmt::format("#define EMULATION_UBO_BINDING {}\n", base_bindings.cbuf++); | 175 | source += fmt::format("#define EMULATION_UBO_BINDING {}\n", base_bindings.cbuf++); |
| 175 | 176 | ||
| 176 | for (const auto& cbuf : entries.const_buffers) { | 177 | for (const auto& cbuf : entries.const_buffers) { |
diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp index 6d4658c8b..e9f8d40db 100644 --- a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp +++ b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp | |||
| @@ -31,6 +31,8 @@ using Tegra::Shader::IpaInterpMode; | |||
| 31 | using Tegra::Shader::IpaMode; | 31 | using Tegra::Shader::IpaMode; |
| 32 | using Tegra::Shader::IpaSampleMode; | 32 | using Tegra::Shader::IpaSampleMode; |
| 33 | using Tegra::Shader::Register; | 33 | using Tegra::Shader::Register; |
| 34 | |||
| 35 | using namespace std::string_literals; | ||
| 34 | using namespace VideoCommon::Shader; | 36 | using namespace VideoCommon::Shader; |
| 35 | 37 | ||
| 36 | using Maxwell = Tegra::Engines::Maxwell3D::Regs; | 38 | using Maxwell = Tegra::Engines::Maxwell3D::Regs; |
| @@ -93,11 +95,9 @@ private: | |||
| 93 | }; | 95 | }; |
| 94 | 96 | ||
| 95 | /// Generates code to use for a swizzle operation. | 97 | /// Generates code to use for a swizzle operation. |
| 96 | std::string GetSwizzle(u32 elem) { | 98 | constexpr const char* GetSwizzle(u32 element) { |
| 97 | ASSERT(elem <= 3); | 99 | constexpr std::array<const char*, 4> swizzle = {".x", ".y", ".z", ".w"}; |
| 98 | std::string swizzle = "."; | 100 | return swizzle.at(element); |
| 99 | swizzle += "xyzw"[elem]; | ||
| 100 | return swizzle; | ||
| 101 | } | 101 | } |
| 102 | 102 | ||
| 103 | /// Translate topology | 103 | /// Translate topology |
| @@ -636,7 +636,7 @@ private: | |||
| 636 | if (stage != ShaderStage::Fragment) { | 636 | if (stage != ShaderStage::Fragment) { |
| 637 | return GeometryPass("position") + GetSwizzle(element); | 637 | return GeometryPass("position") + GetSwizzle(element); |
| 638 | } else { | 638 | } else { |
| 639 | return element == 3 ? "1.0f" : "gl_FragCoord" + GetSwizzle(element); | 639 | return element == 3 ? "1.0f" : ("gl_FragCoord"s + GetSwizzle(element)); |
| 640 | } | 640 | } |
| 641 | case Attribute::Index::PointCoord: | 641 | case Attribute::Index::PointCoord: |
| 642 | switch (element) { | 642 | switch (element) { |
| @@ -921,7 +921,7 @@ private: | |||
| 921 | target = [&]() -> std::string { | 921 | target = [&]() -> std::string { |
| 922 | switch (const auto attribute = abuf->GetIndex(); abuf->GetIndex()) { | 922 | switch (const auto attribute = abuf->GetIndex(); abuf->GetIndex()) { |
| 923 | case Attribute::Index::Position: | 923 | case Attribute::Index::Position: |
| 924 | return "position" + GetSwizzle(abuf->GetElement()); | 924 | return "position"s + GetSwizzle(abuf->GetElement()); |
| 925 | case Attribute::Index::PointSize: | 925 | case Attribute::Index::PointSize: |
| 926 | return "gl_PointSize"; | 926 | return "gl_PointSize"; |
| 927 | case Attribute::Index::ClipDistances0123: | 927 | case Attribute::Index::ClipDistances0123: |
| @@ -1526,6 +1526,16 @@ private: | |||
| 1526 | return "uintBitsToFloat(config_pack[2])"; | 1526 | return "uintBitsToFloat(config_pack[2])"; |
| 1527 | } | 1527 | } |
| 1528 | 1528 | ||
| 1529 | template <u32 element> | ||
| 1530 | std::string LocalInvocationId(Operation) { | ||
| 1531 | return "utof(gl_LocalInvocationID"s + GetSwizzle(element) + ')'; | ||
| 1532 | } | ||
| 1533 | |||
| 1534 | template <u32 element> | ||
| 1535 | std::string WorkGroupId(Operation) { | ||
| 1536 | return "utof(gl_WorkGroupID"s + GetSwizzle(element) + ')'; | ||
| 1537 | } | ||
| 1538 | |||
| 1529 | static constexpr OperationDecompilersArray operation_decompilers = { | 1539 | static constexpr OperationDecompilersArray operation_decompilers = { |
| 1530 | &GLSLDecompiler::Assign, | 1540 | &GLSLDecompiler::Assign, |
| 1531 | 1541 | ||
| @@ -1665,6 +1675,12 @@ private: | |||
| 1665 | &GLSLDecompiler::EndPrimitive, | 1675 | &GLSLDecompiler::EndPrimitive, |
| 1666 | 1676 | ||
| 1667 | &GLSLDecompiler::YNegate, | 1677 | &GLSLDecompiler::YNegate, |
| 1678 | &GLSLDecompiler::LocalInvocationId<0>, | ||
| 1679 | &GLSLDecompiler::LocalInvocationId<1>, | ||
| 1680 | &GLSLDecompiler::LocalInvocationId<2>, | ||
| 1681 | &GLSLDecompiler::WorkGroupId<0>, | ||
| 1682 | &GLSLDecompiler::WorkGroupId<1>, | ||
| 1683 | &GLSLDecompiler::WorkGroupId<2>, | ||
| 1668 | }; | 1684 | }; |
| 1669 | 1685 | ||
| 1670 | std::string GetRegister(u32 index) const { | 1686 | std::string GetRegister(u32 index) const { |
diff --git a/src/video_core/renderer_opengl/gl_shader_gen.cpp b/src/video_core/renderer_opengl/gl_shader_gen.cpp index 7ab0b4553..d2bb705a9 100644 --- a/src/video_core/renderer_opengl/gl_shader_gen.cpp +++ b/src/video_core/renderer_opengl/gl_shader_gen.cpp | |||
| @@ -19,8 +19,7 @@ static constexpr u32 PROGRAM_OFFSET{10}; | |||
| 19 | ProgramResult GenerateVertexShader(const Device& device, const ShaderSetup& setup) { | 19 | ProgramResult GenerateVertexShader(const Device& device, const ShaderSetup& setup) { |
| 20 | const std::string id = fmt::format("{:016x}", setup.program.unique_identifier); | 20 | const std::string id = fmt::format("{:016x}", setup.program.unique_identifier); |
| 21 | 21 | ||
| 22 | std::string out = "#extension GL_ARB_separate_shader_objects : enable\n\n"; | 22 | std::string out = "// Shader Unique Id: VS" + id + "\n\n"; |
| 23 | out += "// Shader Unique Id: VS" + id + "\n\n"; | ||
| 24 | out += GetCommonDeclarations(); | 23 | out += GetCommonDeclarations(); |
| 25 | 24 | ||
| 26 | out += R"( | 25 | out += R"( |
| @@ -82,8 +81,7 @@ void main() { | |||
| 82 | ProgramResult GenerateGeometryShader(const Device& device, const ShaderSetup& setup) { | 81 | ProgramResult GenerateGeometryShader(const Device& device, const ShaderSetup& setup) { |
| 83 | const std::string id = fmt::format("{:016x}", setup.program.unique_identifier); | 82 | const std::string id = fmt::format("{:016x}", setup.program.unique_identifier); |
| 84 | 83 | ||
| 85 | std::string out = "#extension GL_ARB_separate_shader_objects : enable\n\n"; | 84 | std::string out = "// Shader Unique Id: GS" + id + "\n\n"; |
| 86 | out += "// Shader Unique Id: GS" + id + "\n\n"; | ||
| 87 | out += GetCommonDeclarations(); | 85 | out += GetCommonDeclarations(); |
| 88 | 86 | ||
| 89 | out += R"( | 87 | out += R"( |
| @@ -113,8 +111,7 @@ void main() { | |||
| 113 | ProgramResult GenerateFragmentShader(const Device& device, const ShaderSetup& setup) { | 111 | ProgramResult GenerateFragmentShader(const Device& device, const ShaderSetup& setup) { |
| 114 | const std::string id = fmt::format("{:016x}", setup.program.unique_identifier); | 112 | const std::string id = fmt::format("{:016x}", setup.program.unique_identifier); |
| 115 | 113 | ||
| 116 | std::string out = "#extension GL_ARB_separate_shader_objects : enable\n\n"; | 114 | std::string out = "// Shader Unique Id: FS" + id + "\n\n"; |
| 117 | out += "// Shader Unique Id: FS" + id + "\n\n"; | ||
| 118 | out += GetCommonDeclarations(); | 115 | out += GetCommonDeclarations(); |
| 119 | 116 | ||
| 120 | out += R"( | 117 | out += R"( |
diff --git a/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp b/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp index b61a6d170..a5b25aeff 100644 --- a/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp +++ b/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp | |||
| @@ -1035,6 +1035,18 @@ private: | |||
| 1035 | return {}; | 1035 | return {}; |
| 1036 | } | 1036 | } |
| 1037 | 1037 | ||
| 1038 | template <u32 element> | ||
| 1039 | Id LocalInvocationId(Operation) { | ||
| 1040 | UNIMPLEMENTED(); | ||
| 1041 | return {}; | ||
| 1042 | } | ||
| 1043 | |||
| 1044 | template <u32 element> | ||
| 1045 | Id WorkGroupId(Operation) { | ||
| 1046 | UNIMPLEMENTED(); | ||
| 1047 | return {}; | ||
| 1048 | } | ||
| 1049 | |||
| 1038 | Id DeclareBuiltIn(spv::BuiltIn builtin, spv::StorageClass storage, Id type, | 1050 | Id DeclareBuiltIn(spv::BuiltIn builtin, spv::StorageClass storage, Id type, |
| 1039 | const std::string& name) { | 1051 | const std::string& name) { |
| 1040 | const Id id = OpVariable(type, storage); | 1052 | const Id id = OpVariable(type, storage); |
| @@ -1291,6 +1303,12 @@ private: | |||
| 1291 | &SPIRVDecompiler::EndPrimitive, | 1303 | &SPIRVDecompiler::EndPrimitive, |
| 1292 | 1304 | ||
| 1293 | &SPIRVDecompiler::YNegate, | 1305 | &SPIRVDecompiler::YNegate, |
| 1306 | &SPIRVDecompiler::LocalInvocationId<0>, | ||
| 1307 | &SPIRVDecompiler::LocalInvocationId<1>, | ||
| 1308 | &SPIRVDecompiler::LocalInvocationId<2>, | ||
| 1309 | &SPIRVDecompiler::WorkGroupId<0>, | ||
| 1310 | &SPIRVDecompiler::WorkGroupId<1>, | ||
| 1311 | &SPIRVDecompiler::WorkGroupId<2>, | ||
| 1294 | }; | 1312 | }; |
| 1295 | 1313 | ||
| 1296 | const ShaderIR& ir; | 1314 | const ShaderIR& ir; |
diff --git a/src/video_core/shader/decode/other.cpp b/src/video_core/shader/decode/other.cpp index ca7af72e1..a6c123573 100644 --- a/src/video_core/shader/decode/other.cpp +++ b/src/video_core/shader/decode/other.cpp | |||
| @@ -14,6 +14,7 @@ using Tegra::Shader::ConditionCode; | |||
| 14 | using Tegra::Shader::Instruction; | 14 | using Tegra::Shader::Instruction; |
| 15 | using Tegra::Shader::OpCode; | 15 | using Tegra::Shader::OpCode; |
| 16 | using Tegra::Shader::Register; | 16 | using Tegra::Shader::Register; |
| 17 | using Tegra::Shader::SystemVariable; | ||
| 17 | 18 | ||
| 18 | u32 ShaderIR::DecodeOther(NodeBlock& bb, u32 pc) { | 19 | u32 ShaderIR::DecodeOther(NodeBlock& bb, u32 pc) { |
| 19 | const Instruction instr = {program_code[pc]}; | 20 | const Instruction instr = {program_code[pc]}; |
| @@ -59,20 +60,33 @@ u32 ShaderIR::DecodeOther(NodeBlock& bb, u32 pc) { | |||
| 59 | break; | 60 | break; |
| 60 | } | 61 | } |
| 61 | case OpCode::Id::MOV_SYS: { | 62 | case OpCode::Id::MOV_SYS: { |
| 62 | switch (instr.sys20) { | 63 | const Node value = [&]() { |
| 63 | case Tegra::Shader::SystemVariable::InvocationInfo: { | 64 | switch (instr.sys20) { |
| 64 | LOG_WARNING(HW_GPU, "MOV_SYS instruction with InvocationInfo is incomplete"); | 65 | case SystemVariable::Ydirection: |
| 65 | SetRegister(bb, instr.gpr0, Immediate(0u)); | 66 | return Operation(OperationCode::YNegate); |
| 66 | break; | 67 | case SystemVariable::InvocationInfo: |
| 67 | } | 68 | LOG_WARNING(HW_GPU, "MOV_SYS instruction with InvocationInfo is incomplete"); |
| 68 | case Tegra::Shader::SystemVariable::Ydirection: { | 69 | return Immediate(0u); |
| 69 | // Config pack's third value is Y_NEGATE's state. | 70 | case SystemVariable::TidX: |
| 70 | SetRegister(bb, instr.gpr0, Operation(OperationCode::YNegate)); | 71 | return Operation(OperationCode::LocalInvocationIdX); |
| 71 | break; | 72 | case SystemVariable::TidY: |
| 72 | } | 73 | return Operation(OperationCode::LocalInvocationIdY); |
| 73 | default: | 74 | case SystemVariable::TidZ: |
| 74 | UNIMPLEMENTED_MSG("Unhandled system move: {}", static_cast<u32>(instr.sys20.Value())); | 75 | return Operation(OperationCode::LocalInvocationIdZ); |
| 75 | } | 76 | case SystemVariable::CtaIdX: |
| 77 | return Operation(OperationCode::WorkGroupIdX); | ||
| 78 | case SystemVariable::CtaIdY: | ||
| 79 | return Operation(OperationCode::WorkGroupIdY); | ||
| 80 | case SystemVariable::CtaIdZ: | ||
| 81 | return Operation(OperationCode::WorkGroupIdZ); | ||
| 82 | default: | ||
| 83 | UNIMPLEMENTED_MSG("Unhandled system move: {}", | ||
| 84 | static_cast<u32>(instr.sys20.Value())); | ||
| 85 | return Immediate(0u); | ||
| 86 | } | ||
| 87 | }(); | ||
| 88 | SetRegister(bb, instr.gpr0, value); | ||
| 89 | |||
| 76 | break; | 90 | break; |
| 77 | } | 91 | } |
| 78 | case OpCode::Id::BRA: { | 92 | case OpCode::Id::BRA: { |
diff --git a/src/video_core/shader/shader_ir.h b/src/video_core/shader/shader_ir.h index 35f72bddb..ff7472e30 100644 --- a/src/video_core/shader/shader_ir.h +++ b/src/video_core/shader/shader_ir.h | |||
| @@ -181,7 +181,13 @@ enum class OperationCode { | |||
| 181 | EmitVertex, /// () -> void | 181 | EmitVertex, /// () -> void |
| 182 | EndPrimitive, /// () -> void | 182 | EndPrimitive, /// () -> void |
| 183 | 183 | ||
| 184 | YNegate, /// () -> float | 184 | YNegate, /// () -> float |
| 185 | LocalInvocationIdX, /// () -> uint | ||
| 186 | LocalInvocationIdY, /// () -> uint | ||
| 187 | LocalInvocationIdZ, /// () -> uint | ||
| 188 | WorkGroupIdX, /// () -> uint | ||
| 189 | WorkGroupIdY, /// () -> uint | ||
| 190 | WorkGroupIdZ, /// () -> uint | ||
| 185 | 191 | ||
| 186 | Amount, | 192 | Amount, |
| 187 | }; | 193 | }; |
diff --git a/src/yuzu/bootmanager.cpp b/src/yuzu/bootmanager.cpp index eeee603d1..9e420b359 100644 --- a/src/yuzu/bootmanager.cpp +++ b/src/yuzu/bootmanager.cpp | |||
| @@ -440,8 +440,7 @@ void GRenderWindow::CaptureScreenshot(u16 res_scale, const QString& screenshot_p | |||
| 440 | layout); | 440 | layout); |
| 441 | } | 441 | } |
| 442 | 442 | ||
| 443 | void GRenderWindow::OnMinimalClientAreaChangeRequest( | 443 | void GRenderWindow::OnMinimalClientAreaChangeRequest(std::pair<unsigned, unsigned> minimal_size) { |
| 444 | const std::pair<unsigned, unsigned>& minimal_size) { | ||
| 445 | setMinimumSize(minimal_size.first, minimal_size.second); | 444 | setMinimumSize(minimal_size.first, minimal_size.second); |
| 446 | } | 445 | } |
| 447 | 446 | ||
diff --git a/src/yuzu/bootmanager.h b/src/yuzu/bootmanager.h index 3df33aca1..7f9f8e8e3 100644 --- a/src/yuzu/bootmanager.h +++ b/src/yuzu/bootmanager.h | |||
| @@ -162,8 +162,7 @@ private: | |||
| 162 | void TouchUpdateEvent(const QTouchEvent* event); | 162 | void TouchUpdateEvent(const QTouchEvent* event); |
| 163 | void TouchEndEvent(); | 163 | void TouchEndEvent(); |
| 164 | 164 | ||
| 165 | void OnMinimalClientAreaChangeRequest( | 165 | void OnMinimalClientAreaChangeRequest(std::pair<unsigned, unsigned> minimal_size) override; |
| 166 | const std::pair<unsigned, unsigned>& minimal_size) override; | ||
| 167 | 166 | ||
| 168 | QWidget* container = nullptr; | 167 | QWidget* container = nullptr; |
| 169 | GGLWidgetInternal* child = nullptr; | 168 | GGLWidgetInternal* child = nullptr; |
diff --git a/src/yuzu_cmd/CMakeLists.txt b/src/yuzu_cmd/CMakeLists.txt index 297dab653..b5f06ab9e 100644 --- a/src/yuzu_cmd/CMakeLists.txt +++ b/src/yuzu_cmd/CMakeLists.txt | |||
| @@ -4,6 +4,8 @@ add_executable(yuzu-cmd | |||
| 4 | config.cpp | 4 | config.cpp |
| 5 | config.h | 5 | config.h |
| 6 | default_ini.h | 6 | default_ini.h |
| 7 | emu_window/emu_window_sdl2_gl.cpp | ||
| 8 | emu_window/emu_window_sdl2_gl.h | ||
| 7 | emu_window/emu_window_sdl2.cpp | 9 | emu_window/emu_window_sdl2.cpp |
| 8 | emu_window/emu_window_sdl2.h | 10 | emu_window/emu_window_sdl2.h |
| 9 | resource.h | 11 | resource.h |
diff --git a/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp b/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp index 8f104062d..a6edc089a 100644 --- a/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp +++ b/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp | |||
| @@ -2,53 +2,27 @@ | |||
| 2 | // Licensed under GPLv2 or any later version | 2 | // Licensed under GPLv2 or any later version |
| 3 | // Refer to the license.txt file included. | 3 | // Refer to the license.txt file included. |
| 4 | 4 | ||
| 5 | #include <algorithm> | ||
| 6 | #include <cstdlib> | ||
| 7 | #include <string> | ||
| 8 | #define SDL_MAIN_HANDLED | ||
| 9 | #include <SDL.h> | 5 | #include <SDL.h> |
| 10 | #include <fmt/format.h> | ||
| 11 | #include <glad/glad.h> | ||
| 12 | #include "common/logging/log.h" | 6 | #include "common/logging/log.h" |
| 13 | #include "common/scm_rev.h" | ||
| 14 | #include "common/string_util.h" | ||
| 15 | #include "core/settings.h" | ||
| 16 | #include "input_common/keyboard.h" | 7 | #include "input_common/keyboard.h" |
| 17 | #include "input_common/main.h" | 8 | #include "input_common/main.h" |
| 18 | #include "input_common/motion_emu.h" | 9 | #include "input_common/motion_emu.h" |
| 19 | #include "input_common/sdl/sdl.h" | 10 | #include "input_common/sdl/sdl.h" |
| 20 | #include "yuzu_cmd/emu_window/emu_window_sdl2.h" | 11 | #include "yuzu_cmd/emu_window/emu_window_sdl2.h" |
| 21 | 12 | ||
| 22 | class SDLGLContext : public Core::Frontend::GraphicsContext { | 13 | EmuWindow_SDL2::EmuWindow_SDL2(bool fullscreen) { |
| 23 | public: | 14 | if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_JOYSTICK) < 0) { |
| 24 | explicit SDLGLContext() { | 15 | LOG_CRITICAL(Frontend, "Failed to initialize SDL2! Exiting..."); |
| 25 | // create a hidden window to make the shared context against | 16 | exit(1); |
| 26 | window = SDL_CreateWindow("", SDL_WINDOWPOS_UNDEFINED, // x position | ||
| 27 | SDL_WINDOWPOS_UNDEFINED, // y position | ||
| 28 | Layout::ScreenUndocked::Width, Layout::ScreenUndocked::Height, | ||
| 29 | SDL_WINDOW_OPENGL | SDL_WINDOW_HIDDEN); | ||
| 30 | context = SDL_GL_CreateContext(window); | ||
| 31 | } | ||
| 32 | |||
| 33 | ~SDLGLContext() { | ||
| 34 | SDL_GL_DeleteContext(context); | ||
| 35 | SDL_DestroyWindow(window); | ||
| 36 | } | ||
| 37 | |||
| 38 | void MakeCurrent() override { | ||
| 39 | SDL_GL_MakeCurrent(window, context); | ||
| 40 | } | ||
| 41 | |||
| 42 | void DoneCurrent() override { | ||
| 43 | SDL_GL_MakeCurrent(window, nullptr); | ||
| 44 | } | 17 | } |
| 18 | InputCommon::Init(); | ||
| 19 | SDL_SetMainReady(); | ||
| 20 | } | ||
| 45 | 21 | ||
| 46 | void SwapBuffers() override {} | 22 | EmuWindow_SDL2::~EmuWindow_SDL2() { |
| 47 | 23 | InputCommon::Shutdown(); | |
| 48 | private: | 24 | SDL_Quit(); |
| 49 | SDL_Window* window; | 25 | } |
| 50 | SDL_GLContext context; | ||
| 51 | }; | ||
| 52 | 26 | ||
| 53 | void EmuWindow_SDL2::OnMouseMotion(s32 x, s32 y) { | 27 | void EmuWindow_SDL2::OnMouseMotion(s32 x, s32 y) { |
| 54 | TouchMoved((unsigned)std::max(x, 0), (unsigned)std::max(y, 0)); | 28 | TouchMoved((unsigned)std::max(x, 0), (unsigned)std::max(y, 0)); |
| @@ -139,112 +113,6 @@ void EmuWindow_SDL2::Fullscreen() { | |||
| 139 | SDL_MaximizeWindow(render_window); | 113 | SDL_MaximizeWindow(render_window); |
| 140 | } | 114 | } |
| 141 | 115 | ||
| 142 | bool EmuWindow_SDL2::SupportsRequiredGLExtensions() { | ||
| 143 | std::vector<std::string> unsupported_ext; | ||
| 144 | |||
| 145 | if (!GLAD_GL_ARB_direct_state_access) | ||
| 146 | unsupported_ext.push_back("ARB_direct_state_access"); | ||
| 147 | if (!GLAD_GL_ARB_vertex_type_10f_11f_11f_rev) | ||
| 148 | unsupported_ext.push_back("ARB_vertex_type_10f_11f_11f_rev"); | ||
| 149 | if (!GLAD_GL_ARB_texture_mirror_clamp_to_edge) | ||
| 150 | unsupported_ext.push_back("ARB_texture_mirror_clamp_to_edge"); | ||
| 151 | if (!GLAD_GL_ARB_multi_bind) | ||
| 152 | unsupported_ext.push_back("ARB_multi_bind"); | ||
| 153 | |||
| 154 | // Extensions required to support some texture formats. | ||
| 155 | if (!GLAD_GL_EXT_texture_compression_s3tc) | ||
| 156 | unsupported_ext.push_back("EXT_texture_compression_s3tc"); | ||
| 157 | if (!GLAD_GL_ARB_texture_compression_rgtc) | ||
| 158 | unsupported_ext.push_back("ARB_texture_compression_rgtc"); | ||
| 159 | if (!GLAD_GL_ARB_depth_buffer_float) | ||
| 160 | unsupported_ext.push_back("ARB_depth_buffer_float"); | ||
| 161 | |||
| 162 | for (const std::string& ext : unsupported_ext) | ||
| 163 | LOG_CRITICAL(Frontend, "Unsupported GL extension: {}", ext); | ||
| 164 | |||
| 165 | return unsupported_ext.empty(); | ||
| 166 | } | ||
| 167 | |||
| 168 | EmuWindow_SDL2::EmuWindow_SDL2(bool fullscreen) { | ||
| 169 | // Initialize the window | ||
| 170 | if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_JOYSTICK) < 0) { | ||
| 171 | LOG_CRITICAL(Frontend, "Failed to initialize SDL2! Exiting..."); | ||
| 172 | exit(1); | ||
| 173 | } | ||
| 174 | |||
| 175 | InputCommon::Init(); | ||
| 176 | |||
| 177 | SDL_SetMainReady(); | ||
| 178 | |||
| 179 | const SDL_GLprofile profile = Settings::values.use_compatibility_profile | ||
| 180 | ? SDL_GL_CONTEXT_PROFILE_COMPATIBILITY | ||
| 181 | : SDL_GL_CONTEXT_PROFILE_CORE; | ||
| 182 | |||
| 183 | SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 4); | ||
| 184 | SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3); | ||
| 185 | SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, profile); | ||
| 186 | SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); | ||
| 187 | SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8); | ||
| 188 | SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8); | ||
| 189 | SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8); | ||
| 190 | SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 0); | ||
| 191 | SDL_GL_SetAttribute(SDL_GL_SHARE_WITH_CURRENT_CONTEXT, 1); | ||
| 192 | |||
| 193 | std::string window_title = fmt::format("yuzu {} | {}-{}", Common::g_build_fullname, | ||
| 194 | Common::g_scm_branch, Common::g_scm_desc); | ||
| 195 | render_window = | ||
| 196 | SDL_CreateWindow(window_title.c_str(), | ||
| 197 | SDL_WINDOWPOS_UNDEFINED, // x position | ||
| 198 | SDL_WINDOWPOS_UNDEFINED, // y position | ||
| 199 | Layout::ScreenUndocked::Width, Layout::ScreenUndocked::Height, | ||
| 200 | SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI); | ||
| 201 | |||
| 202 | if (render_window == nullptr) { | ||
| 203 | LOG_CRITICAL(Frontend, "Failed to create SDL2 window! {}", SDL_GetError()); | ||
| 204 | exit(1); | ||
| 205 | } | ||
| 206 | |||
| 207 | if (fullscreen) { | ||
| 208 | Fullscreen(); | ||
| 209 | } | ||
| 210 | gl_context = SDL_GL_CreateContext(render_window); | ||
| 211 | |||
| 212 | if (gl_context == nullptr) { | ||
| 213 | LOG_CRITICAL(Frontend, "Failed to create SDL2 GL context! {}", SDL_GetError()); | ||
| 214 | exit(1); | ||
| 215 | } | ||
| 216 | |||
| 217 | if (!gladLoadGLLoader(static_cast<GLADloadproc>(SDL_GL_GetProcAddress))) { | ||
| 218 | LOG_CRITICAL(Frontend, "Failed to initialize GL functions! {}", SDL_GetError()); | ||
| 219 | exit(1); | ||
| 220 | } | ||
| 221 | |||
| 222 | if (!SupportsRequiredGLExtensions()) { | ||
| 223 | LOG_CRITICAL(Frontend, "GPU does not support all required OpenGL extensions! Exiting..."); | ||
| 224 | exit(1); | ||
| 225 | } | ||
| 226 | |||
| 227 | OnResize(); | ||
| 228 | OnMinimalClientAreaChangeRequest(GetActiveConfig().min_client_area_size); | ||
| 229 | SDL_PumpEvents(); | ||
| 230 | SDL_GL_SetSwapInterval(false); | ||
| 231 | LOG_INFO(Frontend, "yuzu Version: {} | {}-{}", Common::g_build_fullname, Common::g_scm_branch, | ||
| 232 | Common::g_scm_desc); | ||
| 233 | Settings::LogSettings(); | ||
| 234 | |||
| 235 | DoneCurrent(); | ||
| 236 | } | ||
| 237 | |||
| 238 | EmuWindow_SDL2::~EmuWindow_SDL2() { | ||
| 239 | InputCommon::Shutdown(); | ||
| 240 | SDL_GL_DeleteContext(gl_context); | ||
| 241 | SDL_Quit(); | ||
| 242 | } | ||
| 243 | |||
| 244 | void EmuWindow_SDL2::SwapBuffers() { | ||
| 245 | SDL_GL_SwapWindow(render_window); | ||
| 246 | } | ||
| 247 | |||
| 248 | void EmuWindow_SDL2::PollEvents() { | 116 | void EmuWindow_SDL2::PollEvents() { |
| 249 | SDL_Event event; | 117 | SDL_Event event; |
| 250 | 118 | ||
| @@ -257,7 +125,11 @@ void EmuWindow_SDL2::PollEvents() { | |||
| 257 | case SDL_WINDOWEVENT_RESIZED: | 125 | case SDL_WINDOWEVENT_RESIZED: |
| 258 | case SDL_WINDOWEVENT_MAXIMIZED: | 126 | case SDL_WINDOWEVENT_MAXIMIZED: |
| 259 | case SDL_WINDOWEVENT_RESTORED: | 127 | case SDL_WINDOWEVENT_RESTORED: |
| 128 | OnResize(); | ||
| 129 | break; | ||
| 260 | case SDL_WINDOWEVENT_MINIMIZED: | 130 | case SDL_WINDOWEVENT_MINIMIZED: |
| 131 | case SDL_WINDOWEVENT_EXPOSED: | ||
| 132 | is_shown = event.window.event == SDL_WINDOWEVENT_EXPOSED; | ||
| 261 | OnResize(); | 133 | OnResize(); |
| 262 | break; | 134 | break; |
| 263 | case SDL_WINDOWEVENT_CLOSE: | 135 | case SDL_WINDOWEVENT_CLOSE: |
| @@ -300,20 +172,6 @@ void EmuWindow_SDL2::PollEvents() { | |||
| 300 | } | 172 | } |
| 301 | } | 173 | } |
| 302 | 174 | ||
| 303 | void EmuWindow_SDL2::MakeCurrent() { | 175 | void EmuWindow_SDL2::OnMinimalClientAreaChangeRequest(std::pair<unsigned, unsigned> minimal_size) { |
| 304 | SDL_GL_MakeCurrent(render_window, gl_context); | ||
| 305 | } | ||
| 306 | |||
| 307 | void EmuWindow_SDL2::DoneCurrent() { | ||
| 308 | SDL_GL_MakeCurrent(render_window, nullptr); | ||
| 309 | } | ||
| 310 | |||
| 311 | void EmuWindow_SDL2::OnMinimalClientAreaChangeRequest( | ||
| 312 | const std::pair<unsigned, unsigned>& minimal_size) { | ||
| 313 | |||
| 314 | SDL_SetWindowMinimumSize(render_window, minimal_size.first, minimal_size.second); | 176 | SDL_SetWindowMinimumSize(render_window, minimal_size.first, minimal_size.second); |
| 315 | } | 177 | } |
| 316 | |||
| 317 | std::unique_ptr<Core::Frontend::GraphicsContext> EmuWindow_SDL2::CreateSharedContext() const { | ||
| 318 | return std::make_unique<SDLGLContext>(); | ||
| 319 | } | ||
diff --git a/src/yuzu_cmd/emu_window/emu_window_sdl2.h b/src/yuzu_cmd/emu_window/emu_window_sdl2.h index 17e98227f..d8051ebdf 100644 --- a/src/yuzu_cmd/emu_window/emu_window_sdl2.h +++ b/src/yuzu_cmd/emu_window/emu_window_sdl2.h | |||
| @@ -15,24 +15,13 @@ public: | |||
| 15 | explicit EmuWindow_SDL2(bool fullscreen); | 15 | explicit EmuWindow_SDL2(bool fullscreen); |
| 16 | ~EmuWindow_SDL2(); | 16 | ~EmuWindow_SDL2(); |
| 17 | 17 | ||
| 18 | /// Swap buffers to display the next frame | ||
| 19 | void SwapBuffers() override; | ||
| 20 | |||
| 21 | /// Polls window events | 18 | /// Polls window events |
| 22 | void PollEvents() override; | 19 | void PollEvents() override; |
| 23 | 20 | ||
| 24 | /// Makes the graphics context current for the caller thread | ||
| 25 | void MakeCurrent() override; | ||
| 26 | |||
| 27 | /// Releases the GL context from the caller thread | ||
| 28 | void DoneCurrent() override; | ||
| 29 | |||
| 30 | std::unique_ptr<Core::Frontend::GraphicsContext> CreateSharedContext() const override; | ||
| 31 | |||
| 32 | /// Whether the window is still open, and a close request hasn't yet been sent | 21 | /// Whether the window is still open, and a close request hasn't yet been sent |
| 33 | bool IsOpen() const; | 22 | bool IsOpen() const; |
| 34 | 23 | ||
| 35 | private: | 24 | protected: |
| 36 | /// Called by PollEvents when a key is pressed or released. | 25 | /// Called by PollEvents when a key is pressed or released. |
| 37 | void OnKeyEvent(int key, u8 state); | 26 | void OnKeyEvent(int key, u8 state); |
| 38 | 27 | ||
| @@ -60,20 +49,15 @@ private: | |||
| 60 | /// Called when user passes the fullscreen parameter flag | 49 | /// Called when user passes the fullscreen parameter flag |
| 61 | void Fullscreen(); | 50 | void Fullscreen(); |
| 62 | 51 | ||
| 63 | /// Whether the GPU and driver supports the OpenGL extension required | ||
| 64 | bool SupportsRequiredGLExtensions(); | ||
| 65 | |||
| 66 | /// Called when a configuration change affects the minimal size of the window | 52 | /// Called when a configuration change affects the minimal size of the window |
| 67 | void OnMinimalClientAreaChangeRequest( | 53 | void OnMinimalClientAreaChangeRequest(std::pair<unsigned, unsigned> minimal_size) override; |
| 68 | const std::pair<unsigned, unsigned>& minimal_size) override; | ||
| 69 | 54 | ||
| 70 | /// Is the window still open? | 55 | /// Is the window still open? |
| 71 | bool is_open = true; | 56 | bool is_open = true; |
| 72 | 57 | ||
| 58 | /// Is the window being shown? | ||
| 59 | bool is_shown = true; | ||
| 60 | |||
| 73 | /// Internal SDL2 render window | 61 | /// Internal SDL2 render window |
| 74 | SDL_Window* render_window; | 62 | SDL_Window* render_window; |
| 75 | |||
| 76 | using SDL_GLContext = void*; | ||
| 77 | /// The OpenGL context associated with the window | ||
| 78 | SDL_GLContext gl_context; | ||
| 79 | }; | 63 | }; |
diff --git a/src/yuzu_cmd/emu_window/emu_window_sdl2_gl.cpp b/src/yuzu_cmd/emu_window/emu_window_sdl2_gl.cpp new file mode 100644 index 000000000..904022137 --- /dev/null +++ b/src/yuzu_cmd/emu_window/emu_window_sdl2_gl.cpp | |||
| @@ -0,0 +1,154 @@ | |||
| 1 | // Copyright 2019 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include <algorithm> | ||
| 6 | #include <cstdlib> | ||
| 7 | #include <string> | ||
| 8 | #define SDL_MAIN_HANDLED | ||
| 9 | #include <SDL.h> | ||
| 10 | #include <fmt/format.h> | ||
| 11 | #include <glad/glad.h> | ||
| 12 | #include "common/logging/log.h" | ||
| 13 | #include "common/scm_rev.h" | ||
| 14 | #include "common/string_util.h" | ||
| 15 | #include "core/settings.h" | ||
| 16 | #include "input_common/keyboard.h" | ||
| 17 | #include "input_common/main.h" | ||
| 18 | #include "input_common/motion_emu.h" | ||
| 19 | #include "yuzu_cmd/emu_window/emu_window_sdl2_gl.h" | ||
| 20 | |||
| 21 | class SDLGLContext : public Core::Frontend::GraphicsContext { | ||
| 22 | public: | ||
| 23 | explicit SDLGLContext() { | ||
| 24 | // create a hidden window to make the shared context against | ||
| 25 | window = SDL_CreateWindow("", SDL_WINDOWPOS_UNDEFINED, // x position | ||
| 26 | SDL_WINDOWPOS_UNDEFINED, // y position | ||
| 27 | Layout::ScreenUndocked::Width, Layout::ScreenUndocked::Height, | ||
| 28 | SDL_WINDOW_OPENGL | SDL_WINDOW_HIDDEN); | ||
| 29 | context = SDL_GL_CreateContext(window); | ||
| 30 | } | ||
| 31 | |||
| 32 | ~SDLGLContext() { | ||
| 33 | SDL_GL_DeleteContext(context); | ||
| 34 | SDL_DestroyWindow(window); | ||
| 35 | } | ||
| 36 | |||
| 37 | void MakeCurrent() override { | ||
| 38 | SDL_GL_MakeCurrent(window, context); | ||
| 39 | } | ||
| 40 | |||
| 41 | void DoneCurrent() override { | ||
| 42 | SDL_GL_MakeCurrent(window, nullptr); | ||
| 43 | } | ||
| 44 | |||
| 45 | void SwapBuffers() override {} | ||
| 46 | |||
| 47 | private: | ||
| 48 | SDL_Window* window; | ||
| 49 | SDL_GLContext context; | ||
| 50 | }; | ||
| 51 | |||
| 52 | bool EmuWindow_SDL2_GL::SupportsRequiredGLExtensions() { | ||
| 53 | std::vector<std::string> unsupported_ext; | ||
| 54 | |||
| 55 | if (!GLAD_GL_ARB_vertex_type_10f_11f_11f_rev) | ||
| 56 | unsupported_ext.push_back("ARB_vertex_type_10f_11f_11f_rev"); | ||
| 57 | if (!GLAD_GL_ARB_texture_mirror_clamp_to_edge) | ||
| 58 | unsupported_ext.push_back("ARB_texture_mirror_clamp_to_edge"); | ||
| 59 | if (!GLAD_GL_ARB_multi_bind) | ||
| 60 | unsupported_ext.push_back("ARB_multi_bind"); | ||
| 61 | |||
| 62 | // Extensions required to support some texture formats. | ||
| 63 | if (!GLAD_GL_EXT_texture_compression_s3tc) | ||
| 64 | unsupported_ext.push_back("EXT_texture_compression_s3tc"); | ||
| 65 | if (!GLAD_GL_ARB_texture_compression_rgtc) | ||
| 66 | unsupported_ext.push_back("ARB_texture_compression_rgtc"); | ||
| 67 | if (!GLAD_GL_ARB_depth_buffer_float) | ||
| 68 | unsupported_ext.push_back("ARB_depth_buffer_float"); | ||
| 69 | |||
| 70 | for (const std::string& ext : unsupported_ext) | ||
| 71 | LOG_CRITICAL(Frontend, "Unsupported GL extension: {}", ext); | ||
| 72 | |||
| 73 | return unsupported_ext.empty(); | ||
| 74 | } | ||
| 75 | |||
| 76 | EmuWindow_SDL2_GL::EmuWindow_SDL2_GL(bool fullscreen) : EmuWindow_SDL2(fullscreen) { | ||
| 77 | const SDL_GLprofile profile = Settings::values.use_compatibility_profile | ||
| 78 | ? SDL_GL_CONTEXT_PROFILE_COMPATIBILITY | ||
| 79 | : SDL_GL_CONTEXT_PROFILE_CORE; | ||
| 80 | |||
| 81 | SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 4); | ||
| 82 | SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3); | ||
| 83 | SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, profile); | ||
| 84 | SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); | ||
| 85 | SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8); | ||
| 86 | SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8); | ||
| 87 | SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8); | ||
| 88 | SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 0); | ||
| 89 | SDL_GL_SetAttribute(SDL_GL_SHARE_WITH_CURRENT_CONTEXT, 1); | ||
| 90 | |||
| 91 | std::string window_title = fmt::format("yuzu {} | {}-{}", Common::g_build_fullname, | ||
| 92 | Common::g_scm_branch, Common::g_scm_desc); | ||
| 93 | render_window = | ||
| 94 | SDL_CreateWindow(window_title.c_str(), | ||
| 95 | SDL_WINDOWPOS_UNDEFINED, // x position | ||
| 96 | SDL_WINDOWPOS_UNDEFINED, // y position | ||
| 97 | Layout::ScreenUndocked::Width, Layout::ScreenUndocked::Height, | ||
| 98 | SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI); | ||
| 99 | |||
| 100 | if (render_window == nullptr) { | ||
| 101 | LOG_CRITICAL(Frontend, "Failed to create SDL2 window! {}", SDL_GetError()); | ||
| 102 | exit(1); | ||
| 103 | } | ||
| 104 | |||
| 105 | if (fullscreen) { | ||
| 106 | Fullscreen(); | ||
| 107 | } | ||
| 108 | gl_context = SDL_GL_CreateContext(render_window); | ||
| 109 | |||
| 110 | if (gl_context == nullptr) { | ||
| 111 | LOG_CRITICAL(Frontend, "Failed to create SDL2 GL context! {}", SDL_GetError()); | ||
| 112 | exit(1); | ||
| 113 | } | ||
| 114 | |||
| 115 | if (!gladLoadGLLoader(static_cast<GLADloadproc>(SDL_GL_GetProcAddress))) { | ||
| 116 | LOG_CRITICAL(Frontend, "Failed to initialize GL functions! {}", SDL_GetError()); | ||
| 117 | exit(1); | ||
| 118 | } | ||
| 119 | |||
| 120 | if (!SupportsRequiredGLExtensions()) { | ||
| 121 | LOG_CRITICAL(Frontend, "GPU does not support all required OpenGL extensions! Exiting..."); | ||
| 122 | exit(1); | ||
| 123 | } | ||
| 124 | |||
| 125 | OnResize(); | ||
| 126 | OnMinimalClientAreaChangeRequest(GetActiveConfig().min_client_area_size); | ||
| 127 | SDL_PumpEvents(); | ||
| 128 | SDL_GL_SetSwapInterval(false); | ||
| 129 | LOG_INFO(Frontend, "yuzu Version: {} | {}-{}", Common::g_build_fullname, Common::g_scm_branch, | ||
| 130 | Common::g_scm_desc); | ||
| 131 | Settings::LogSettings(); | ||
| 132 | |||
| 133 | DoneCurrent(); | ||
| 134 | } | ||
| 135 | |||
| 136 | EmuWindow_SDL2_GL::~EmuWindow_SDL2_GL() { | ||
| 137 | SDL_GL_DeleteContext(gl_context); | ||
| 138 | } | ||
| 139 | |||
| 140 | void EmuWindow_SDL2_GL::SwapBuffers() { | ||
| 141 | SDL_GL_SwapWindow(render_window); | ||
| 142 | } | ||
| 143 | |||
| 144 | void EmuWindow_SDL2_GL::MakeCurrent() { | ||
| 145 | SDL_GL_MakeCurrent(render_window, gl_context); | ||
| 146 | } | ||
| 147 | |||
| 148 | void EmuWindow_SDL2_GL::DoneCurrent() { | ||
| 149 | SDL_GL_MakeCurrent(render_window, nullptr); | ||
| 150 | } | ||
| 151 | |||
| 152 | std::unique_ptr<Core::Frontend::GraphicsContext> EmuWindow_SDL2_GL::CreateSharedContext() const { | ||
| 153 | return std::make_unique<SDLGLContext>(); | ||
| 154 | } | ||
diff --git a/src/yuzu_cmd/emu_window/emu_window_sdl2_gl.h b/src/yuzu_cmd/emu_window/emu_window_sdl2_gl.h new file mode 100644 index 000000000..630deba93 --- /dev/null +++ b/src/yuzu_cmd/emu_window/emu_window_sdl2_gl.h | |||
| @@ -0,0 +1,34 @@ | |||
| 1 | // Copyright 2019 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include <memory> | ||
| 8 | #include "core/frontend/emu_window.h" | ||
| 9 | #include "yuzu_cmd/emu_window/emu_window_sdl2.h" | ||
| 10 | |||
| 11 | class EmuWindow_SDL2_GL final : public EmuWindow_SDL2 { | ||
| 12 | public: | ||
| 13 | explicit EmuWindow_SDL2_GL(bool fullscreen); | ||
| 14 | ~EmuWindow_SDL2_GL(); | ||
| 15 | |||
| 16 | /// Swap buffers to display the next frame | ||
| 17 | void SwapBuffers() override; | ||
| 18 | |||
| 19 | /// Makes the graphics context current for the caller thread | ||
| 20 | void MakeCurrent() override; | ||
| 21 | |||
| 22 | /// Releases the GL context from the caller thread | ||
| 23 | void DoneCurrent() override; | ||
| 24 | |||
| 25 | std::unique_ptr<Core::Frontend::GraphicsContext> CreateSharedContext() const override; | ||
| 26 | |||
| 27 | private: | ||
| 28 | /// Whether the GPU and driver supports the OpenGL extension required | ||
| 29 | bool SupportsRequiredGLExtensions(); | ||
| 30 | |||
| 31 | using SDL_GLContext = void*; | ||
| 32 | /// The OpenGL context associated with the window | ||
| 33 | SDL_GLContext gl_context; | ||
| 34 | }; | ||
diff --git a/src/yuzu_cmd/yuzu.cpp b/src/yuzu_cmd/yuzu.cpp index d3734927b..5d9442646 100644 --- a/src/yuzu_cmd/yuzu.cpp +++ b/src/yuzu_cmd/yuzu.cpp | |||
| @@ -31,6 +31,7 @@ | |||
| 31 | #include "video_core/renderer_base.h" | 31 | #include "video_core/renderer_base.h" |
| 32 | #include "yuzu_cmd/config.h" | 32 | #include "yuzu_cmd/config.h" |
| 33 | #include "yuzu_cmd/emu_window/emu_window_sdl2.h" | 33 | #include "yuzu_cmd/emu_window/emu_window_sdl2.h" |
| 34 | #include "yuzu_cmd/emu_window/emu_window_sdl2_gl.h" | ||
| 34 | 35 | ||
| 35 | #include "core/file_sys/registered_cache.h" | 36 | #include "core/file_sys/registered_cache.h" |
| 36 | 37 | ||
| @@ -173,7 +174,7 @@ int main(int argc, char** argv) { | |||
| 173 | Settings::values.use_gdbstub = use_gdbstub; | 174 | Settings::values.use_gdbstub = use_gdbstub; |
| 174 | Settings::Apply(); | 175 | Settings::Apply(); |
| 175 | 176 | ||
| 176 | std::unique_ptr<EmuWindow_SDL2> emu_window{std::make_unique<EmuWindow_SDL2>(fullscreen)}; | 177 | std::unique_ptr<EmuWindow_SDL2> emu_window{std::make_unique<EmuWindow_SDL2_GL>(fullscreen)}; |
| 177 | 178 | ||
| 178 | if (!Settings::values.use_multi_core) { | 179 | if (!Settings::values.use_multi_core) { |
| 179 | // Single core mode must acquire OpenGL context for entire emulation session | 180 | // Single core mode must acquire OpenGL context for entire emulation session |