early-access version 1258
This commit is contained in:
		| @@ -1,7 +1,7 @@ | ||||
| yuzu emulator early access | ||||
| ============= | ||||
|  | ||||
| This is the source code for early-access 1255. | ||||
| This is the source code for early-access 1258. | ||||
|  | ||||
| ## Legal Notice | ||||
|  | ||||
|   | ||||
| @@ -11,7 +11,6 @@ | ||||
| #include "audio_core/info_updater.h" | ||||
| #include "audio_core/voice_context.h" | ||||
| #include "common/logging/log.h" | ||||
| #include "core/hle/kernel/writable_event.h" | ||||
| #include "core/memory.h" | ||||
| #include "core/settings.h" | ||||
|  | ||||
| @@ -71,10 +70,9 @@ namespace { | ||||
| namespace AudioCore { | ||||
| AudioRenderer::AudioRenderer(Core::Timing::CoreTiming& core_timing, Core::Memory::Memory& memory_, | ||||
|                              AudioCommon::AudioRendererParameter params, | ||||
|                              std::shared_ptr<Kernel::WritableEvent> buffer_event_, | ||||
|                              Stream::ReleaseCallback&& release_callback, | ||||
|                              std::size_t instance_number) | ||||
|     : worker_params{params}, buffer_event{buffer_event_}, | ||||
|       memory_pool_info(params.effect_count + params.voice_count * 4), | ||||
|     : worker_params{params}, memory_pool_info(params.effect_count + params.voice_count * 4), | ||||
|       voice_context(params.voice_count), effect_context(params.effect_count), mix_context(), | ||||
|       sink_context(params.sink_count), splitter_context(), | ||||
|       voices(params.voice_count), memory{memory_}, | ||||
| @@ -85,10 +83,9 @@ AudioRenderer::AudioRenderer(Core::Timing::CoreTiming& core_timing, Core::Memory | ||||
|                                 params.num_splitter_send_channels); | ||||
|     mix_context.Initialize(behavior_info, params.submix_count + 1, params.effect_count); | ||||
|     audio_out = std::make_unique<AudioCore::AudioOut>(); | ||||
|     stream = | ||||
|         audio_out->OpenStream(core_timing, params.sample_rate, AudioCommon::STREAM_NUM_CHANNELS, | ||||
|                               fmt::format("AudioRenderer-Instance{}", instance_number), | ||||
|                               [=]() { buffer_event_->Signal(); }); | ||||
|     stream = audio_out->OpenStream( | ||||
|         core_timing, params.sample_rate, AudioCommon::STREAM_NUM_CHANNELS, | ||||
|         fmt::format("AudioRenderer-Instance{}", instance_number), std::move(release_callback)); | ||||
|     audio_out->StartStream(stream); | ||||
|  | ||||
|     QueueMixedBuffer(0); | ||||
|   | ||||
| @@ -27,10 +27,6 @@ namespace Core::Timing { | ||||
| class CoreTiming; | ||||
| } | ||||
|  | ||||
| namespace Kernel { | ||||
| class WritableEvent; | ||||
| } | ||||
|  | ||||
| namespace Core::Memory { | ||||
| class Memory; | ||||
| } | ||||
| @@ -44,8 +40,7 @@ class AudioRenderer { | ||||
| public: | ||||
|     AudioRenderer(Core::Timing::CoreTiming& core_timing, Core::Memory::Memory& memory_, | ||||
|                   AudioCommon::AudioRendererParameter params, | ||||
|                   std::shared_ptr<Kernel::WritableEvent> buffer_event_, | ||||
|                   std::size_t instance_number); | ||||
|                   Stream::ReleaseCallback&& release_callback, std::size_t instance_number); | ||||
|     ~AudioRenderer(); | ||||
|  | ||||
|     [[nodiscard]] ResultCode UpdateAudioRenderer(const std::vector<u8>& input_params, | ||||
| @@ -61,7 +56,6 @@ private: | ||||
|     BehaviorInfo behavior_info{}; | ||||
|  | ||||
|     AudioCommon::AudioRendererParameter worker_params; | ||||
|     std::shared_ptr<Kernel::WritableEvent> buffer_event; | ||||
|     std::vector<ServerMemoryPoolInfo> memory_pool_info; | ||||
|     VoiceContext voice_context; | ||||
|     EffectContext effect_context; | ||||
|   | ||||
| @@ -132,6 +132,8 @@ std::vector<Buffer::Tag> Stream::GetTagsAndReleaseBuffers(std::size_t max_count) | ||||
|     for (std::size_t count = 0; count < max_count && !released_buffers.empty(); ++count) { | ||||
|         if (released_buffers.front()) { | ||||
|             tags.push_back(released_buffers.front()->GetTag()); | ||||
|         } else { | ||||
|             ASSERT_MSG(false, "Invalid tag in released_buffers!"); | ||||
|         } | ||||
|         released_buffers.pop(); | ||||
|     } | ||||
| @@ -144,6 +146,8 @@ std::vector<Buffer::Tag> Stream::GetTagsAndReleaseBuffers() { | ||||
|     while (!released_buffers.empty()) { | ||||
|         if (released_buffers.front()) { | ||||
|             tags.push_back(released_buffers.front()->GetTag()); | ||||
|         } else { | ||||
|             ASSERT_MSG(false, "Invalid tag in released_buffers!"); | ||||
|         } | ||||
|         released_buffers.pop(); | ||||
|     } | ||||
|   | ||||
| @@ -8,7 +8,7 @@ | ||||
| #include <functional> | ||||
| #include <memory> | ||||
| #include <thread> | ||||
| #include <unordered_set> | ||||
| #include <unordered_map> | ||||
| #include <utility> | ||||
|  | ||||
| #include "common/assert.h" | ||||
| @@ -35,7 +35,6 @@ | ||||
| #include "core/hle/kernel/physical_core.h" | ||||
| #include "core/hle/kernel/process.h" | ||||
| #include "core/hle/kernel/resource_limit.h" | ||||
| #include "core/hle/kernel/service_thread.h" | ||||
| #include "core/hle/kernel/shared_memory.h" | ||||
| #include "core/hle/kernel/synchronization.h" | ||||
| #include "core/hle/kernel/thread.h" | ||||
| @@ -108,9 +107,6 @@ struct KernelCore::Impl { | ||||
|         std::fill(register_host_thread_keys.begin(), register_host_thread_keys.end(), | ||||
|                   std::thread::id{}); | ||||
|         std::fill(register_host_thread_values.begin(), register_host_thread_values.end(), 0); | ||||
|  | ||||
|         // Ensures all service threads gracefully shutdown | ||||
|         service_threads.clear(); | ||||
|     } | ||||
|  | ||||
|     void InitializePhysicalCores() { | ||||
| @@ -349,9 +345,6 @@ struct KernelCore::Impl { | ||||
|     std::shared_ptr<Kernel::SharedMemory> irs_shared_mem; | ||||
|     std::shared_ptr<Kernel::SharedMemory> time_shared_mem; | ||||
|  | ||||
|     // Threads used for services | ||||
|     std::unordered_set<std::shared_ptr<Kernel::ServiceThread>> service_threads; | ||||
|  | ||||
|     std::array<std::shared_ptr<Thread>, Core::Hardware::NUM_CPU_CORES> suspend_threads{}; | ||||
|     std::array<Core::CPUInterruptHandler, Core::Hardware::NUM_CPU_CORES> interrupts{}; | ||||
|     std::array<std::unique_ptr<Kernel::KScheduler>, Core::Hardware::NUM_CPU_CORES> schedulers{}; | ||||
| @@ -646,16 +639,4 @@ void KernelCore::ExitSVCProfile() { | ||||
|     MicroProfileLeave(MICROPROFILE_TOKEN(Kernel_SVC), impl->svc_ticks[core]); | ||||
| } | ||||
|  | ||||
| std::weak_ptr<Kernel::ServiceThread> KernelCore::CreateServiceThread(const std::string& name) { | ||||
|     auto service_thread = std::make_shared<Kernel::ServiceThread>(*this, 1, name); | ||||
|     impl->service_threads.emplace(service_thread); | ||||
|     return service_thread; | ||||
| } | ||||
|  | ||||
| void KernelCore::ReleaseServiceThread(std::weak_ptr<Kernel::ServiceThread> service_thread) { | ||||
|     if (auto strong_ptr = service_thread.lock()) { | ||||
|         impl->service_threads.erase(strong_ptr); | ||||
|     } | ||||
| } | ||||
|  | ||||
| } // namespace Kernel | ||||
|   | ||||
| @@ -42,7 +42,6 @@ class Process; | ||||
| class ResourceLimit; | ||||
| class KScheduler; | ||||
| class SharedMemory; | ||||
| class ServiceThread; | ||||
| class Synchronization; | ||||
| class Thread; | ||||
| class TimeManager; | ||||
| @@ -228,22 +227,6 @@ public: | ||||
|  | ||||
|     void ExitSVCProfile(); | ||||
|  | ||||
|     /** | ||||
|      * Creates an HLE service thread, which are used to execute service routines asynchronously. | ||||
|      * While these are allocated per ServerSession, these need to be owned and managed outside of | ||||
|      * ServerSession to avoid a circular dependency. | ||||
|      * @param name String name for the ServerSession creating this thread, used for debug purposes. | ||||
|      * @returns The a weak pointer newly created service thread. | ||||
|      */ | ||||
|     std::weak_ptr<Kernel::ServiceThread> CreateServiceThread(const std::string& name); | ||||
|  | ||||
|     /** | ||||
|      * Releases a HLE service thread, instructing KernelCore to free it. This should be called when | ||||
|      * the ServerSession associated with the thread is destroyed. | ||||
|      * @param service_thread Service thread to release. | ||||
|      */ | ||||
|     void ReleaseServiceThread(std::weak_ptr<Kernel::ServiceThread> service_thread); | ||||
|  | ||||
| private: | ||||
|     friend class Object; | ||||
|     friend class Process; | ||||
|   | ||||
| @@ -25,10 +25,7 @@ | ||||
| namespace Kernel { | ||||
|  | ||||
| ServerSession::ServerSession(KernelCore& kernel) : SynchronizationObject{kernel} {} | ||||
|  | ||||
| ServerSession::~ServerSession() { | ||||
|     kernel.ReleaseServiceThread(service_thread); | ||||
| } | ||||
| ServerSession::~ServerSession() = default; | ||||
|  | ||||
| ResultVal<std::shared_ptr<ServerSession>> ServerSession::Create(KernelCore& kernel, | ||||
|                                                                 std::shared_ptr<Session> parent, | ||||
| @@ -37,7 +34,7 @@ ResultVal<std::shared_ptr<ServerSession>> ServerSession::Create(KernelCore& kern | ||||
|  | ||||
|     session->name = std::move(name); | ||||
|     session->parent = std::move(parent); | ||||
|     session->service_thread = kernel.CreateServiceThread(session->name); | ||||
|     session->service_thread = std::make_unique<ServiceThread>(kernel, 1); | ||||
|  | ||||
|     return MakeResult(std::move(session)); | ||||
| } | ||||
| @@ -142,11 +139,7 @@ ResultCode ServerSession::QueueSyncRequest(std::shared_ptr<Thread> thread, | ||||
|         std::make_shared<HLERequestContext>(kernel, memory, SharedFrom(this), std::move(thread)); | ||||
|  | ||||
|     context->PopulateFromIncomingCommandBuffer(kernel.CurrentProcess()->GetHandleTable(), cmd_buf); | ||||
|  | ||||
|     if (auto strong_ptr = service_thread.lock()) { | ||||
|         strong_ptr->QueueSyncRequest(*this, std::move(context)); | ||||
|         return RESULT_SUCCESS; | ||||
|     } | ||||
|     service_thread->QueueSyncRequest(*this, std::move(context)); | ||||
|  | ||||
|     return RESULT_SUCCESS; | ||||
| } | ||||
|   | ||||
| @@ -167,7 +167,7 @@ private: | ||||
|     std::string name; | ||||
|  | ||||
|     /// Thread to dispatch service requests | ||||
|     std::weak_ptr<ServiceThread> service_thread; | ||||
|     std::unique_ptr<ServiceThread> service_thread; | ||||
| }; | ||||
|  | ||||
| } // namespace Kernel | ||||
|   | ||||
| @@ -11,7 +11,6 @@ | ||||
|  | ||||
| #include "common/assert.h" | ||||
| #include "common/scope_exit.h" | ||||
| #include "common/thread.h" | ||||
| #include "core/core.h" | ||||
| #include "core/hle/kernel/kernel.h" | ||||
| #include "core/hle/kernel/server_session.h" | ||||
| @@ -23,7 +22,7 @@ namespace Kernel { | ||||
|  | ||||
| class ServiceThread::Impl final { | ||||
| public: | ||||
|     explicit Impl(KernelCore& kernel, std::size_t num_threads, const std::string& name); | ||||
|     explicit Impl(KernelCore& kernel, std::size_t num_threads); | ||||
|     ~Impl(); | ||||
|  | ||||
|     void QueueSyncRequest(ServerSession& session, std::shared_ptr<HLERequestContext>&& context); | ||||
| @@ -33,17 +32,12 @@ private: | ||||
|     std::queue<std::function<void()>> requests; | ||||
|     std::mutex queue_mutex; | ||||
|     std::condition_variable condition; | ||||
|     const std::string service_name; | ||||
|     bool stop{}; | ||||
| }; | ||||
|  | ||||
| ServiceThread::Impl::Impl(KernelCore& kernel, std::size_t num_threads, const std::string& name) | ||||
|     : service_name{name} { | ||||
|  | ||||
| ServiceThread::Impl::Impl(KernelCore& kernel, std::size_t num_threads) { | ||||
|     for (std::size_t i = 0; i < num_threads; ++i) | ||||
|         threads.emplace_back([this, &kernel] { | ||||
|             Common::SetCurrentThreadName(std::string{"Hle_" + service_name}.c_str()); | ||||
|  | ||||
|         threads.emplace_back([&] { | ||||
|             // Wait for first request before trying to acquire a render context | ||||
|             { | ||||
|                 std::unique_lock lock{queue_mutex}; | ||||
| @@ -58,7 +52,7 @@ ServiceThread::Impl::Impl(KernelCore& kernel, std::size_t num_threads, const std | ||||
|                 { | ||||
|                     std::unique_lock lock{queue_mutex}; | ||||
|                     condition.wait(lock, [this] { return stop || !requests.empty(); }); | ||||
|                     if (stop || requests.empty()) { | ||||
|                     if (stop && requests.empty()) { | ||||
|                         return; | ||||
|                     } | ||||
|                     task = std::move(requests.front()); | ||||
| @@ -93,8 +87,8 @@ ServiceThread::Impl::~Impl() { | ||||
|     } | ||||
| } | ||||
|  | ||||
| ServiceThread::ServiceThread(KernelCore& kernel, std::size_t num_thread, const std::string& name) | ||||
|     : impl{std::make_unique<Impl>(kernel, num_thread, name)} {} | ||||
| ServiceThread::ServiceThread(KernelCore& kernel, std::size_t num_threads) | ||||
|     : impl{std::make_unique<Impl>(kernel, num_threads)} {} | ||||
|  | ||||
| ServiceThread::~ServiceThread() = default; | ||||
|  | ||||
|   | ||||
| @@ -5,7 +5,6 @@ | ||||
| #pragma once | ||||
|  | ||||
| #include <memory> | ||||
| #include <string> | ||||
|  | ||||
| namespace Kernel { | ||||
|  | ||||
| @@ -15,7 +14,7 @@ class ServerSession; | ||||
|  | ||||
| class ServiceThread final { | ||||
| public: | ||||
|     explicit ServiceThread(KernelCore& kernel, std::size_t num_threads, const std::string& name); | ||||
|     explicit ServiceThread(KernelCore& kernel, std::size_t num_threads); | ||||
|     ~ServiceThread(); | ||||
|  | ||||
|     void QueueSyncRequest(ServerSession& session, std::shared_ptr<HLERequestContext>&& context); | ||||
|   | ||||
| @@ -70,8 +70,10 @@ public: | ||||
|             Kernel::WritableEvent::CreateEventPair(system.Kernel(), "IAudioOutBufferReleased"); | ||||
|  | ||||
|         stream = audio_core.OpenStream(system.CoreTiming(), audio_params.sample_rate, | ||||
|                                        audio_params.channel_count, std::move(unique_name), | ||||
|                                        [this] { buffer_event.writable->Signal(); }); | ||||
|                                        audio_params.channel_count, std::move(unique_name), [this] { | ||||
|                                            const auto guard = LockService(); | ||||
|                                            buffer_event.writable->Signal(); | ||||
|                                        }); | ||||
|     } | ||||
|  | ||||
| private: | ||||
|   | ||||
| @@ -49,16 +49,16 @@ public: | ||||
|  | ||||
|         system_event = | ||||
|             Kernel::WritableEvent::CreateEventPair(system.Kernel(), "IAudioRenderer:SystemEvent"); | ||||
|         renderer = std::make_unique<AudioCore::AudioRenderer>(system.CoreTiming(), system.Memory(), | ||||
|                                                               audren_params, system_event.writable, | ||||
|                                                               instance_number); | ||||
|         renderer = std::make_unique<AudioCore::AudioRenderer>( | ||||
|             system.CoreTiming(), system.Memory(), audren_params, | ||||
|             [this]() { | ||||
|                 const auto guard = LockService(); | ||||
|                 system_event.writable->Signal(); | ||||
|             }, | ||||
|             instance_number); | ||||
|     } | ||||
|  | ||||
| private: | ||||
|     void UpdateAudioCallback() { | ||||
|         system_event.writable->Signal(); | ||||
|     } | ||||
|  | ||||
|     void GetSampleRate(Kernel::HLERequestContext& ctx) { | ||||
|         LOG_DEBUG(Service_Audio, "called"); | ||||
|  | ||||
|   | ||||
| @@ -78,11 +78,13 @@ IAppletResource::IAppletResource(Core::System& system_) | ||||
|     pad_update_event = Core::Timing::CreateEvent( | ||||
|         "HID::UpdatePadCallback", | ||||
|         [this](std::uintptr_t user_data, std::chrono::nanoseconds ns_late) { | ||||
|             const auto guard = LockService(); | ||||
|             UpdateControllers(user_data, ns_late); | ||||
|         }); | ||||
|     motion_update_event = Core::Timing::CreateEvent( | ||||
|         "HID::MotionPadCallback", | ||||
|         [this](std::uintptr_t user_data, std::chrono::nanoseconds ns_late) { | ||||
|             const auto guard = LockService(); | ||||
|             UpdateMotion(user_data, ns_late); | ||||
|         }); | ||||
|  | ||||
|   | ||||
| @@ -95,9 +95,14 @@ ServiceFrameworkBase::ServiceFrameworkBase(Core::System& system_, const char* se | ||||
|     : system{system_}, service_name{service_name_}, max_sessions{max_sessions_}, | ||||
|       handler_invoker{handler_invoker_} {} | ||||
|  | ||||
| ServiceFrameworkBase::~ServiceFrameworkBase() = default; | ||||
| ServiceFrameworkBase::~ServiceFrameworkBase() { | ||||
|     // Wait for other threads to release access before destroying | ||||
|     const auto guard = LockService(); | ||||
| } | ||||
|  | ||||
| void ServiceFrameworkBase::InstallAsService(SM::ServiceManager& service_manager) { | ||||
|     const auto guard = LockService(); | ||||
|  | ||||
|     ASSERT(!port_installed); | ||||
|  | ||||
|     auto port = service_manager.RegisterService(service_name, max_sessions).Unwrap(); | ||||
| @@ -106,6 +111,8 @@ void ServiceFrameworkBase::InstallAsService(SM::ServiceManager& service_manager) | ||||
| } | ||||
|  | ||||
| void ServiceFrameworkBase::InstallAsNamedPort(Kernel::KernelCore& kernel) { | ||||
|     const auto guard = LockService(); | ||||
|  | ||||
|     ASSERT(!port_installed); | ||||
|  | ||||
|     auto [server_port, client_port] = | ||||
| @@ -115,17 +122,6 @@ void ServiceFrameworkBase::InstallAsNamedPort(Kernel::KernelCore& kernel) { | ||||
|     port_installed = true; | ||||
| } | ||||
|  | ||||
| std::shared_ptr<Kernel::ClientPort> ServiceFrameworkBase::CreatePort(Kernel::KernelCore& kernel) { | ||||
|     ASSERT(!port_installed); | ||||
|  | ||||
|     auto [server_port, client_port] = | ||||
|         Kernel::ServerPort::CreatePortPair(kernel, max_sessions, service_name); | ||||
|     auto port = MakeResult(std::move(server_port)).Unwrap(); | ||||
|     port->SetHleHandler(shared_from_this()); | ||||
|     port_installed = true; | ||||
|     return client_port; | ||||
| } | ||||
|  | ||||
| void ServiceFrameworkBase::RegisterHandlersBase(const FunctionInfoBase* functions, std::size_t n) { | ||||
|     handlers.reserve(handlers.size() + n); | ||||
|     for (std::size_t i = 0; i < n; ++i) { | ||||
| @@ -164,6 +160,8 @@ void ServiceFrameworkBase::InvokeRequest(Kernel::HLERequestContext& ctx) { | ||||
| } | ||||
|  | ||||
| ResultCode ServiceFrameworkBase::HandleSyncRequest(Kernel::HLERequestContext& context) { | ||||
|     const auto guard = LockService(); | ||||
|  | ||||
|     switch (context.GetCommandType()) { | ||||
|     case IPC::CommandType::Close: { | ||||
|         IPC::ResponseBuilder rb{context, 2}; | ||||
|   | ||||
| @@ -5,9 +5,11 @@ | ||||
| #pragma once | ||||
|  | ||||
| #include <cstddef> | ||||
| #include <mutex> | ||||
| #include <string> | ||||
| #include <boost/container/flat_map.hpp> | ||||
| #include "common/common_types.h" | ||||
| #include "common/spin_lock.h" | ||||
| #include "core/hle/kernel/hle_ipc.h" | ||||
| #include "core/hle/kernel/object.h" | ||||
|  | ||||
| @@ -68,11 +70,9 @@ public: | ||||
|     void InstallAsService(SM::ServiceManager& service_manager); | ||||
|     /// Creates a port pair and registers it on the kernel's global port registry. | ||||
|     void InstallAsNamedPort(Kernel::KernelCore& kernel); | ||||
|     /// Creates and returns an unregistered port for the service. | ||||
|     std::shared_ptr<Kernel::ClientPort> CreatePort(Kernel::KernelCore& kernel); | ||||
|  | ||||
|     /// Invokes a service request routine. | ||||
|     void InvokeRequest(Kernel::HLERequestContext& ctx); | ||||
|  | ||||
|     /// Handles a synchronization request for the service. | ||||
|     ResultCode HandleSyncRequest(Kernel::HLERequestContext& context) override; | ||||
|  | ||||
| protected: | ||||
| @@ -80,6 +80,11 @@ protected: | ||||
|     template <typename Self> | ||||
|     using HandlerFnP = void (Self::*)(Kernel::HLERequestContext&); | ||||
|  | ||||
|     /// Used to gain exclusive access to the service members, e.g. from CoreTiming thread. | ||||
|     [[nodiscard]] std::scoped_lock<Common::SpinLock> LockService() { | ||||
|         return std::scoped_lock{lock_service}; | ||||
|     } | ||||
|  | ||||
|     /// System context that the service operates under. | ||||
|     Core::System& system; | ||||
|  | ||||
| @@ -115,6 +120,9 @@ private: | ||||
|     /// Function used to safely up-cast pointers to the derived class before invoking a handler. | ||||
|     InvokerFn* handler_invoker; | ||||
|     boost::container::flat_map<u32, FunctionInfoBase> handlers; | ||||
|  | ||||
|     /// Used to gain exclusive access to the service members, e.g. from CoreTiming thread. | ||||
|     Common::SpinLock lock_service; | ||||
| }; | ||||
|  | ||||
| /** | ||||
|   | ||||
| @@ -186,18 +186,18 @@ void RendererOpenGL::LoadFBToScreenInfo(const Tegra::FramebufferConfig& framebuf | ||||
|     // Reset the screen info's display texture to its own permanent texture | ||||
|     screen_info.display_texture = screen_info.texture.resource.handle; | ||||
|  | ||||
|     // TODO(Rodrigo): Read this from HLE | ||||
|     constexpr u32 block_height_log2 = 4; | ||||
|     const auto pixel_format{ | ||||
|         VideoCore::Surface::PixelFormatFromGPUPixelFormat(framebuffer.pixel_format)}; | ||||
|     const u32 bytes_per_pixel{VideoCore::Surface::BytesPerBlock(pixel_format)}; | ||||
|     const u64 size_in_bytes{framebuffer.stride * framebuffer.height * bytes_per_pixel}; | ||||
|     u8* const host_ptr{cpu_memory.GetPointer(framebuffer_addr)}; | ||||
|     rasterizer->FlushRegion(ToCacheAddr(host_ptr), size_in_bytes); | ||||
|  | ||||
|     // TODO(Rodrigo): Read this from HLE | ||||
|     constexpr u32 block_height_log2 = 4; | ||||
|     Tegra::Texture::UnswizzleTexture(gl_framebuffer_data, std::span<u8>(host_ptr, size_in_bytes), | ||||
|                                      bytes_per_pixel, framebuffer.width, framebuffer.height, 1, | ||||
|                                      block_height_log2, 0); | ||||
|     const u64 size_in_bytes{Tegra::Texture::CalculateSize( | ||||
|         true, bytes_per_pixel, framebuffer.stride, framebuffer.height, 1, block_height_log2, 0)}; | ||||
|     const u8* const host_ptr{cpu_memory.GetPointer(framebuffer_addr)}; | ||||
|     const std::span<const u8> input_data(host_ptr, size_in_bytes); | ||||
|     Tegra::Texture::UnswizzleTexture(gl_framebuffer_data, input_data, bytes_per_pixel, | ||||
|                                      framebuffer.width, framebuffer.height, 1, block_height_log2, | ||||
|                                      0); | ||||
|  | ||||
|     glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); | ||||
|     glPixelStorei(GL_UNPACK_ROW_LENGTH, static_cast<GLint>(framebuffer.stride)); | ||||
|   | ||||
| @@ -116,19 +116,6 @@ constexpr std::array DYNAMIC_STATES{ | ||||
|     VK_DYNAMIC_STATE_VIEWPORT, | ||||
|     VK_DYNAMIC_STATE_SCISSOR, | ||||
| }; | ||||
| constexpr std::array EXTENDED_DYNAMIC_STATES{ | ||||
|     VK_DYNAMIC_STATE_VIEWPORT, | ||||
|     VK_DYNAMIC_STATE_SCISSOR, | ||||
|     VK_DYNAMIC_STATE_CULL_MODE_EXT, | ||||
|     VK_DYNAMIC_STATE_FRONT_FACE_EXT, | ||||
|     VK_DYNAMIC_STATE_VERTEX_INPUT_BINDING_STRIDE_EXT, | ||||
|     VK_DYNAMIC_STATE_DEPTH_TEST_ENABLE_EXT, | ||||
|     VK_DYNAMIC_STATE_DEPTH_WRITE_ENABLE_EXT, | ||||
|     VK_DYNAMIC_STATE_DEPTH_COMPARE_OP_EXT, | ||||
|     VK_DYNAMIC_STATE_DEPTH_BOUNDS_TEST_ENABLE_EXT, | ||||
|     VK_DYNAMIC_STATE_STENCIL_TEST_ENABLE_EXT, | ||||
|     VK_DYNAMIC_STATE_STENCIL_OP_EXT, | ||||
| }; | ||||
| constexpr VkPipelineDynamicStateCreateInfo PIPELINE_DYNAMIC_STATE_CREATE_INFO{ | ||||
|     .sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO, | ||||
|     .pNext = nullptr, | ||||
| @@ -136,13 +123,6 @@ constexpr VkPipelineDynamicStateCreateInfo PIPELINE_DYNAMIC_STATE_CREATE_INFO{ | ||||
|     .dynamicStateCount = static_cast<u32>(DYNAMIC_STATES.size()), | ||||
|     .pDynamicStates = DYNAMIC_STATES.data(), | ||||
| }; | ||||
| constexpr VkPipelineDynamicStateCreateInfo PIPELINE_EXTENDED_DYNAMIC_STATE_CREATE_INFO{ | ||||
|     .sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO, | ||||
|     .pNext = nullptr, | ||||
|     .flags = 0, | ||||
|     .dynamicStateCount = static_cast<u32>(EXTENDED_DYNAMIC_STATES.size()), | ||||
|     .pDynamicStates = EXTENDED_DYNAMIC_STATES.data(), | ||||
| }; | ||||
| constexpr VkPipelineColorBlendStateCreateInfo PIPELINE_COLOR_BLEND_STATE_EMPTY_CREATE_INFO{ | ||||
|     .sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, | ||||
|     .pNext = nullptr, | ||||
| @@ -309,7 +289,7 @@ void UpdateTwoTexturesDescriptorSet(const VKDevice& device, VkDescriptorSet desc | ||||
|     device.GetLogical().UpdateDescriptorSets(write_descriptor_sets, nullptr); | ||||
| } | ||||
|  | ||||
| void BindBlitState(const VKDevice& device, vk::CommandBuffer cmdbuf, VkPipelineLayout layout, | ||||
| void BindBlitState(vk::CommandBuffer cmdbuf, VkPipelineLayout layout, | ||||
|                    const std::array<Offset2D, 2>& dst_region, | ||||
|                    const std::array<Offset2D, 2>& src_region) { | ||||
|     const VkOffset2D offset{ | ||||
| @@ -341,22 +321,6 @@ void BindBlitState(const VKDevice& device, vk::CommandBuffer cmdbuf, VkPipelineL | ||||
|     }; | ||||
|     cmdbuf.SetViewport(0, viewport); | ||||
|     cmdbuf.SetScissor(0, scissor); | ||||
|     if (device.IsExtExtendedDynamicStateSupported()) { | ||||
|         // Workaround bug on Nvidia's drivers where the state is not properly handled when switching | ||||
|         // from one pipeline without dynamic state to one with. | ||||
|         // To workaround the bug, we manually set the pipeline state as dynamic state and keep the | ||||
|         // relevant bits enabled. | ||||
|         cmdbuf.SetCullModeEXT(PIPELINE_RASTERIZATION_STATE_CREATE_INFO.cullMode); | ||||
|         cmdbuf.SetFrontFaceEXT(PIPELINE_RASTERIZATION_STATE_CREATE_INFO.frontFace); | ||||
|         cmdbuf.SetDepthTestEnableEXT(PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO.depthTestEnable); | ||||
|         cmdbuf.SetDepthWriteEnableEXT(PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO.depthWriteEnable); | ||||
|         cmdbuf.SetDepthCompareOpEXT(PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO.depthCompareOp); | ||||
|         cmdbuf.SetDepthBoundsTestEnableEXT( | ||||
|             PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO.depthBoundsTestEnable); | ||||
|         cmdbuf.SetStencilTestEnableEXT(PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO.stencilTestEnable); | ||||
|         cmdbuf.SetStencilOpEXT(VK_STENCIL_FACE_FRONT_AND_BACK, VK_STENCIL_OP_KEEP, | ||||
|                                VK_STENCIL_OP_KEEP, VK_STENCIL_OP_KEEP, VK_COMPARE_OP_NEVER); | ||||
|     } | ||||
|     cmdbuf.PushConstants(layout, VK_SHADER_STAGE_VERTEX_BIT, push_constants); | ||||
| } | ||||
|  | ||||
| @@ -411,7 +375,7 @@ void BlitImageHelper::BlitColor(const Framebuffer* dst_framebuffer, const ImageV | ||||
|         cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline); | ||||
|         cmdbuf.BindDescriptorSets(VK_PIPELINE_BIND_POINT_GRAPHICS, layout, 0, descriptor_set, | ||||
|                                   nullptr); | ||||
|         BindBlitState(device, cmdbuf, layout, dst_region, src_region); | ||||
|         BindBlitState(cmdbuf, layout, dst_region, src_region); | ||||
|         cmdbuf.Draw(3, 1, 0, 0); | ||||
|     }); | ||||
|     scheduler.InvalidateState(); | ||||
| @@ -440,7 +404,7 @@ void BlitImageHelper::BlitDepthStencil(const Framebuffer* dst_framebuffer, | ||||
|         cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline); | ||||
|         cmdbuf.BindDescriptorSets(VK_PIPELINE_BIND_POINT_GRAPHICS, layout, 0, descriptor_set, | ||||
|                                   nullptr); | ||||
|         BindBlitState(device, cmdbuf, layout, dst_region, src_region); | ||||
|         BindBlitState(cmdbuf, layout, dst_region, src_region); | ||||
|         cmdbuf.Draw(3, 1, 0, 0); | ||||
|     }); | ||||
|     scheduler.InvalidateState(); | ||||
| @@ -562,9 +526,7 @@ VkPipeline BlitImageHelper::FindOrEmplacePipeline(const BlitImagePipelineKey& ke | ||||
|         .pMultisampleState = &PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, | ||||
|         .pDepthStencilState = nullptr, | ||||
|         .pColorBlendState = &color_blend_create_info, | ||||
|         .pDynamicState = device.IsExtExtendedDynamicStateSupported() | ||||
|                              ? &PIPELINE_EXTENDED_DYNAMIC_STATE_CREATE_INFO | ||||
|                              : &PIPELINE_DYNAMIC_STATE_CREATE_INFO, | ||||
|         .pDynamicState = &PIPELINE_DYNAMIC_STATE_CREATE_INFO, | ||||
|         .layout = *one_texture_pipeline_layout, | ||||
|         .renderPass = key.renderpass, | ||||
|         .subpass = 0, | ||||
| @@ -593,9 +555,7 @@ VkPipeline BlitImageHelper::BlitDepthStencilPipeline(VkRenderPass renderpass) { | ||||
|         .pMultisampleState = &PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, | ||||
|         .pDepthStencilState = &PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO, | ||||
|         .pColorBlendState = &PIPELINE_COLOR_BLEND_STATE_EMPTY_CREATE_INFO, | ||||
|         .pDynamicState = device.IsExtExtendedDynamicStateSupported() | ||||
|                              ? &PIPELINE_EXTENDED_DYNAMIC_STATE_CREATE_INFO | ||||
|                              : &PIPELINE_DYNAMIC_STATE_CREATE_INFO, | ||||
|         .pDynamicState = &PIPELINE_DYNAMIC_STATE_CREATE_INFO, | ||||
|         .layout = *two_textures_pipeline_layout, | ||||
|         .renderPass = renderpass, | ||||
|         .subpass = 0, | ||||
|   | ||||
| @@ -477,14 +477,13 @@ void RasterizerVulkan::Draw(bool is_indexed, bool is_instanced) { | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     UpdateDynamicStates(); | ||||
|  | ||||
|     buffer_bindings.Bind(device, scheduler); | ||||
|  | ||||
|     BeginTransformFeedback(); | ||||
|  | ||||
|     scheduler.RequestRenderpass(framebuffer); | ||||
|     scheduler.BindGraphicsPipeline(pipeline->GetHandle()); | ||||
|     UpdateDynamicStates(); | ||||
|  | ||||
|     const auto pipeline_layout = pipeline->GetLayout(); | ||||
|     const auto descriptor_set = pipeline->CommitDescriptorSet(); | ||||
|   | ||||
		Reference in New Issue
	
	Block a user