GL4 command processor.
This commit is contained in:
@@ -9,26 +9,148 @@
|
||||
|
||||
#include <xenia/gpu/gl4/gl4_graphics_system.h>
|
||||
|
||||
#include <poly/threading.h>
|
||||
#include <xenia/cpu/processor.h>
|
||||
#include <xenia/gpu/gpu-private.h>
|
||||
|
||||
namespace xe {
|
||||
namespace gpu {
|
||||
namespace gl4 {
|
||||
|
||||
GL4GraphicsSystem::GL4GraphicsSystem(Emulator* emulator)
|
||||
: GraphicsSystem(emulator) {}
|
||||
: GraphicsSystem(emulator), timer_queue_(nullptr), vsync_timer_(nullptr) {}
|
||||
|
||||
GL4GraphicsSystem::~GL4GraphicsSystem() = default;
|
||||
|
||||
X_STATUS GL4GraphicsSystem::Setup() {
|
||||
auto result = GraphicsSystem::Setup();
|
||||
if (result) {
|
||||
return result;
|
||||
}
|
||||
|
||||
// Create rendering control.
|
||||
// This must happen on the UI thread.
|
||||
poly::threading::Fence control_ready_fence;
|
||||
auto loop = emulator_->main_window()->loop();
|
||||
loop->Post([this]() {
|
||||
control_ = std::make_unique<WGLControl>();
|
||||
loop->Post([&]() {
|
||||
control_ = std::make_unique<WGLControl>(loop);
|
||||
emulator_->main_window()->AddChild(control_.get());
|
||||
control_ready_fence.Signal();
|
||||
});
|
||||
control_ready_fence.Wait();
|
||||
|
||||
// Create command processor. This will spin up a thread to process all
|
||||
// incoming ringbuffer packets.
|
||||
command_processor_ = std::make_unique<CommandProcessor>(this);
|
||||
command_processor_->set_swap_handler(
|
||||
std::bind(&GL4GraphicsSystem::SwapHandler, this));
|
||||
|
||||
// Let the processor know we want register access callbacks.
|
||||
emulator_->memory()->AddMappedRange(
|
||||
0x7FC80000, 0xFFFF0000, 0x0000FFFF, this,
|
||||
reinterpret_cast<cpu::MMIOReadCallback>(MMIOReadRegisterThunk),
|
||||
reinterpret_cast<cpu::MMIOWriteCallback>(MMIOWriteRegisterThunk));
|
||||
|
||||
// 60hz vsync timer.
|
||||
timer_queue_ = CreateTimerQueue();
|
||||
CreateTimerQueueTimer(&vsync_timer_, timer_queue_,
|
||||
(WAITORTIMERCALLBACK)VsyncCallbackThunk, this, 16, 16,
|
||||
WT_EXECUTEINTIMERTHREAD);
|
||||
|
||||
return X_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
void GL4GraphicsSystem::Shutdown() {
|
||||
DeleteTimerQueueTimer(timer_queue_, vsync_timer_, nullptr);
|
||||
DeleteTimerQueue(timer_queue_);
|
||||
|
||||
command_processor_->Shutdown();
|
||||
|
||||
// TODO(benvanik): remove mapped range.
|
||||
|
||||
command_processor_.reset();
|
||||
control_.reset();
|
||||
|
||||
GraphicsSystem::Shutdown();
|
||||
}
|
||||
|
||||
void GL4GraphicsSystem::InitializeRingBuffer(uint32_t ptr,
|
||||
uint32_t page_count) {
|
||||
command_processor_->Initialize(ptr, page_count);
|
||||
}
|
||||
|
||||
void GL4GraphicsSystem::EnableReadPointerWriteBack(uint32_t ptr,
|
||||
uint32_t block_size) {
|
||||
command_processor_->EnableReadPointerWriteBack(ptr, block_size);
|
||||
}
|
||||
|
||||
void GL4GraphicsSystem::MarkVblank() {
|
||||
static bool thread_name_set = false;
|
||||
if (!thread_name_set) {
|
||||
thread_name_set = true;
|
||||
Profiler::ThreadEnter("GL4 Vsync Timer");
|
||||
}
|
||||
SCOPE_profile_cpu_f("gpu");
|
||||
|
||||
// Increment vblank counter (so the game sees us making progress).
|
||||
command_processor_->increment_counter();
|
||||
|
||||
// TODO(benvanik): we shouldn't need to do the dispatch here, but there's
|
||||
// something wrong and the CP will block waiting for code that
|
||||
// needs to be run in the interrupt.
|
||||
DispatchInterruptCallback(0, 2);
|
||||
}
|
||||
|
||||
void GL4GraphicsSystem::SwapHandler() {
|
||||
SCOPE_profile_cpu_f("gpu");
|
||||
|
||||
// Swap requested. Synchronously post a request to the loop so that
|
||||
// we do the swap in the right thread.
|
||||
control_->SynchronousRepaint();
|
||||
|
||||
// Roll over vblank.
|
||||
MarkVblank();
|
||||
}
|
||||
|
||||
uint64_t GL4GraphicsSystem::ReadRegister(uint64_t addr) {
|
||||
uint32_t r = addr & 0xFFFF;
|
||||
if (FLAGS_trace_ring_buffer) {
|
||||
XELOGGPU("ReadRegister(%.4X)", r);
|
||||
}
|
||||
|
||||
switch (r) {
|
||||
case 0x6530: // ????
|
||||
return 1;
|
||||
case 0x6544: // ? vblank pending?
|
||||
return 1;
|
||||
case 0x6584: // ????
|
||||
return 1;
|
||||
}
|
||||
|
||||
assert_true(r >= 0 && r < RegisterFile::kRegisterCount);
|
||||
return register_file_.values[r].u32;
|
||||
}
|
||||
|
||||
void GL4GraphicsSystem::WriteRegister(uint64_t addr, uint64_t value) {
|
||||
uint32_t r = addr & 0xFFFF;
|
||||
if (FLAGS_trace_ring_buffer) {
|
||||
XELOGGPU("WriteRegister(%.4X, %.8X)", r, value);
|
||||
}
|
||||
|
||||
switch (r) {
|
||||
case 0x0714: // CP_RB_WPTR
|
||||
command_processor_->UpdateWritePointer(static_cast<uint32_t>(value));
|
||||
break;
|
||||
case 0x6110: // ? swap related?
|
||||
XELOGW("Unimplemented GPU register %.4X write: %.8X", r, value);
|
||||
return;
|
||||
default:
|
||||
XELOGW("Unknown GPU register %.4X write: %.8X", r, value);
|
||||
break;
|
||||
}
|
||||
|
||||
assert_true(r >= 0 && r < RegisterFile::kRegisterCount);
|
||||
register_file_.values[r].u32 = static_cast<uint32_t>(value);
|
||||
}
|
||||
|
||||
} // namespace gl4
|
||||
|
||||
Reference in New Issue
Block a user