mirror of
				https://github.com/PabloMK7/citra.git
				synced 2025-11-03 23:28:48 +00:00 
			
		
		
		
	HLE/GSP: Make RegisterInterruptRelayQueue work in a per-session basis.
The registered interrupt event is unique to each session that calls RegisterInterruptRelayQueue, and only that event should be reset when UnregisterInterruptRelayQueue is called.
This commit is contained in:
		
							parent
							
								
									ae42267cc7
								
							
						
					
					
						commit
						aabb07cca4
					
				
					 2 changed files with 55 additions and 25 deletions
				
			
		| 
						 | 
				
			
			@ -9,7 +9,6 @@
 | 
			
		|||
#include "core/core.h"
 | 
			
		||||
#include "core/hle/ipc.h"
 | 
			
		||||
#include "core/hle/ipc_helpers.h"
 | 
			
		||||
#include "core/hle/kernel/event.h"
 | 
			
		||||
#include "core/hle/kernel/handle_table.h"
 | 
			
		||||
#include "core/hle/kernel/shared_memory.h"
 | 
			
		||||
#include "core/hle/result.h"
 | 
			
		||||
| 
						 | 
				
			
			@ -319,12 +318,19 @@ void GSP_GPU::RegisterInterruptRelayQueue(Kernel::HLERequestContext& ctx) {
 | 
			
		|||
    IPC::RequestParser rp(ctx, 0x13, 1, 2);
 | 
			
		||||
    u32 flags = rp.Pop<u32>();
 | 
			
		||||
 | 
			
		||||
    interrupt_event = rp.PopObject<Kernel::Event>();
 | 
			
		||||
    auto interrupt_event = rp.PopObject<Kernel::Event>();
 | 
			
		||||
    // TODO(mailwl): return right error code instead assert
 | 
			
		||||
    ASSERT_MSG((interrupt_event != nullptr), "handle is not valid!");
 | 
			
		||||
 | 
			
		||||
    interrupt_event->name = "GSP_GSP_GPU::interrupt_event";
 | 
			
		||||
 | 
			
		||||
    u32 thread_id = next_thread_id++;
 | 
			
		||||
 | 
			
		||||
    SessionData* session_data = GetSessionData(ctx.Session());
 | 
			
		||||
    session_data->thread_id = thread_id;
 | 
			
		||||
    session_data->interrupt_event = std::move(interrupt_event);
 | 
			
		||||
    session_data->registered = true;
 | 
			
		||||
 | 
			
		||||
    IPC::RequestBuilder rb = rp.MakeBuilder(2, 2);
 | 
			
		||||
 | 
			
		||||
    if (first_initialization) {
 | 
			
		||||
| 
						 | 
				
			
			@ -338,22 +344,23 @@ void GSP_GPU::RegisterInterruptRelayQueue(Kernel::HLERequestContext& ctx) {
 | 
			
		|||
    rb.Push(thread_id);
 | 
			
		||||
    rb.PushCopyObjects(shared_memory);
 | 
			
		||||
 | 
			
		||||
    thread_id++;
 | 
			
		||||
    interrupt_event->Signal(); // TODO(bunnei): Is this correct?
 | 
			
		||||
 | 
			
		||||
    LOG_WARNING(Service_GSP, "called, flags=0x%08X", flags);
 | 
			
		||||
    LOG_DEBUG(Service_GSP, "called, flags=0x%08X", flags);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void GSP_GPU::UnregisterInterruptRelayQueue(Kernel::HLERequestContext& ctx) {
 | 
			
		||||
    IPC::RequestParser rp(ctx, 0x14, 0, 0);
 | 
			
		||||
 | 
			
		||||
    thread_id = 0;
 | 
			
		||||
    interrupt_event = nullptr;
 | 
			
		||||
    SessionData* session_data = GetSessionData(ctx.Session());
 | 
			
		||||
    session_data->thread_id = 0;
 | 
			
		||||
    session_data->interrupt_event = nullptr;
 | 
			
		||||
    session_data->registered = false;
 | 
			
		||||
 | 
			
		||||
    // TODO(Subv): Reset next_thread_id so that it doesn't go past the maximum of 4.
 | 
			
		||||
 | 
			
		||||
    IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
 | 
			
		||||
    rb.Push(RESULT_SUCCESS);
 | 
			
		||||
 | 
			
		||||
    LOG_WARNING(Service_GSP, "(STUBBED) called");
 | 
			
		||||
    LOG_DEBUG(Service_GSP, "called");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
| 
						 | 
				
			
			@ -366,15 +373,20 @@ void GSP_GPU::SignalInterrupt(InterruptId interrupt_id) {
 | 
			
		|||
    if (!gpu_right_acquired) {
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
    if (nullptr == interrupt_event) {
 | 
			
		||||
        LOG_WARNING(Service_GSP, "cannot synchronize until GSP event has been created!");
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
    if (nullptr == shared_memory) {
 | 
			
		||||
        LOG_WARNING(Service_GSP, "cannot synchronize until GSP shared memory has been created!");
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
    for (int thread_id = 0; thread_id < 0x4; ++thread_id) {
 | 
			
		||||
        SessionData* session_data = FindRegisteredThreadData(thread_id);
 | 
			
		||||
        if (session_data == nullptr)
 | 
			
		||||
            continue;
 | 
			
		||||
 | 
			
		||||
        auto interrupt_event = session_data->interrupt_event;
 | 
			
		||||
        if (interrupt_event == nullptr) {
 | 
			
		||||
            LOG_WARNING(Service_GSP, "cannot synchronize until GSP event has been created!");
 | 
			
		||||
            continue;
 | 
			
		||||
        }
 | 
			
		||||
        InterruptRelayQueue* interrupt_relay_queue =
 | 
			
		||||
            GetInterruptRelayQueue(shared_memory, thread_id);
 | 
			
		||||
        u8 next = interrupt_relay_queue->index;
 | 
			
		||||
| 
						 | 
				
			
			@ -398,8 +410,8 @@ void GSP_GPU::SignalInterrupt(InterruptId interrupt_id) {
 | 
			
		|||
                info->is_dirty.Assign(false);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        interrupt_event->Signal();
 | 
			
		||||
    }
 | 
			
		||||
    interrupt_event->Signal();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
MICROPROFILE_DEFINE(GPU_GSP_DMA, "GPU", "GSP DMA", MP_RGB(100, 0, 255));
 | 
			
		||||
| 
						 | 
				
			
			@ -655,6 +667,17 @@ void GSP_GPU::StoreDataCache(Kernel::HLERequestContext& ctx) {
 | 
			
		|||
              size, process->process_id);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
SessionData* GSP_GPU::FindRegisteredThreadData(u32 thread_id) {
 | 
			
		||||
    for (auto& session_info : connected_sessions) {
 | 
			
		||||
        SessionData* data = static_cast<SessionData*>(session_info.data.get())
 | 
			
		||||
        if (!data->registered)
 | 
			
		||||
            continue;
 | 
			
		||||
        if (data->thread_id == thread_id)
 | 
			
		||||
            return data;
 | 
			
		||||
    }
 | 
			
		||||
    return nullptr;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
GSP_GPU::GSP_GPU() : ServiceFramework("gsp::Gpu", 2) {
 | 
			
		||||
    static const FunctionInfo functions[] = {
 | 
			
		||||
        {0x00010082, &GSP_GPU::WriteHWRegs, "WriteHWRegs"},
 | 
			
		||||
| 
						 | 
				
			
			@ -691,17 +714,13 @@ GSP_GPU::GSP_GPU() : ServiceFramework("gsp::Gpu", 2) {
 | 
			
		|||
    };
 | 
			
		||||
    RegisterHandlers(functions);
 | 
			
		||||
 | 
			
		||||
    interrupt_event = nullptr;
 | 
			
		||||
 | 
			
		||||
    using Kernel::MemoryPermission;
 | 
			
		||||
    shared_memory = Kernel::SharedMemory::Create(nullptr, 0x1000, MemoryPermission::ReadWrite,
 | 
			
		||||
                                                 MemoryPermission::ReadWrite, 0,
 | 
			
		||||
                                                 Kernel::MemoryRegion::BASE, "GSP:SharedMemory");
 | 
			
		||||
 | 
			
		||||
    thread_id = 0;
 | 
			
		||||
    gpu_right_acquired = false;
 | 
			
		||||
    first_initialization = true;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // namespace GSP
 | 
			
		||||
} // namespace Service
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -8,12 +8,12 @@
 | 
			
		|||
#include <string>
 | 
			
		||||
#include "common/bit_field.h"
 | 
			
		||||
#include "common/common_types.h"
 | 
			
		||||
#include "core/hle/kernel/event.h"
 | 
			
		||||
#include "core/hle/kernel/hle_ipc.h"
 | 
			
		||||
#include "core/hle/result.h"
 | 
			
		||||
#include "core/hle/service/service.h"
 | 
			
		||||
 | 
			
		||||
namespace Kernel {
 | 
			
		||||
class Event;
 | 
			
		||||
class SharedMemory;
 | 
			
		||||
} // namespace Kernel
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -179,7 +179,16 @@ struct CommandBuffer {
 | 
			
		|||
};
 | 
			
		||||
static_assert(sizeof(CommandBuffer) == 0x200, "CommandBuffer struct has incorrect size");
 | 
			
		||||
 | 
			
		||||
class GSP_GPU final : public ServiceFramework<GSP_GPU> {
 | 
			
		||||
struct SessionData : public Kernel::SessionRequestHandler::SessionDataBase {
 | 
			
		||||
    /// Event triggered when GSP interrupt has been signalled
 | 
			
		||||
    Kernel::SharedPtr<Kernel::Event> interrupt_event;
 | 
			
		||||
    /// Thread index into interrupt relay queue
 | 
			
		||||
    u32 thread_id = 0;
 | 
			
		||||
    /// Whether RegisterInterruptRelayQueue was called for this session
 | 
			
		||||
    bool registered = false;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class GSP_GPU final : public ServiceFramework<GSP_GPU, SessionData> {
 | 
			
		||||
public:
 | 
			
		||||
    GSP_GPU();
 | 
			
		||||
    ~GSP_GPU() = default;
 | 
			
		||||
| 
						 | 
				
			
			@ -351,12 +360,14 @@ private:
 | 
			
		|||
     */
 | 
			
		||||
    void StoreDataCache(Kernel::HLERequestContext& ctx);
 | 
			
		||||
 | 
			
		||||
    /// Event triggered when GSP interrupt has been signalled
 | 
			
		||||
    Kernel::SharedPtr<Kernel::Event> interrupt_event;
 | 
			
		||||
    /// GSP shared memoryings
 | 
			
		||||
    /// Returns the session data for the specified registered thread id, or nullptr if not found.
 | 
			
		||||
    SessionData* FindRegisteredThreadData(u32 thread_id);
 | 
			
		||||
 | 
			
		||||
    /// Next threadid value to use when RegisterInterruptRelayQueue is called.
 | 
			
		||||
    u32 next_thread_id = 0;
 | 
			
		||||
 | 
			
		||||
    /// GSP shared memory
 | 
			
		||||
    Kernel::SharedPtr<Kernel::SharedMemory> shared_memory;
 | 
			
		||||
    /// Thread index into interrupt relay queue
 | 
			
		||||
    u32 thread_id = 0;
 | 
			
		||||
 | 
			
		||||
    bool gpu_right_acquired = false;
 | 
			
		||||
    bool first_initialization = true;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue