diff options
| -rw-r--r-- | CMakeLists.txt | 14 | ||||
| -rw-r--r-- | src/core/hle/service/friend/friend.cpp | 9 | ||||
| -rw-r--r-- | src/core/hle/service/hid/hid.cpp | 17 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_rasterizer.cpp | 192 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_rasterizer.h | 23 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_shader_decompiler.cpp | 12 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_state.cpp | 15 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_state.h | 6 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_stream_buffer.cpp | 201 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_stream_buffer.h | 42 |
10 files changed, 213 insertions, 318 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index 3639b623c..ff8385e3a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | # CMake 3.6 required for FindBoost to define IMPORTED libs properly on unknown Boost versions | 1 | cmake_minimum_required(VERSION 3.7) |
| 2 | cmake_minimum_required(VERSION 3.6) | 2 | |
| 3 | list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/CMakeModules") | 3 | list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/CMakeModules") |
| 4 | list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/externals/cmake-modules") | 4 | list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/externals/cmake-modules") |
| 5 | include(DownloadExternals) | 5 | include(DownloadExternals) |
| @@ -187,8 +187,8 @@ find_package(Threads REQUIRED) | |||
| 187 | if (ENABLE_SDL2) | 187 | if (ENABLE_SDL2) |
| 188 | if (YUZU_USE_BUNDLED_SDL2) | 188 | if (YUZU_USE_BUNDLED_SDL2) |
| 189 | # Detect toolchain and platform | 189 | # Detect toolchain and platform |
| 190 | if (MSVC14 AND ARCHITECTURE_x86_64) | 190 | if ((MSVC_VERSION GREATER_EQUAL 1910 AND MSVC_VERSION LESS 1920) AND ARCHITECTURE_x86_64) |
| 191 | set(SDL2_VER "SDL2-2.0.5") | 191 | set(SDL2_VER "SDL2-2.0.8") |
| 192 | else() | 192 | else() |
| 193 | message(FATAL_ERROR "No bundled SDL2 binaries for your toolchain. Disable YUZU_USE_BUNDLED_SDL2 and provide your own.") | 193 | message(FATAL_ERROR "No bundled SDL2 binaries for your toolchain. Disable YUZU_USE_BUNDLED_SDL2 and provide your own.") |
| 194 | endif() | 194 | endif() |
| @@ -220,7 +220,7 @@ if (YUZU_USE_BUNDLED_UNICORN) | |||
| 220 | if (MSVC) | 220 | if (MSVC) |
| 221 | message(STATUS "unicorn not found, falling back to bundled") | 221 | message(STATUS "unicorn not found, falling back to bundled") |
| 222 | # Detect toolchain and platform | 222 | # Detect toolchain and platform |
| 223 | if (MSVC14 AND ARCHITECTURE_x86_64) | 223 | if ((MSVC_VERSION GREATER_EQUAL 1910 AND MSVC_VERSION LESS 1920) AND ARCHITECTURE_x86_64) |
| 224 | set(UNICORN_VER "unicorn-yuzu") | 224 | set(UNICORN_VER "unicorn-yuzu") |
| 225 | else() | 225 | else() |
| 226 | message(FATAL_ERROR "No bundled Unicorn binaries for your toolchain. Disable YUZU_USE_BUNDLED_UNICORN and provide your own.") | 226 | message(FATAL_ERROR "No bundled Unicorn binaries for your toolchain. Disable YUZU_USE_BUNDLED_UNICORN and provide your own.") |
| @@ -279,7 +279,7 @@ endif() | |||
| 279 | 279 | ||
| 280 | if (ENABLE_QT) | 280 | if (ENABLE_QT) |
| 281 | if (YUZU_USE_BUNDLED_QT) | 281 | if (YUZU_USE_BUNDLED_QT) |
| 282 | if (MSVC14 AND ARCHITECTURE_x86_64) | 282 | if ((MSVC_VERSION GREATER_EQUAL 1910 AND MSVC_VERSION LESS 1920) AND ARCHITECTURE_x86_64) |
| 283 | set(QT_VER qt-5.10.0-msvc2015_64) | 283 | set(QT_VER qt-5.10.0-msvc2015_64) |
| 284 | else() | 284 | else() |
| 285 | message(FATAL_ERROR "No bundled Qt binaries for your toolchain. Disable YUZU_USE_BUNDLED_QT and provide your own.") | 285 | message(FATAL_ERROR "No bundled Qt binaries for your toolchain. Disable YUZU_USE_BUNDLED_QT and provide your own.") |
| @@ -303,7 +303,7 @@ endif() | |||
| 303 | # ====================================== | 303 | # ====================================== |
| 304 | 304 | ||
| 305 | IF (APPLE) | 305 | IF (APPLE) |
| 306 | FIND_LIBRARY(COCOA_LIBRARY Cocoa) # Umbrella framework for everything GUI-related | 306 | find_library(COCOA_LIBRARY Cocoa) # Umbrella framework for everything GUI-related |
| 307 | set(PLATFORM_LIBRARIES ${COCOA_LIBRARY} ${IOKIT_LIBRARY} ${COREVIDEO_LIBRARY}) | 307 | set(PLATFORM_LIBRARIES ${COCOA_LIBRARY} ${IOKIT_LIBRARY} ${COREVIDEO_LIBRARY}) |
| 308 | 308 | ||
| 309 | if (CMAKE_CXX_COMPILER_ID STREQUAL Clang) | 309 | if (CMAKE_CXX_COMPILER_ID STREQUAL Clang) |
diff --git a/src/core/hle/service/friend/friend.cpp b/src/core/hle/service/friend/friend.cpp index 2b642c32f..f2b0e509a 100644 --- a/src/core/hle/service/friend/friend.cpp +++ b/src/core/hle/service/friend/friend.cpp | |||
| @@ -26,7 +26,7 @@ public: | |||
| 26 | {10600, nullptr, "DeclareOpenOnlinePlaySession"}, | 26 | {10600, nullptr, "DeclareOpenOnlinePlaySession"}, |
| 27 | {10601, &IFriendService::DeclareCloseOnlinePlaySession, | 27 | {10601, &IFriendService::DeclareCloseOnlinePlaySession, |
| 28 | "DeclareCloseOnlinePlaySession"}, | 28 | "DeclareCloseOnlinePlaySession"}, |
| 29 | {10610, nullptr, "UpdateUserPresence"}, | 29 | {10610, &IFriendService::UpdateUserPresence, "UpdateUserPresence"}, |
| 30 | {10700, nullptr, "GetPlayHistoryRegistrationKey"}, | 30 | {10700, nullptr, "GetPlayHistoryRegistrationKey"}, |
| 31 | {10701, nullptr, "GetPlayHistoryRegistrationKeyWithNetworkServiceAccountId"}, | 31 | {10701, nullptr, "GetPlayHistoryRegistrationKeyWithNetworkServiceAccountId"}, |
| 32 | {10702, nullptr, "AddPlayHistory"}, | 32 | {10702, nullptr, "AddPlayHistory"}, |
| @@ -99,6 +99,13 @@ private: | |||
| 99 | IPC::ResponseBuilder rb{ctx, 2}; | 99 | IPC::ResponseBuilder rb{ctx, 2}; |
| 100 | rb.Push(RESULT_SUCCESS); | 100 | rb.Push(RESULT_SUCCESS); |
| 101 | } | 101 | } |
| 102 | |||
| 103 | void UpdateUserPresence(Kernel::HLERequestContext& ctx) { | ||
| 104 | // Stub used by Retro City Rampage | ||
| 105 | LOG_WARNING(Service_ACC, "(STUBBED) called"); | ||
| 106 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 107 | rb.Push(RESULT_SUCCESS); | ||
| 108 | } | ||
| 102 | }; | 109 | }; |
| 103 | 110 | ||
| 104 | void Module::Interface::CreateFriendService(Kernel::HLERequestContext& ctx) { | 111 | void Module::Interface::CreateFriendService(Kernel::HLERequestContext& ctx) { |
diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp index dcdfa0e19..970942d3f 100644 --- a/src/core/hle/service/hid/hid.cpp +++ b/src/core/hle/service/hid/hid.cpp | |||
| @@ -291,6 +291,7 @@ private: | |||
| 291 | class Hid final : public ServiceFramework<Hid> { | 291 | class Hid final : public ServiceFramework<Hid> { |
| 292 | public: | 292 | public: |
| 293 | Hid() : ServiceFramework("hid") { | 293 | Hid() : ServiceFramework("hid") { |
| 294 | // clang-format off | ||
| 294 | static const FunctionInfo functions[] = { | 295 | static const FunctionInfo functions[] = { |
| 295 | {0, &Hid::CreateAppletResource, "CreateAppletResource"}, | 296 | {0, &Hid::CreateAppletResource, "CreateAppletResource"}, |
| 296 | {1, &Hid::ActivateDebugPad, "ActivateDebugPad"}, | 297 | {1, &Hid::ActivateDebugPad, "ActivateDebugPad"}, |
| @@ -333,15 +334,13 @@ public: | |||
| 333 | {102, &Hid::SetSupportedNpadIdType, "SetSupportedNpadIdType"}, | 334 | {102, &Hid::SetSupportedNpadIdType, "SetSupportedNpadIdType"}, |
| 334 | {103, &Hid::ActivateNpad, "ActivateNpad"}, | 335 | {103, &Hid::ActivateNpad, "ActivateNpad"}, |
| 335 | {104, nullptr, "DeactivateNpad"}, | 336 | {104, nullptr, "DeactivateNpad"}, |
| 336 | {106, &Hid::AcquireNpadStyleSetUpdateEventHandle, | 337 | {106, &Hid::AcquireNpadStyleSetUpdateEventHandle, "AcquireNpadStyleSetUpdateEventHandle"}, |
| 337 | "AcquireNpadStyleSetUpdateEventHandle"}, | 338 | {107, &Hid::DisconnectNpad, "DisconnectNpad"}, |
| 338 | {107, nullptr, "DisconnectNpad"}, | ||
| 339 | {108, &Hid::GetPlayerLedPattern, "GetPlayerLedPattern"}, | 339 | {108, &Hid::GetPlayerLedPattern, "GetPlayerLedPattern"}, |
| 340 | {109, nullptr, "ActivateNpadWithRevision"}, | 340 | {109, nullptr, "ActivateNpadWithRevision"}, |
| 341 | {120, &Hid::SetNpadJoyHoldType, "SetNpadJoyHoldType"}, | 341 | {120, &Hid::SetNpadJoyHoldType, "SetNpadJoyHoldType"}, |
| 342 | {121, &Hid::GetNpadJoyHoldType, "GetNpadJoyHoldType"}, | 342 | {121, &Hid::GetNpadJoyHoldType, "GetNpadJoyHoldType"}, |
| 343 | {122, &Hid::SetNpadJoyAssignmentModeSingleByDefault, | 343 | {122, &Hid::SetNpadJoyAssignmentModeSingleByDefault, "SetNpadJoyAssignmentModeSingleByDefault"}, |
| 344 | "SetNpadJoyAssignmentModeSingleByDefault"}, | ||
| 345 | {123, nullptr, "SetNpadJoyAssignmentModeSingleByDefault"}, | 344 | {123, nullptr, "SetNpadJoyAssignmentModeSingleByDefault"}, |
| 346 | {124, &Hid::SetNpadJoyAssignmentModeDual, "SetNpadJoyAssignmentModeDual"}, | 345 | {124, &Hid::SetNpadJoyAssignmentModeDual, "SetNpadJoyAssignmentModeDual"}, |
| 347 | {125, &Hid::MergeSingleJoyAsDualJoy, "MergeSingleJoyAsDualJoy"}, | 346 | {125, &Hid::MergeSingleJoyAsDualJoy, "MergeSingleJoyAsDualJoy"}, |
| @@ -398,6 +397,8 @@ public: | |||
| 398 | {1000, nullptr, "SetNpadCommunicationMode"}, | 397 | {1000, nullptr, "SetNpadCommunicationMode"}, |
| 399 | {1001, nullptr, "GetNpadCommunicationMode"}, | 398 | {1001, nullptr, "GetNpadCommunicationMode"}, |
| 400 | }; | 399 | }; |
| 400 | // clang-format on | ||
| 401 | |||
| 401 | RegisterHandlers(functions); | 402 | RegisterHandlers(functions); |
| 402 | 403 | ||
| 403 | event = Kernel::Event::Create(Kernel::ResetType::OneShot, "hid:EventHandle"); | 404 | event = Kernel::Event::Create(Kernel::ResetType::OneShot, "hid:EventHandle"); |
| @@ -496,6 +497,12 @@ private: | |||
| 496 | LOG_WARNING(Service_HID, "(STUBBED) called"); | 497 | LOG_WARNING(Service_HID, "(STUBBED) called"); |
| 497 | } | 498 | } |
| 498 | 499 | ||
| 500 | void DisconnectNpad(Kernel::HLERequestContext& ctx) { | ||
| 501 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 502 | rb.Push(RESULT_SUCCESS); | ||
| 503 | LOG_WARNING(Service_HID, "(STUBBED) called"); | ||
| 504 | } | ||
| 505 | |||
| 499 | void GetPlayerLedPattern(Kernel::HLERequestContext& ctx) { | 506 | void GetPlayerLedPattern(Kernel::HLERequestContext& ctx) { |
| 500 | IPC::ResponseBuilder rb{ctx, 2}; | 507 | IPC::ResponseBuilder rb{ctx, 2}; |
| 501 | rb.Push(RESULT_SUCCESS); | 508 | rb.Push(RESULT_SUCCESS); |
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp index 38a7b1413..52a649e2f 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp | |||
| @@ -36,30 +36,21 @@ MICROPROFILE_DEFINE(OpenGL_Drawing, "OpenGL", "Drawing", MP_RGB(128, 128, 192)); | |||
| 36 | MICROPROFILE_DEFINE(OpenGL_Blits, "OpenGL", "Blits", MP_RGB(100, 100, 255)); | 36 | MICROPROFILE_DEFINE(OpenGL_Blits, "OpenGL", "Blits", MP_RGB(100, 100, 255)); |
| 37 | MICROPROFILE_DEFINE(OpenGL_CacheManagement, "OpenGL", "Cache Mgmt", MP_RGB(100, 255, 100)); | 37 | MICROPROFILE_DEFINE(OpenGL_CacheManagement, "OpenGL", "Cache Mgmt", MP_RGB(100, 255, 100)); |
| 38 | 38 | ||
| 39 | RasterizerOpenGL::RasterizerOpenGL(Core::Frontend::EmuWindow& window) : emu_window{window} { | 39 | RasterizerOpenGL::RasterizerOpenGL(Core::Frontend::EmuWindow& window) |
| 40 | : emu_window{window}, stream_buffer(GL_ARRAY_BUFFER, STREAM_BUFFER_SIZE) { | ||
| 40 | // Create sampler objects | 41 | // Create sampler objects |
| 41 | for (size_t i = 0; i < texture_samplers.size(); ++i) { | 42 | for (size_t i = 0; i < texture_samplers.size(); ++i) { |
| 42 | texture_samplers[i].Create(); | 43 | texture_samplers[i].Create(); |
| 43 | state.texture_units[i].sampler = texture_samplers[i].sampler.handle; | 44 | state.texture_units[i].sampler = texture_samplers[i].sampler.handle; |
| 44 | } | 45 | } |
| 45 | 46 | ||
| 46 | // Create SSBOs | ||
| 47 | for (size_t stage = 0; stage < ssbos.size(); ++stage) { | ||
| 48 | for (size_t buffer = 0; buffer < ssbos[stage].size(); ++buffer) { | ||
| 49 | ssbos[stage][buffer].Create(); | ||
| 50 | state.draw.const_buffers[stage][buffer].ssbo = ssbos[stage][buffer].handle; | ||
| 51 | } | ||
| 52 | } | ||
| 53 | |||
| 54 | GLint ext_num; | 47 | GLint ext_num; |
| 55 | glGetIntegerv(GL_NUM_EXTENSIONS, &ext_num); | 48 | glGetIntegerv(GL_NUM_EXTENSIONS, &ext_num); |
| 56 | for (GLint i = 0; i < ext_num; i++) { | 49 | for (GLint i = 0; i < ext_num; i++) { |
| 57 | const std::string_view extension{ | 50 | const std::string_view extension{ |
| 58 | reinterpret_cast<const char*>(glGetStringi(GL_EXTENSIONS, i))}; | 51 | reinterpret_cast<const char*>(glGetStringi(GL_EXTENSIONS, i))}; |
| 59 | 52 | ||
| 60 | if (extension == "GL_ARB_buffer_storage") { | 53 | if (extension == "GL_ARB_direct_state_access") { |
| 61 | has_ARB_buffer_storage = true; | ||
| 62 | } else if (extension == "GL_ARB_direct_state_access") { | ||
| 63 | has_ARB_direct_state_access = true; | 54 | has_ARB_direct_state_access = true; |
| 64 | } else if (extension == "GL_ARB_separate_shader_objects") { | 55 | } else if (extension == "GL_ARB_separate_shader_objects") { |
| 65 | has_ARB_separate_shader_objects = true; | 56 | has_ARB_separate_shader_objects = true; |
| @@ -86,47 +77,31 @@ RasterizerOpenGL::RasterizerOpenGL(Core::Frontend::EmuWindow& window) : emu_wind | |||
| 86 | 77 | ||
| 87 | hw_vao.Create(); | 78 | hw_vao.Create(); |
| 88 | 79 | ||
| 89 | stream_buffer = OGLStreamBuffer::MakeBuffer(has_ARB_buffer_storage, GL_ARRAY_BUFFER); | 80 | state.draw.vertex_buffer = stream_buffer.GetHandle(); |
| 90 | stream_buffer->Create(STREAM_BUFFER_SIZE, STREAM_BUFFER_SIZE / 2); | ||
| 91 | state.draw.vertex_buffer = stream_buffer->GetHandle(); | ||
| 92 | 81 | ||
| 93 | shader_program_manager = std::make_unique<GLShader::ProgramManager>(); | 82 | shader_program_manager = std::make_unique<GLShader::ProgramManager>(); |
| 94 | state.draw.shader_program = 0; | 83 | state.draw.shader_program = 0; |
| 95 | state.draw.vertex_array = hw_vao.handle; | 84 | state.draw.vertex_array = hw_vao.handle; |
| 96 | state.Apply(); | 85 | state.Apply(); |
| 97 | 86 | ||
| 98 | glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, stream_buffer->GetHandle()); | 87 | glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, stream_buffer.GetHandle()); |
| 99 | |||
| 100 | for (unsigned index = 0; index < uniform_buffers.size(); ++index) { | ||
| 101 | auto& buffer = uniform_buffers[index]; | ||
| 102 | buffer.Create(); | ||
| 103 | glBindBuffer(GL_UNIFORM_BUFFER, buffer.handle); | ||
| 104 | glBufferData(GL_UNIFORM_BUFFER, sizeof(GLShader::MaxwellUniformData), nullptr, | ||
| 105 | GL_STREAM_COPY); | ||
| 106 | glBindBufferBase(GL_UNIFORM_BUFFER, index, buffer.handle); | ||
| 107 | } | ||
| 108 | 88 | ||
| 109 | glEnable(GL_BLEND); | 89 | glEnable(GL_BLEND); |
| 110 | 90 | ||
| 91 | glGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &uniform_buffer_alignment); | ||
| 92 | |||
| 111 | LOG_CRITICAL(Render_OpenGL, "Sync fixed function OpenGL state here!"); | 93 | LOG_CRITICAL(Render_OpenGL, "Sync fixed function OpenGL state here!"); |
| 112 | } | 94 | } |
| 113 | 95 | ||
| 114 | RasterizerOpenGL::~RasterizerOpenGL() { | 96 | RasterizerOpenGL::~RasterizerOpenGL() {} |
| 115 | if (stream_buffer != nullptr) { | ||
| 116 | state.draw.vertex_buffer = stream_buffer->GetHandle(); | ||
| 117 | state.Apply(); | ||
| 118 | stream_buffer->Release(); | ||
| 119 | } | ||
| 120 | } | ||
| 121 | 97 | ||
| 122 | std::pair<u8*, GLintptr> RasterizerOpenGL::SetupVertexArrays(u8* array_ptr, | 98 | std::pair<u8*, GLintptr> RasterizerOpenGL::SetupVertexArrays(u8* array_ptr, |
| 123 | GLintptr buffer_offset) { | 99 | GLintptr buffer_offset) { |
| 124 | MICROPROFILE_SCOPE(OpenGL_VAO); | 100 | MICROPROFILE_SCOPE(OpenGL_VAO); |
| 125 | const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs; | 101 | const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs; |
| 126 | const auto& memory_manager = Core::System::GetInstance().GPU().memory_manager; | ||
| 127 | 102 | ||
| 128 | state.draw.vertex_array = hw_vao.handle; | 103 | state.draw.vertex_array = hw_vao.handle; |
| 129 | state.draw.vertex_buffer = stream_buffer->GetHandle(); | 104 | state.draw.vertex_buffer = stream_buffer.GetHandle(); |
| 130 | state.Apply(); | 105 | state.Apply(); |
| 131 | 106 | ||
| 132 | // Upload all guest vertex arrays sequentially to our buffer | 107 | // Upload all guest vertex arrays sequentially to our buffer |
| @@ -141,16 +116,15 @@ std::pair<u8*, GLintptr> RasterizerOpenGL::SetupVertexArrays(u8* array_ptr, | |||
| 141 | ASSERT(end > start); | 116 | ASSERT(end > start); |
| 142 | u64 size = end - start + 1; | 117 | u64 size = end - start + 1; |
| 143 | 118 | ||
| 144 | // Copy vertex array data | 119 | GLintptr vertex_buffer_offset; |
| 145 | Memory::ReadBlock(*memory_manager->GpuToCpuAddress(start), array_ptr, size); | 120 | std::tie(array_ptr, buffer_offset, vertex_buffer_offset) = |
| 121 | UploadMemory(array_ptr, buffer_offset, start, size); | ||
| 146 | 122 | ||
| 147 | // Bind the vertex array to the buffer at the current offset. | 123 | // Bind the vertex array to the buffer at the current offset. |
| 148 | glBindVertexBuffer(index, stream_buffer->GetHandle(), buffer_offset, vertex_array.stride); | 124 | glBindVertexBuffer(index, stream_buffer.GetHandle(), vertex_buffer_offset, |
| 125 | vertex_array.stride); | ||
| 149 | 126 | ||
| 150 | ASSERT_MSG(vertex_array.divisor == 0, "Vertex buffer divisor unimplemented"); | 127 | ASSERT_MSG(vertex_array.divisor == 0, "Vertex buffer divisor unimplemented"); |
| 151 | |||
| 152 | array_ptr += size; | ||
| 153 | buffer_offset += size; | ||
| 154 | } | 128 | } |
| 155 | 129 | ||
| 156 | // Use the vertex array as-is, assumes that the data is formatted correctly for OpenGL. | 130 | // Use the vertex array as-is, assumes that the data is formatted correctly for OpenGL. |
| @@ -201,22 +175,12 @@ static GLShader::ProgramCode GetShaderProgramCode(Maxwell::ShaderProgram program | |||
| 201 | return program_code; | 175 | return program_code; |
| 202 | } | 176 | } |
| 203 | 177 | ||
| 204 | void RasterizerOpenGL::SetupShaders(u8* buffer_ptr, GLintptr buffer_offset) { | 178 | std::pair<u8*, GLintptr> RasterizerOpenGL::SetupShaders(u8* buffer_ptr, GLintptr buffer_offset) { |
| 205 | // Helper function for uploading uniform data | ||
| 206 | const auto copy_buffer = [&](GLuint handle, GLintptr offset, GLsizeiptr size) { | ||
| 207 | if (has_ARB_direct_state_access) { | ||
| 208 | glCopyNamedBufferSubData(stream_buffer->GetHandle(), handle, offset, 0, size); | ||
| 209 | } else { | ||
| 210 | glBindBuffer(GL_COPY_WRITE_BUFFER, handle); | ||
| 211 | glCopyBufferSubData(GL_ARRAY_BUFFER, GL_COPY_WRITE_BUFFER, offset, 0, size); | ||
| 212 | } | ||
| 213 | }; | ||
| 214 | |||
| 215 | auto& gpu = Core::System::GetInstance().GPU().Maxwell3D(); | 179 | auto& gpu = Core::System::GetInstance().GPU().Maxwell3D(); |
| 216 | 180 | ||
| 217 | // Next available bindpoints to use when uploading the const buffers and textures to the GLSL | 181 | // Next available bindpoints to use when uploading the const buffers and textures to the GLSL |
| 218 | // shaders. The constbuffer bindpoint starts after the shader stage configuration bind points. | 182 | // shaders. The constbuffer bindpoint starts after the shader stage configuration bind points. |
| 219 | u32 current_constbuffer_bindpoint = static_cast<u32>(uniform_buffers.size()); | 183 | u32 current_constbuffer_bindpoint = Tegra::Engines::Maxwell3D::Regs::MaxShaderStage; |
| 220 | u32 current_texture_bindpoint = 0; | 184 | u32 current_texture_bindpoint = 0; |
| 221 | 185 | ||
| 222 | for (size_t index = 0; index < Maxwell::MaxShaderProgram; ++index) { | 186 | for (size_t index = 0; index < Maxwell::MaxShaderProgram; ++index) { |
| @@ -228,22 +192,21 @@ void RasterizerOpenGL::SetupShaders(u8* buffer_ptr, GLintptr buffer_offset) { | |||
| 228 | continue; | 192 | continue; |
| 229 | } | 193 | } |
| 230 | 194 | ||
| 195 | std::tie(buffer_ptr, buffer_offset) = | ||
| 196 | AlignBuffer(buffer_ptr, buffer_offset, static_cast<size_t>(uniform_buffer_alignment)); | ||
| 197 | |||
| 231 | const size_t stage{index == 0 ? 0 : index - 1}; // Stage indices are 0 - 5 | 198 | const size_t stage{index == 0 ? 0 : index - 1}; // Stage indices are 0 - 5 |
| 232 | 199 | ||
| 233 | GLShader::MaxwellUniformData ubo{}; | 200 | GLShader::MaxwellUniformData ubo{}; |
| 234 | ubo.SetFromRegs(gpu.state.shader_stages[stage]); | 201 | ubo.SetFromRegs(gpu.state.shader_stages[stage]); |
| 235 | std::memcpy(buffer_ptr, &ubo, sizeof(ubo)); | 202 | std::memcpy(buffer_ptr, &ubo, sizeof(ubo)); |
| 236 | 203 | ||
| 237 | // Flush the buffer so that the GPU can see the data we just wrote. | 204 | // Bind the buffer |
| 238 | glFlushMappedBufferRange(GL_ARRAY_BUFFER, buffer_offset, sizeof(ubo)); | 205 | glBindBufferRange(GL_UNIFORM_BUFFER, stage, stream_buffer.GetHandle(), buffer_offset, |
| 239 | 206 | sizeof(ubo)); | |
| 240 | // Upload uniform data as one UBO per stage | ||
| 241 | const GLintptr ubo_offset = buffer_offset; | ||
| 242 | copy_buffer(uniform_buffers[stage].handle, ubo_offset, | ||
| 243 | sizeof(GLShader::MaxwellUniformData)); | ||
| 244 | 207 | ||
| 245 | buffer_ptr += sizeof(GLShader::MaxwellUniformData); | 208 | buffer_ptr += sizeof(ubo); |
| 246 | buffer_offset += sizeof(GLShader::MaxwellUniformData); | 209 | buffer_offset += sizeof(ubo); |
| 247 | 210 | ||
| 248 | GLShader::ShaderSetup setup{GetShaderProgramCode(program)}; | 211 | GLShader::ShaderSetup setup{GetShaderProgramCode(program)}; |
| 249 | GLShader::ShaderEntries shader_resources; | 212 | GLShader::ShaderEntries shader_resources; |
| @@ -282,9 +245,9 @@ void RasterizerOpenGL::SetupShaders(u8* buffer_ptr, GLintptr buffer_offset) { | |||
| 282 | static_cast<Maxwell::ShaderStage>(stage)); | 245 | static_cast<Maxwell::ShaderStage>(stage)); |
| 283 | 246 | ||
| 284 | // Configure the const buffers for this shader stage. | 247 | // Configure the const buffers for this shader stage. |
| 285 | current_constbuffer_bindpoint = | 248 | std::tie(buffer_ptr, buffer_offset, current_constbuffer_bindpoint) = SetupConstBuffers( |
| 286 | SetupConstBuffers(static_cast<Maxwell::ShaderStage>(stage), gl_stage_program, | 249 | buffer_ptr, buffer_offset, static_cast<Maxwell::ShaderStage>(stage), gl_stage_program, |
| 287 | current_constbuffer_bindpoint, shader_resources.const_buffer_entries); | 250 | current_constbuffer_bindpoint, shader_resources.const_buffer_entries); |
| 288 | 251 | ||
| 289 | // Configure the textures for this shader stage. | 252 | // Configure the textures for this shader stage. |
| 290 | current_texture_bindpoint = | 253 | current_texture_bindpoint = |
| @@ -299,6 +262,8 @@ void RasterizerOpenGL::SetupShaders(u8* buffer_ptr, GLintptr buffer_offset) { | |||
| 299 | } | 262 | } |
| 300 | 263 | ||
| 301 | shader_program_manager->UseTrivialGeometryShader(); | 264 | shader_program_manager->UseTrivialGeometryShader(); |
| 265 | |||
| 266 | return {buffer_ptr, buffer_offset}; | ||
| 302 | } | 267 | } |
| 303 | 268 | ||
| 304 | size_t RasterizerOpenGL::CalculateVertexArraysSize() const { | 269 | size_t RasterizerOpenGL::CalculateVertexArraysSize() const { |
| @@ -432,6 +397,31 @@ void RasterizerOpenGL::Clear() { | |||
| 432 | } | 397 | } |
| 433 | } | 398 | } |
| 434 | 399 | ||
| 400 | std::pair<u8*, GLintptr> RasterizerOpenGL::AlignBuffer(u8* buffer_ptr, GLintptr buffer_offset, | ||
| 401 | size_t alignment) { | ||
| 402 | // Align the offset, not the mapped pointer | ||
| 403 | GLintptr offset_aligned = | ||
| 404 | static_cast<GLintptr>(Common::AlignUp(static_cast<size_t>(buffer_offset), alignment)); | ||
| 405 | return {buffer_ptr + (offset_aligned - buffer_offset), offset_aligned}; | ||
| 406 | } | ||
| 407 | |||
| 408 | std::tuple<u8*, GLintptr, GLintptr> RasterizerOpenGL::UploadMemory(u8* buffer_ptr, | ||
| 409 | GLintptr buffer_offset, | ||
| 410 | Tegra::GPUVAddr gpu_addr, | ||
| 411 | size_t size, size_t alignment) { | ||
| 412 | std::tie(buffer_ptr, buffer_offset) = AlignBuffer(buffer_ptr, buffer_offset, alignment); | ||
| 413 | GLintptr uploaded_offset = buffer_offset; | ||
| 414 | |||
| 415 | const auto& memory_manager = Core::System::GetInstance().GPU().memory_manager; | ||
| 416 | const boost::optional<VAddr> cpu_addr{memory_manager->GpuToCpuAddress(gpu_addr)}; | ||
| 417 | Memory::ReadBlock(*cpu_addr, buffer_ptr, size); | ||
| 418 | |||
| 419 | buffer_ptr += size; | ||
| 420 | buffer_offset += size; | ||
| 421 | |||
| 422 | return {buffer_ptr, buffer_offset, uploaded_offset}; | ||
| 423 | } | ||
| 424 | |||
| 435 | void RasterizerOpenGL::DrawArrays() { | 425 | void RasterizerOpenGL::DrawArrays() { |
| 436 | if (accelerate_draw == AccelDraw::Disabled) | 426 | if (accelerate_draw == AccelDraw::Disabled) |
| 437 | return; | 427 | return; |
| @@ -456,7 +446,7 @@ void RasterizerOpenGL::DrawArrays() { | |||
| 456 | const u64 index_buffer_size{regs.index_array.count * regs.index_array.FormatSizeInBytes()}; | 446 | const u64 index_buffer_size{regs.index_array.count * regs.index_array.FormatSizeInBytes()}; |
| 457 | const unsigned vertex_num{is_indexed ? regs.index_array.count : regs.vertex_buffer.count}; | 447 | const unsigned vertex_num{is_indexed ? regs.index_array.count : regs.vertex_buffer.count}; |
| 458 | 448 | ||
| 459 | state.draw.vertex_buffer = stream_buffer->GetHandle(); | 449 | state.draw.vertex_buffer = stream_buffer.GetHandle(); |
| 460 | state.Apply(); | 450 | state.Apply(); |
| 461 | 451 | ||
| 462 | size_t buffer_size = CalculateVertexArraysSize(); | 452 | size_t buffer_size = CalculateVertexArraysSize(); |
| @@ -466,41 +456,31 @@ void RasterizerOpenGL::DrawArrays() { | |||
| 466 | } | 456 | } |
| 467 | 457 | ||
| 468 | // Uniform space for the 5 shader stages | 458 | // Uniform space for the 5 shader stages |
| 469 | buffer_size = Common::AlignUp<size_t>(buffer_size, 4) + | 459 | buffer_size = |
| 470 | sizeof(GLShader::MaxwellUniformData) * Maxwell::MaxShaderStage; | 460 | Common::AlignUp<size_t>(buffer_size, 4) + |
| 461 | (sizeof(GLShader::MaxwellUniformData) + uniform_buffer_alignment) * Maxwell::MaxShaderStage; | ||
| 462 | |||
| 463 | // Add space for at least 18 constant buffers | ||
| 464 | buffer_size += Maxwell::MaxConstBuffers * (MaxConstbufferSize + uniform_buffer_alignment); | ||
| 471 | 465 | ||
| 472 | u8* buffer_ptr; | 466 | u8* buffer_ptr; |
| 473 | GLintptr buffer_offset; | 467 | GLintptr buffer_offset; |
| 474 | std::tie(buffer_ptr, buffer_offset) = | 468 | std::tie(buffer_ptr, buffer_offset, std::ignore) = |
| 475 | stream_buffer->Map(static_cast<GLsizeiptr>(buffer_size), 4); | 469 | stream_buffer.Map(static_cast<GLsizeiptr>(buffer_size), 4); |
| 470 | u8* buffer_ptr_base = buffer_ptr; | ||
| 476 | 471 | ||
| 477 | u8* offseted_buffer; | 472 | std::tie(buffer_ptr, buffer_offset) = SetupVertexArrays(buffer_ptr, buffer_offset); |
| 478 | std::tie(offseted_buffer, buffer_offset) = SetupVertexArrays(buffer_ptr, buffer_offset); | ||
| 479 | |||
| 480 | offseted_buffer = | ||
| 481 | reinterpret_cast<u8*>(Common::AlignUp(reinterpret_cast<size_t>(offseted_buffer), 4)); | ||
| 482 | buffer_offset = Common::AlignUp<size_t>(buffer_offset, 4); | ||
| 483 | 473 | ||
| 484 | // If indexed mode, copy the index buffer | 474 | // If indexed mode, copy the index buffer |
| 485 | GLintptr index_buffer_offset = 0; | 475 | GLintptr index_buffer_offset = 0; |
| 486 | if (is_indexed) { | 476 | if (is_indexed) { |
| 487 | const auto& memory_manager = Core::System::GetInstance().GPU().memory_manager; | 477 | std::tie(buffer_ptr, buffer_offset, index_buffer_offset) = UploadMemory( |
| 488 | const boost::optional<VAddr> index_data_addr{ | 478 | buffer_ptr, buffer_offset, regs.index_array.StartAddress(), index_buffer_size); |
| 489 | memory_manager->GpuToCpuAddress(regs.index_array.StartAddress())}; | ||
| 490 | Memory::ReadBlock(*index_data_addr, offseted_buffer, index_buffer_size); | ||
| 491 | |||
| 492 | index_buffer_offset = buffer_offset; | ||
| 493 | offseted_buffer += index_buffer_size; | ||
| 494 | buffer_offset += index_buffer_size; | ||
| 495 | } | 479 | } |
| 496 | 480 | ||
| 497 | offseted_buffer = | 481 | std::tie(buffer_ptr, buffer_offset) = SetupShaders(buffer_ptr, buffer_offset); |
| 498 | reinterpret_cast<u8*>(Common::AlignUp(reinterpret_cast<size_t>(offseted_buffer), 4)); | ||
| 499 | buffer_offset = Common::AlignUp<size_t>(buffer_offset, 4); | ||
| 500 | |||
| 501 | SetupShaders(offseted_buffer, buffer_offset); | ||
| 502 | 482 | ||
| 503 | stream_buffer->Unmap(); | 483 | stream_buffer.Unmap(buffer_ptr - buffer_ptr_base); |
| 504 | 484 | ||
| 505 | shader_program_manager->ApplyTo(state); | 485 | shader_program_manager->ApplyTo(state); |
| 506 | state.Apply(); | 486 | state.Apply(); |
| @@ -647,36 +627,23 @@ void RasterizerOpenGL::SamplerInfo::SyncWithConfig(const Tegra::Texture::TSCEntr | |||
| 647 | } | 627 | } |
| 648 | } | 628 | } |
| 649 | 629 | ||
| 650 | u32 RasterizerOpenGL::SetupConstBuffers(Maxwell::ShaderStage stage, GLuint program, | 630 | std::tuple<u8*, GLintptr, u32> RasterizerOpenGL::SetupConstBuffers( |
| 651 | u32 current_bindpoint, | 631 | u8* buffer_ptr, GLintptr buffer_offset, Maxwell::ShaderStage stage, GLuint program, |
| 652 | const std::vector<GLShader::ConstBufferEntry>& entries) { | 632 | u32 current_bindpoint, const std::vector<GLShader::ConstBufferEntry>& entries) { |
| 653 | const auto& gpu = Core::System::GetInstance().GPU(); | 633 | const auto& gpu = Core::System::GetInstance().GPU(); |
| 654 | const auto& maxwell3d = gpu.Maxwell3D(); | 634 | const auto& maxwell3d = gpu.Maxwell3D(); |
| 655 | 635 | ||
| 656 | // Reset all buffer draw state for this stage. | ||
| 657 | for (auto& buffer : state.draw.const_buffers[static_cast<size_t>(stage)]) { | ||
| 658 | buffer.bindpoint = 0; | ||
| 659 | buffer.enabled = false; | ||
| 660 | } | ||
| 661 | |||
| 662 | // Upload only the enabled buffers from the 16 constbuffers of each shader stage | 636 | // Upload only the enabled buffers from the 16 constbuffers of each shader stage |
| 663 | const auto& shader_stage = maxwell3d.state.shader_stages[static_cast<size_t>(stage)]; | 637 | const auto& shader_stage = maxwell3d.state.shader_stages[static_cast<size_t>(stage)]; |
| 664 | 638 | ||
| 665 | for (u32 bindpoint = 0; bindpoint < entries.size(); ++bindpoint) { | 639 | for (u32 bindpoint = 0; bindpoint < entries.size(); ++bindpoint) { |
| 666 | const auto& used_buffer = entries[bindpoint]; | 640 | const auto& used_buffer = entries[bindpoint]; |
| 667 | const auto& buffer = shader_stage.const_buffers[used_buffer.GetIndex()]; | 641 | const auto& buffer = shader_stage.const_buffers[used_buffer.GetIndex()]; |
| 668 | auto& buffer_draw_state = | ||
| 669 | state.draw.const_buffers[static_cast<size_t>(stage)][used_buffer.GetIndex()]; | ||
| 670 | 642 | ||
| 671 | if (!buffer.enabled) { | 643 | if (!buffer.enabled) { |
| 672 | continue; | 644 | continue; |
| 673 | } | 645 | } |
| 674 | 646 | ||
| 675 | buffer_draw_state.enabled = true; | ||
| 676 | buffer_draw_state.bindpoint = current_bindpoint + bindpoint; | ||
| 677 | |||
| 678 | boost::optional<VAddr> addr = gpu.memory_manager->GpuToCpuAddress(buffer.address); | ||
| 679 | |||
| 680 | size_t size = 0; | 647 | size_t size = 0; |
| 681 | 648 | ||
| 682 | if (used_buffer.IsIndirect()) { | 649 | if (used_buffer.IsIndirect()) { |
| @@ -698,25 +665,26 @@ u32 RasterizerOpenGL::SetupConstBuffers(Maxwell::ShaderStage stage, GLuint progr | |||
| 698 | size = Common::AlignUp(size, sizeof(GLvec4)); | 665 | size = Common::AlignUp(size, sizeof(GLvec4)); |
| 699 | ASSERT_MSG(size <= MaxConstbufferSize, "Constbuffer too big"); | 666 | ASSERT_MSG(size <= MaxConstbufferSize, "Constbuffer too big"); |
| 700 | 667 | ||
| 701 | std::vector<u8> data(size); | 668 | GLintptr const_buffer_offset; |
| 702 | Memory::ReadBlock(*addr, data.data(), data.size()); | 669 | std::tie(buffer_ptr, buffer_offset, const_buffer_offset) = |
| 670 | UploadMemory(buffer_ptr, buffer_offset, buffer.address, size, | ||
| 671 | static_cast<size_t>(uniform_buffer_alignment)); | ||
| 703 | 672 | ||
| 704 | glBindBuffer(GL_UNIFORM_BUFFER, buffer_draw_state.ssbo); | 673 | glBindBufferRange(GL_UNIFORM_BUFFER, current_bindpoint + bindpoint, |
| 705 | glBufferData(GL_UNIFORM_BUFFER, data.size(), data.data(), GL_DYNAMIC_DRAW); | 674 | stream_buffer.GetHandle(), const_buffer_offset, size); |
| 706 | glBindBuffer(GL_UNIFORM_BUFFER, 0); | ||
| 707 | 675 | ||
| 708 | // Now configure the bindpoint of the buffer inside the shader | 676 | // Now configure the bindpoint of the buffer inside the shader |
| 709 | const std::string buffer_name = used_buffer.GetName(); | 677 | const std::string buffer_name = used_buffer.GetName(); |
| 710 | const GLuint index = | 678 | const GLuint index = |
| 711 | glGetProgramResourceIndex(program, GL_UNIFORM_BLOCK, buffer_name.c_str()); | 679 | glGetProgramResourceIndex(program, GL_UNIFORM_BLOCK, buffer_name.c_str()); |
| 712 | if (index != GL_INVALID_INDEX) { | 680 | if (index != GL_INVALID_INDEX) { |
| 713 | glUniformBlockBinding(program, index, buffer_draw_state.bindpoint); | 681 | glUniformBlockBinding(program, index, current_bindpoint + bindpoint); |
| 714 | } | 682 | } |
| 715 | } | 683 | } |
| 716 | 684 | ||
| 717 | state.Apply(); | 685 | state.Apply(); |
| 718 | 686 | ||
| 719 | return current_bindpoint + static_cast<u32>(entries.size()); | 687 | return {buffer_ptr, buffer_offset, current_bindpoint + static_cast<u32>(entries.size())}; |
| 720 | } | 688 | } |
| 721 | 689 | ||
| 722 | u32 RasterizerOpenGL::SetupTextures(Maxwell::ShaderStage stage, GLuint program, u32 current_unit, | 690 | u32 RasterizerOpenGL::SetupTextures(Maxwell::ShaderStage stage, GLuint program, u32 current_unit, |
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h index bd01dc0ae..74307f626 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.h +++ b/src/video_core/renderer_opengl/gl_rasterizer.h | |||
| @@ -7,6 +7,7 @@ | |||
| 7 | #include <array> | 7 | #include <array> |
| 8 | #include <cstddef> | 8 | #include <cstddef> |
| 9 | #include <memory> | 9 | #include <memory> |
| 10 | #include <tuple> | ||
| 10 | #include <utility> | 11 | #include <utility> |
| 11 | #include <vector> | 12 | #include <vector> |
| 12 | #include <glad/glad.h> | 13 | #include <glad/glad.h> |
| @@ -100,9 +101,10 @@ private: | |||
| 100 | * @param entries Vector describing the buffers that are actually used in the guest shader. | 101 | * @param entries Vector describing the buffers that are actually used in the guest shader. |
| 101 | * @returns The next available bindpoint for use in the next shader stage. | 102 | * @returns The next available bindpoint for use in the next shader stage. |
| 102 | */ | 103 | */ |
| 103 | u32 SetupConstBuffers(Tegra::Engines::Maxwell3D::Regs::ShaderStage stage, GLuint program, | 104 | std::tuple<u8*, GLintptr, u32> SetupConstBuffers( |
| 104 | u32 current_bindpoint, | 105 | u8* buffer_ptr, GLintptr buffer_offset, Tegra::Engines::Maxwell3D::Regs::ShaderStage stage, |
| 105 | const std::vector<GLShader::ConstBufferEntry>& entries); | 106 | GLuint program, u32 current_bindpoint, |
| 107 | const std::vector<GLShader::ConstBufferEntry>& entries); | ||
| 106 | 108 | ||
| 107 | /* | 109 | /* |
| 108 | * Configures the current textures to use for the draw command. | 110 | * Configures the current textures to use for the draw command. |
| @@ -139,7 +141,6 @@ private: | |||
| 139 | /// Syncs the blend state to match the guest state | 141 | /// Syncs the blend state to match the guest state |
| 140 | void SyncBlendState(); | 142 | void SyncBlendState(); |
| 141 | 143 | ||
| 142 | bool has_ARB_buffer_storage = false; | ||
| 143 | bool has_ARB_direct_state_access = false; | 144 | bool has_ARB_direct_state_access = false; |
| 144 | bool has_ARB_separate_shader_objects = false; | 145 | bool has_ARB_separate_shader_objects = false; |
| 145 | bool has_ARB_vertex_attrib_binding = false; | 146 | bool has_ARB_vertex_attrib_binding = false; |
| @@ -155,22 +156,24 @@ private: | |||
| 155 | OGLVertexArray hw_vao; | 156 | OGLVertexArray hw_vao; |
| 156 | 157 | ||
| 157 | std::array<SamplerInfo, GLShader::NumTextureSamplers> texture_samplers; | 158 | std::array<SamplerInfo, GLShader::NumTextureSamplers> texture_samplers; |
| 158 | std::array<std::array<OGLBuffer, Tegra::Engines::Maxwell3D::Regs::MaxConstBuffers>, | ||
| 159 | Tegra::Engines::Maxwell3D::Regs::MaxShaderStage> | ||
| 160 | ssbos; | ||
| 161 | 159 | ||
| 162 | static constexpr size_t STREAM_BUFFER_SIZE = 128 * 1024 * 1024; | 160 | static constexpr size_t STREAM_BUFFER_SIZE = 128 * 1024 * 1024; |
| 163 | std::unique_ptr<OGLStreamBuffer> stream_buffer; | 161 | OGLStreamBuffer stream_buffer; |
| 164 | OGLBuffer uniform_buffer; | 162 | OGLBuffer uniform_buffer; |
| 165 | OGLFramebuffer framebuffer; | 163 | OGLFramebuffer framebuffer; |
| 164 | GLint uniform_buffer_alignment; | ||
| 166 | 165 | ||
| 167 | size_t CalculateVertexArraysSize() const; | 166 | size_t CalculateVertexArraysSize() const; |
| 168 | 167 | ||
| 169 | std::pair<u8*, GLintptr> SetupVertexArrays(u8* array_ptr, GLintptr buffer_offset); | 168 | std::pair<u8*, GLintptr> SetupVertexArrays(u8* array_ptr, GLintptr buffer_offset); |
| 170 | 169 | ||
| 171 | std::array<OGLBuffer, Tegra::Engines::Maxwell3D::Regs::MaxShaderStage> uniform_buffers; | 170 | std::pair<u8*, GLintptr> SetupShaders(u8* buffer_ptr, GLintptr buffer_offset); |
| 172 | 171 | ||
| 173 | void SetupShaders(u8* buffer_ptr, GLintptr buffer_offset); | 172 | std::pair<u8*, GLintptr> AlignBuffer(u8* buffer_ptr, GLintptr buffer_offset, size_t alignment); |
| 173 | |||
| 174 | std::tuple<u8*, GLintptr, GLintptr> UploadMemory(u8* buffer_ptr, GLintptr buffer_offset, | ||
| 175 | Tegra::GPUVAddr gpu_addr, size_t size, | ||
| 176 | size_t alignment = 4); | ||
| 174 | 177 | ||
| 175 | enum class AccelDraw { Disabled, Arrays, Indexed }; | 178 | enum class AccelDraw { Disabled, Arrays, Indexed }; |
| 176 | AccelDraw accelerate_draw = AccelDraw::Disabled; | 179 | AccelDraw accelerate_draw = AccelDraw::Disabled; |
diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp index 85297bd00..7e038ac86 100644 --- a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp +++ b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp | |||
| @@ -356,13 +356,13 @@ public: | |||
| 356 | * @param reg The register to use as the source value. | 356 | * @param reg The register to use as the source value. |
| 357 | */ | 357 | */ |
| 358 | void SetOutputAttributeToRegister(Attribute::Index attribute, u64 elem, const Register& reg) { | 358 | void SetOutputAttributeToRegister(Attribute::Index attribute, u64 elem, const Register& reg) { |
| 359 | std::string dest = GetOutputAttribute(attribute) + GetSwizzle(elem); | 359 | std::string dest = GetOutputAttribute(attribute); |
| 360 | std::string src = GetRegisterAsFloat(reg); | 360 | std::string src = GetRegisterAsFloat(reg); |
| 361 | 361 | ||
| 362 | if (!dest.empty()) { | 362 | if (!dest.empty()) { |
| 363 | // Can happen with unknown/unimplemented output attributes, in which case we ignore the | 363 | // Can happen with unknown/unimplemented output attributes, in which case we ignore the |
| 364 | // instruction for now. | 364 | // instruction for now. |
| 365 | shader.AddLine(dest + " = " + src + ';'); | 365 | shader.AddLine(dest + GetSwizzle(elem) + " = " + src + ';'); |
| 366 | } | 366 | } |
| 367 | } | 367 | } |
| 368 | 368 | ||
| @@ -1667,7 +1667,15 @@ private: | |||
| 1667 | } | 1667 | } |
| 1668 | case OpCode::Id::KIL: { | 1668 | case OpCode::Id::KIL: { |
| 1669 | ASSERT(instr.flow.cond == Tegra::Shader::FlowCondition::Always); | 1669 | ASSERT(instr.flow.cond == Tegra::Shader::FlowCondition::Always); |
| 1670 | |||
| 1671 | // Enclose "discard" in a conditional, so that GLSL compilation does not complain | ||
| 1672 | // about unexecuted instructions that may follow this. | ||
| 1673 | shader.AddLine("if (true) {"); | ||
| 1674 | ++shader.scope; | ||
| 1670 | shader.AddLine("discard;"); | 1675 | shader.AddLine("discard;"); |
| 1676 | --shader.scope; | ||
| 1677 | shader.AddLine("}"); | ||
| 1678 | |||
| 1671 | break; | 1679 | break; |
| 1672 | } | 1680 | } |
| 1673 | case OpCode::Id::BRA: { | 1681 | case OpCode::Id::BRA: { |
diff --git a/src/video_core/renderer_opengl/gl_state.cpp b/src/video_core/renderer_opengl/gl_state.cpp index 68bacd4c5..1d1975179 100644 --- a/src/video_core/renderer_opengl/gl_state.cpp +++ b/src/video_core/renderer_opengl/gl_state.cpp | |||
| @@ -203,21 +203,6 @@ void OpenGLState::Apply() const { | |||
| 203 | } | 203 | } |
| 204 | } | 204 | } |
| 205 | 205 | ||
| 206 | // Constbuffers | ||
| 207 | for (std::size_t stage = 0; stage < draw.const_buffers.size(); ++stage) { | ||
| 208 | for (std::size_t buffer_id = 0; buffer_id < draw.const_buffers[stage].size(); ++buffer_id) { | ||
| 209 | const auto& current = cur_state.draw.const_buffers[stage][buffer_id]; | ||
| 210 | const auto& new_state = draw.const_buffers[stage][buffer_id]; | ||
| 211 | |||
| 212 | if (current.enabled != new_state.enabled || current.bindpoint != new_state.bindpoint || | ||
| 213 | current.ssbo != new_state.ssbo) { | ||
| 214 | if (new_state.enabled) { | ||
| 215 | glBindBufferBase(GL_UNIFORM_BUFFER, new_state.bindpoint, new_state.ssbo); | ||
| 216 | } | ||
| 217 | } | ||
| 218 | } | ||
| 219 | } | ||
| 220 | |||
| 221 | // Framebuffer | 206 | // Framebuffer |
| 222 | if (draw.read_framebuffer != cur_state.draw.read_framebuffer) { | 207 | if (draw.read_framebuffer != cur_state.draw.read_framebuffer) { |
| 223 | glBindFramebuffer(GL_READ_FRAMEBUFFER, draw.read_framebuffer); | 208 | glBindFramebuffer(GL_READ_FRAMEBUFFER, draw.read_framebuffer); |
diff --git a/src/video_core/renderer_opengl/gl_state.h b/src/video_core/renderer_opengl/gl_state.h index 5c7b636e4..bdb02ba25 100644 --- a/src/video_core/renderer_opengl/gl_state.h +++ b/src/video_core/renderer_opengl/gl_state.h | |||
| @@ -119,12 +119,6 @@ public: | |||
| 119 | GLuint uniform_buffer; // GL_UNIFORM_BUFFER_BINDING | 119 | GLuint uniform_buffer; // GL_UNIFORM_BUFFER_BINDING |
| 120 | GLuint shader_program; // GL_CURRENT_PROGRAM | 120 | GLuint shader_program; // GL_CURRENT_PROGRAM |
| 121 | GLuint program_pipeline; // GL_PROGRAM_PIPELINE_BINDING | 121 | GLuint program_pipeline; // GL_PROGRAM_PIPELINE_BINDING |
| 122 | struct ConstBufferConfig { | ||
| 123 | bool enabled = false; | ||
| 124 | GLuint bindpoint; | ||
| 125 | GLuint ssbo; | ||
| 126 | }; | ||
| 127 | std::array<std::array<ConstBufferConfig, Regs::MaxConstBuffers>, 5> const_buffers; | ||
| 128 | } draw; | 122 | } draw; |
| 129 | 123 | ||
| 130 | struct { | 124 | struct { |
diff --git a/src/video_core/renderer_opengl/gl_stream_buffer.cpp b/src/video_core/renderer_opengl/gl_stream_buffer.cpp index a2713e9f0..03a8ed8b7 100644 --- a/src/video_core/renderer_opengl/gl_stream_buffer.cpp +++ b/src/video_core/renderer_opengl/gl_stream_buffer.cpp | |||
| @@ -9,174 +9,91 @@ | |||
| 9 | #include "video_core/renderer_opengl/gl_state.h" | 9 | #include "video_core/renderer_opengl/gl_state.h" |
| 10 | #include "video_core/renderer_opengl/gl_stream_buffer.h" | 10 | #include "video_core/renderer_opengl/gl_stream_buffer.h" |
| 11 | 11 | ||
| 12 | class OrphanBuffer : public OGLStreamBuffer { | 12 | OGLStreamBuffer::OGLStreamBuffer(GLenum target, GLsizeiptr size, bool prefer_coherent) |
| 13 | public: | 13 | : gl_target(target), buffer_size(size) { |
| 14 | explicit OrphanBuffer(GLenum target) : OGLStreamBuffer(target) {} | 14 | gl_buffer.Create(); |
| 15 | ~OrphanBuffer() override; | 15 | glBindBuffer(gl_target, gl_buffer.handle); |
| 16 | |||
| 17 | private: | ||
| 18 | void Create(size_t size, size_t sync_subdivide) override; | ||
| 19 | void Release() override; | ||
| 20 | |||
| 21 | std::pair<u8*, GLintptr> Map(size_t size, size_t alignment) override; | ||
| 22 | void Unmap() override; | ||
| 23 | |||
| 24 | std::vector<u8> data; | ||
| 25 | }; | ||
| 26 | |||
| 27 | class StorageBuffer : public OGLStreamBuffer { | ||
| 28 | public: | ||
| 29 | explicit StorageBuffer(GLenum target) : OGLStreamBuffer(target) {} | ||
| 30 | ~StorageBuffer() override; | ||
| 31 | |||
| 32 | private: | ||
| 33 | void Create(size_t size, size_t sync_subdivide) override; | ||
| 34 | void Release() override; | ||
| 35 | |||
| 36 | std::pair<u8*, GLintptr> Map(size_t size, size_t alignment) override; | ||
| 37 | void Unmap() override; | ||
| 38 | |||
| 39 | struct Fence { | ||
| 40 | OGLSync sync; | ||
| 41 | size_t offset; | ||
| 42 | }; | ||
| 43 | std::deque<Fence> head; | ||
| 44 | std::deque<Fence> tail; | ||
| 45 | |||
| 46 | u8* mapped_ptr; | ||
| 47 | }; | ||
| 48 | |||
| 49 | OGLStreamBuffer::OGLStreamBuffer(GLenum target) { | ||
| 50 | gl_target = target; | ||
| 51 | } | ||
| 52 | |||
| 53 | GLuint OGLStreamBuffer::GetHandle() const { | ||
| 54 | return gl_buffer.handle; | ||
| 55 | } | ||
| 56 | 16 | ||
| 57 | std::unique_ptr<OGLStreamBuffer> OGLStreamBuffer::MakeBuffer(bool storage_buffer, GLenum target) { | 17 | GLsizeiptr allocate_size = size; |
| 58 | if (storage_buffer) { | 18 | if (target == GL_ARRAY_BUFFER) { |
| 59 | return std::make_unique<StorageBuffer>(target); | 19 | // On AMD GPU there is a strange crash in indexed drawing. The crash happens when the buffer |
| 20 | // read position is near the end and is an out-of-bound access to the vertex buffer. This is | ||
| 21 | // probably a bug in the driver and is related to the usage of vec3<byte> attributes in the | ||
| 22 | // vertex array. Doubling the allocation size for the vertex buffer seems to avoid the | ||
| 23 | // crash. | ||
| 24 | allocate_size *= 2; | ||
| 60 | } | 25 | } |
| 61 | return std::make_unique<OrphanBuffer>(target); | ||
| 62 | } | ||
| 63 | 26 | ||
| 64 | OrphanBuffer::~OrphanBuffer() { | 27 | if (GLAD_GL_ARB_buffer_storage) { |
| 65 | Release(); | 28 | persistent = true; |
| 29 | coherent = prefer_coherent; | ||
| 30 | GLbitfield flags = | ||
| 31 | GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT | (coherent ? GL_MAP_COHERENT_BIT : 0); | ||
| 32 | glBufferStorage(gl_target, allocate_size, nullptr, flags); | ||
| 33 | mapped_ptr = static_cast<u8*>(glMapBufferRange( | ||
| 34 | gl_target, 0, buffer_size, flags | (coherent ? 0 : GL_MAP_FLUSH_EXPLICIT_BIT))); | ||
| 35 | } else { | ||
| 36 | glBufferData(gl_target, allocate_size, nullptr, GL_STREAM_DRAW); | ||
| 37 | } | ||
| 66 | } | 38 | } |
| 67 | 39 | ||
| 68 | void OrphanBuffer::Create(size_t size, size_t /*sync_subdivide*/) { | 40 | OGLStreamBuffer::~OGLStreamBuffer() { |
| 69 | buffer_pos = 0; | 41 | if (persistent) { |
| 70 | buffer_size = size; | ||
| 71 | data.resize(buffer_size); | ||
| 72 | |||
| 73 | if (gl_buffer.handle == 0) { | ||
| 74 | gl_buffer.Create(); | ||
| 75 | glBindBuffer(gl_target, gl_buffer.handle); | 42 | glBindBuffer(gl_target, gl_buffer.handle); |
| 43 | glUnmapBuffer(gl_target); | ||
| 76 | } | 44 | } |
| 77 | |||
| 78 | glBufferData(gl_target, static_cast<GLsizeiptr>(buffer_size), nullptr, GL_STREAM_DRAW); | ||
| 79 | } | ||
| 80 | |||
| 81 | void OrphanBuffer::Release() { | ||
| 82 | gl_buffer.Release(); | 45 | gl_buffer.Release(); |
| 83 | } | 46 | } |
| 84 | 47 | ||
| 85 | std::pair<u8*, GLintptr> OrphanBuffer::Map(size_t size, size_t alignment) { | 48 | GLuint OGLStreamBuffer::GetHandle() const { |
| 86 | buffer_pos = Common::AlignUp(buffer_pos, alignment); | 49 | return gl_buffer.handle; |
| 87 | |||
| 88 | if (buffer_pos + size > buffer_size) { | ||
| 89 | Create(std::max(buffer_size, size), 0); | ||
| 90 | } | ||
| 91 | |||
| 92 | mapped_size = size; | ||
| 93 | return std::make_pair(&data[buffer_pos], static_cast<GLintptr>(buffer_pos)); | ||
| 94 | } | ||
| 95 | |||
| 96 | void OrphanBuffer::Unmap() { | ||
| 97 | glBufferSubData(gl_target, static_cast<GLintptr>(buffer_pos), | ||
| 98 | static_cast<GLsizeiptr>(mapped_size), &data[buffer_pos]); | ||
| 99 | buffer_pos += mapped_size; | ||
| 100 | } | ||
| 101 | |||
| 102 | StorageBuffer::~StorageBuffer() { | ||
| 103 | Release(); | ||
| 104 | } | 50 | } |
| 105 | 51 | ||
| 106 | void StorageBuffer::Create(size_t size, size_t sync_subdivide) { | 52 | GLsizeiptr OGLStreamBuffer::GetSize() const { |
| 107 | if (gl_buffer.handle != 0) | 53 | return buffer_size; |
| 108 | return; | ||
| 109 | |||
| 110 | buffer_pos = 0; | ||
| 111 | buffer_size = size; | ||
| 112 | buffer_sync_subdivide = std::max<size_t>(sync_subdivide, 1); | ||
| 113 | |||
| 114 | gl_buffer.Create(); | ||
| 115 | glBindBuffer(gl_target, gl_buffer.handle); | ||
| 116 | |||
| 117 | glBufferStorage(gl_target, static_cast<GLsizeiptr>(buffer_size), nullptr, | ||
| 118 | GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT); | ||
| 119 | mapped_ptr = reinterpret_cast<u8*>( | ||
| 120 | glMapBufferRange(gl_target, 0, static_cast<GLsizeiptr>(buffer_size), | ||
| 121 | GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT | GL_MAP_FLUSH_EXPLICIT_BIT)); | ||
| 122 | } | 54 | } |
| 123 | 55 | ||
| 124 | void StorageBuffer::Release() { | 56 | std::tuple<u8*, GLintptr, bool> OGLStreamBuffer::Map(GLsizeiptr size, GLintptr alignment) { |
| 125 | if (gl_buffer.handle == 0) | ||
| 126 | return; | ||
| 127 | |||
| 128 | glUnmapBuffer(gl_target); | ||
| 129 | |||
| 130 | gl_buffer.Release(); | ||
| 131 | head.clear(); | ||
| 132 | tail.clear(); | ||
| 133 | } | ||
| 134 | |||
| 135 | std::pair<u8*, GLintptr> StorageBuffer::Map(size_t size, size_t alignment) { | ||
| 136 | ASSERT(size <= buffer_size); | 57 | ASSERT(size <= buffer_size); |
| 58 | ASSERT(alignment <= buffer_size); | ||
| 59 | mapped_size = size; | ||
| 137 | 60 | ||
| 138 | OGLSync sync; | 61 | if (alignment > 0) { |
| 139 | 62 | buffer_pos = Common::AlignUp<size_t>(buffer_pos, alignment); | |
| 140 | buffer_pos = Common::AlignUp(buffer_pos, alignment); | ||
| 141 | size_t effective_offset = Common::AlignDown(buffer_pos, buffer_sync_subdivide); | ||
| 142 | |||
| 143 | if (!head.empty() && | ||
| 144 | (effective_offset > head.back().offset || buffer_pos + size > buffer_size)) { | ||
| 145 | ASSERT(head.back().sync.handle == 0); | ||
| 146 | head.back().sync.Create(); | ||
| 147 | } | 63 | } |
| 148 | 64 | ||
| 65 | bool invalidate = false; | ||
| 149 | if (buffer_pos + size > buffer_size) { | 66 | if (buffer_pos + size > buffer_size) { |
| 150 | if (!tail.empty()) { | ||
| 151 | std::swap(sync, tail.back().sync); | ||
| 152 | tail.clear(); | ||
| 153 | } | ||
| 154 | std::swap(tail, head); | ||
| 155 | buffer_pos = 0; | 67 | buffer_pos = 0; |
| 156 | effective_offset = 0; | 68 | invalidate = true; |
| 157 | } | ||
| 158 | 69 | ||
| 159 | while (!tail.empty() && buffer_pos + size > tail.front().offset) { | 70 | if (persistent) { |
| 160 | std::swap(sync, tail.front().sync); | 71 | glUnmapBuffer(gl_target); |
| 161 | tail.pop_front(); | 72 | } |
| 162 | } | 73 | } |
| 163 | 74 | ||
| 164 | if (sync.handle != 0) { | 75 | if (invalidate | !persistent) { |
| 165 | glClientWaitSync(sync.handle, GL_SYNC_FLUSH_COMMANDS_BIT, GL_TIMEOUT_IGNORED); | 76 | GLbitfield flags = GL_MAP_WRITE_BIT | (persistent ? GL_MAP_PERSISTENT_BIT : 0) | |
| 166 | sync.Release(); | 77 | (coherent ? GL_MAP_COHERENT_BIT : GL_MAP_FLUSH_EXPLICIT_BIT) | |
| 78 | (invalidate ? GL_MAP_INVALIDATE_BUFFER_BIT : GL_MAP_UNSYNCHRONIZED_BIT); | ||
| 79 | mapped_ptr = static_cast<u8*>( | ||
| 80 | glMapBufferRange(gl_target, buffer_pos, buffer_size - buffer_pos, flags)); | ||
| 81 | mapped_offset = buffer_pos; | ||
| 167 | } | 82 | } |
| 168 | 83 | ||
| 169 | if (head.empty() || effective_offset > head.back().offset) { | 84 | return std::make_tuple(mapped_ptr + buffer_pos - mapped_offset, buffer_pos, invalidate); |
| 170 | head.emplace_back(); | 85 | } |
| 171 | head.back().offset = effective_offset; | 86 | |
| 87 | void OGLStreamBuffer::Unmap(GLsizeiptr size) { | ||
| 88 | ASSERT(size <= mapped_size); | ||
| 89 | |||
| 90 | if (!coherent && size > 0) { | ||
| 91 | glFlushMappedBufferRange(gl_target, buffer_pos - mapped_offset, size); | ||
| 172 | } | 92 | } |
| 173 | 93 | ||
| 174 | mapped_size = size; | 94 | if (!persistent) { |
| 175 | return std::make_pair(&mapped_ptr[buffer_pos], static_cast<GLintptr>(buffer_pos)); | 95 | glUnmapBuffer(gl_target); |
| 176 | } | 96 | } |
| 177 | 97 | ||
| 178 | void StorageBuffer::Unmap() { | 98 | buffer_pos += size; |
| 179 | glFlushMappedBufferRange(gl_target, static_cast<GLintptr>(buffer_pos), | ||
| 180 | static_cast<GLsizeiptr>(mapped_size)); | ||
| 181 | buffer_pos += mapped_size; | ||
| 182 | } | 99 | } |
diff --git a/src/video_core/renderer_opengl/gl_stream_buffer.h b/src/video_core/renderer_opengl/gl_stream_buffer.h index e78dc5784..45592daaf 100644 --- a/src/video_core/renderer_opengl/gl_stream_buffer.h +++ b/src/video_core/renderer_opengl/gl_stream_buffer.h | |||
| @@ -2,35 +2,41 @@ | |||
| 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 | #pragma once | 5 | #include <tuple> |
| 6 | |||
| 7 | #include <memory> | ||
| 8 | #include <glad/glad.h> | 6 | #include <glad/glad.h> |
| 9 | #include "common/common_types.h" | 7 | #include "common/common_types.h" |
| 10 | #include "video_core/renderer_opengl/gl_resource_manager.h" | 8 | #include "video_core/renderer_opengl/gl_resource_manager.h" |
| 11 | 9 | ||
| 12 | class OGLStreamBuffer : private NonCopyable { | 10 | class OGLStreamBuffer : private NonCopyable { |
| 13 | public: | 11 | public: |
| 14 | explicit OGLStreamBuffer(GLenum target); | 12 | explicit OGLStreamBuffer(GLenum target, GLsizeiptr size, bool prefer_coherent = false); |
| 15 | virtual ~OGLStreamBuffer() = default; | 13 | ~OGLStreamBuffer(); |
| 16 | |||
| 17 | public: | ||
| 18 | static std::unique_ptr<OGLStreamBuffer> MakeBuffer(bool storage_buffer, GLenum target); | ||
| 19 | |||
| 20 | virtual void Create(size_t size, size_t sync_subdivide) = 0; | ||
| 21 | virtual void Release() {} | ||
| 22 | 14 | ||
| 23 | GLuint GetHandle() const; | 15 | GLuint GetHandle() const; |
| 16 | GLsizeiptr GetSize() const; | ||
| 17 | |||
| 18 | /* | ||
| 19 | * Allocates a linear chunk of memory in the GPU buffer with at least "size" bytes | ||
| 20 | * and the optional alignment requirement. | ||
| 21 | * If the buffer is full, the whole buffer is reallocated which invalidates old chunks. | ||
| 22 | * The return values are the pointer to the new chunk, the offset within the buffer, | ||
| 23 | * and the invalidation flag for previous chunks. | ||
| 24 | * The actual used size must be specified on unmapping the chunk. | ||
| 25 | */ | ||
| 26 | std::tuple<u8*, GLintptr, bool> Map(GLsizeiptr size, GLintptr alignment = 0); | ||
| 24 | 27 | ||
| 25 | virtual std::pair<u8*, GLintptr> Map(size_t size, size_t alignment) = 0; | 28 | void Unmap(GLsizeiptr size); |
| 26 | virtual void Unmap() = 0; | ||
| 27 | 29 | ||
| 28 | protected: | 30 | private: |
| 29 | OGLBuffer gl_buffer; | 31 | OGLBuffer gl_buffer; |
| 30 | GLenum gl_target; | 32 | GLenum gl_target; |
| 31 | 33 | ||
| 32 | size_t buffer_pos = 0; | 34 | bool coherent = false; |
| 33 | size_t buffer_size = 0; | 35 | bool persistent = false; |
| 34 | size_t buffer_sync_subdivide = 0; | 36 | |
| 35 | size_t mapped_size = 0; | 37 | GLintptr buffer_pos = 0; |
| 38 | GLsizeiptr buffer_size = 0; | ||
| 39 | GLintptr mapped_offset = 0; | ||
| 40 | GLsizeiptr mapped_size = 0; | ||
| 41 | u8* mapped_ptr = nullptr; | ||
| 36 | }; | 42 | }; |