Simple UI for frame seeking.
This commit is contained in:
@@ -93,8 +93,6 @@ uint64_t CommandProcessor::QueryTime() {
|
||||
bool CommandProcessor::Initialize(std::unique_ptr<GLContext> context) {
|
||||
context_ = std::move(context);
|
||||
|
||||
pending_fn_event_ = CreateEvent(nullptr, TRUE, FALSE, nullptr);
|
||||
|
||||
worker_running_ = true;
|
||||
worker_thread_ = std::thread([this]() {
|
||||
poly::threading::set_name("GL4 Worker");
|
||||
@@ -118,8 +116,6 @@ void CommandProcessor::Shutdown() {
|
||||
shader_cache_.clear();
|
||||
|
||||
context_.reset();
|
||||
|
||||
CloseHandle(pending_fn_event_);
|
||||
}
|
||||
|
||||
void CommandProcessor::BeginTracing(const std::wstring& root_path) {
|
||||
@@ -130,10 +126,12 @@ void CommandProcessor::BeginTracing(const std::wstring& root_path) {
|
||||
void CommandProcessor::EndTracing() { trace_writer_.Close(); }
|
||||
|
||||
void CommandProcessor::CallInThread(std::function<void()> fn) {
|
||||
assert_null(pending_fn_);
|
||||
pending_fn_ = std::move(fn);
|
||||
WaitForSingleObject(pending_fn_event_, INFINITE);
|
||||
ResetEvent(pending_fn_event_);
|
||||
if (pending_fns_.empty() &&
|
||||
worker_thread_.get_id() == std::this_thread::get_id()) {
|
||||
fn();
|
||||
} else {
|
||||
pending_fns_.push(std::move(fn));
|
||||
}
|
||||
}
|
||||
|
||||
void CommandProcessor::WorkerMain() {
|
||||
@@ -144,11 +142,10 @@ void CommandProcessor::WorkerMain() {
|
||||
}
|
||||
|
||||
while (worker_running_) {
|
||||
if (pending_fn_) {
|
||||
auto fn = std::move(pending_fn_);
|
||||
pending_fn_ = nullptr;
|
||||
while (!pending_fns_.empty()) {
|
||||
auto fn = std::move(pending_fns_.front());
|
||||
pending_fns_.pop();
|
||||
fn();
|
||||
SetEvent(pending_fn_event_);
|
||||
}
|
||||
|
||||
uint32_t write_ptr_index = write_ptr_index_.load();
|
||||
@@ -166,10 +163,10 @@ void CommandProcessor::WorkerMain() {
|
||||
SwitchToThread();
|
||||
MemoryBarrier();
|
||||
write_ptr_index = write_ptr_index_.load();
|
||||
} while (!pending_fn_ && (write_ptr_index == 0xBAADF00D ||
|
||||
read_ptr_index_ == write_ptr_index));
|
||||
} while (pending_fns_.empty() && (write_ptr_index == 0xBAADF00D ||
|
||||
read_ptr_index_ == write_ptr_index));
|
||||
// ReturnFromWait();
|
||||
if (pending_fn_) {
|
||||
if (!pending_fns_.empty()) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#include <atomic>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <queue>
|
||||
#include <thread>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
@@ -212,8 +213,7 @@ class CommandProcessor {
|
||||
std::atomic<bool> worker_running_;
|
||||
std::unique_ptr<GLContext> context_;
|
||||
SwapHandler swap_handler_;
|
||||
std::function<void()> pending_fn_;
|
||||
HANDLE pending_fn_event_;
|
||||
std::queue<std::function<void()>> pending_fns_;
|
||||
|
||||
SwapMode swap_mode_;
|
||||
|
||||
|
||||
@@ -126,99 +126,102 @@ void GL4GraphicsSystem::RequestSwap() {
|
||||
command_processor_->CallInThread([&]() { command_processor_->IssueSwap(); });
|
||||
}
|
||||
|
||||
const uint8_t* GL4GraphicsSystem::PlayTrace(const uint8_t* trace_data,
|
||||
size_t trace_size,
|
||||
TracePlaybackMode playback_mode) {
|
||||
auto trace_ptr = trace_data;
|
||||
command_processor_->CallInThread([&]() {
|
||||
bool pending_break = false;
|
||||
const PacketStartCommand* pending_packet = nullptr;
|
||||
while (trace_ptr < trace_data + trace_size) {
|
||||
auto type =
|
||||
static_cast<TraceCommandType>(poly::load<uint32_t>(trace_ptr));
|
||||
switch (type) {
|
||||
case TraceCommandType::kPrimaryBufferStart: {
|
||||
auto cmd =
|
||||
reinterpret_cast<const PrimaryBufferStartCommand*>(trace_ptr);
|
||||
//
|
||||
trace_ptr += sizeof(*cmd) + cmd->count * 4;
|
||||
break;
|
||||
}
|
||||
case TraceCommandType::kPrimaryBufferEnd: {
|
||||
auto cmd =
|
||||
reinterpret_cast<const PrimaryBufferEndCommand*>(trace_ptr);
|
||||
//
|
||||
trace_ptr += sizeof(*cmd);
|
||||
break;
|
||||
}
|
||||
case TraceCommandType::kIndirectBufferStart: {
|
||||
auto cmd =
|
||||
reinterpret_cast<const IndirectBufferStartCommand*>(trace_ptr);
|
||||
//
|
||||
trace_ptr += sizeof(*cmd) + cmd->count * 4;
|
||||
break;
|
||||
}
|
||||
case TraceCommandType::kIndirectBufferEnd: {
|
||||
auto cmd =
|
||||
reinterpret_cast<const IndirectBufferEndCommand*>(trace_ptr);
|
||||
//
|
||||
trace_ptr += sizeof(*cmd);
|
||||
break;
|
||||
}
|
||||
case TraceCommandType::kPacketStart: {
|
||||
auto cmd = reinterpret_cast<const PacketStartCommand*>(trace_ptr);
|
||||
trace_ptr += sizeof(*cmd);
|
||||
std::memcpy(memory()->Translate(cmd->base_ptr), trace_ptr,
|
||||
cmd->count * 4);
|
||||
trace_ptr += cmd->count * 4;
|
||||
pending_packet = cmd;
|
||||
break;
|
||||
}
|
||||
case TraceCommandType::kPacketEnd: {
|
||||
auto cmd = reinterpret_cast<const PacketEndCommand*>(trace_ptr);
|
||||
trace_ptr += sizeof(*cmd);
|
||||
if (pending_packet) {
|
||||
command_processor_->ExecutePacket(pending_packet->base_ptr,
|
||||
pending_packet->count);
|
||||
pending_packet = nullptr;
|
||||
}
|
||||
if (pending_break) {
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case TraceCommandType::kMemoryRead: {
|
||||
auto cmd = reinterpret_cast<const MemoryReadCommand*>(trace_ptr);
|
||||
trace_ptr += sizeof(*cmd);
|
||||
std::memcpy(memory()->Translate(cmd->base_ptr), trace_ptr,
|
||||
cmd->length);
|
||||
trace_ptr += cmd->length;
|
||||
break;
|
||||
}
|
||||
case TraceCommandType::kMemoryWrite: {
|
||||
auto cmd = reinterpret_cast<const MemoryWriteCommand*>(trace_ptr);
|
||||
trace_ptr += sizeof(*cmd);
|
||||
// ?
|
||||
trace_ptr += cmd->length;
|
||||
break;
|
||||
}
|
||||
case TraceCommandType::kEvent: {
|
||||
auto cmd = reinterpret_cast<const EventCommand*>(trace_ptr);
|
||||
trace_ptr += sizeof(*cmd);
|
||||
switch (cmd->event_type) {
|
||||
case EventType::kSwap: {
|
||||
if (playback_mode == TracePlaybackMode::kBreakOnSwap) {
|
||||
pending_break = true;
|
||||
void GL4GraphicsSystem::PlayTrace(const uint8_t* trace_data, size_t trace_size,
|
||||
TracePlaybackMode playback_mode) {
|
||||
command_processor_->CallInThread(
|
||||
[this, trace_data, trace_size, playback_mode]() {
|
||||
command_processor_->set_swap_mode(SwapMode::kIgnored);
|
||||
|
||||
auto trace_ptr = trace_data;
|
||||
bool pending_break = false;
|
||||
const PacketStartCommand* pending_packet = nullptr;
|
||||
while (trace_ptr < trace_data + trace_size) {
|
||||
auto type =
|
||||
static_cast<TraceCommandType>(poly::load<uint32_t>(trace_ptr));
|
||||
switch (type) {
|
||||
case TraceCommandType::kPrimaryBufferStart: {
|
||||
auto cmd =
|
||||
reinterpret_cast<const PrimaryBufferStartCommand*>(trace_ptr);
|
||||
//
|
||||
trace_ptr += sizeof(*cmd) + cmd->count * 4;
|
||||
break;
|
||||
}
|
||||
case TraceCommandType::kPrimaryBufferEnd: {
|
||||
auto cmd =
|
||||
reinterpret_cast<const PrimaryBufferEndCommand*>(trace_ptr);
|
||||
//
|
||||
trace_ptr += sizeof(*cmd);
|
||||
break;
|
||||
}
|
||||
case TraceCommandType::kIndirectBufferStart: {
|
||||
auto cmd = reinterpret_cast<const IndirectBufferStartCommand*>(
|
||||
trace_ptr);
|
||||
//
|
||||
trace_ptr += sizeof(*cmd) + cmd->count * 4;
|
||||
break;
|
||||
}
|
||||
case TraceCommandType::kIndirectBufferEnd: {
|
||||
auto cmd =
|
||||
reinterpret_cast<const IndirectBufferEndCommand*>(trace_ptr);
|
||||
//
|
||||
trace_ptr += sizeof(*cmd);
|
||||
break;
|
||||
}
|
||||
case TraceCommandType::kPacketStart: {
|
||||
auto cmd = reinterpret_cast<const PacketStartCommand*>(trace_ptr);
|
||||
trace_ptr += sizeof(*cmd);
|
||||
std::memcpy(memory()->Translate(cmd->base_ptr), trace_ptr,
|
||||
cmd->count * 4);
|
||||
trace_ptr += cmd->count * 4;
|
||||
pending_packet = cmd;
|
||||
break;
|
||||
}
|
||||
case TraceCommandType::kPacketEnd: {
|
||||
auto cmd = reinterpret_cast<const PacketEndCommand*>(trace_ptr);
|
||||
trace_ptr += sizeof(*cmd);
|
||||
if (pending_packet) {
|
||||
command_processor_->ExecutePacket(pending_packet->base_ptr,
|
||||
pending_packet->count);
|
||||
pending_packet = nullptr;
|
||||
}
|
||||
if (pending_break) {
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case TraceCommandType::kMemoryRead: {
|
||||
auto cmd = reinterpret_cast<const MemoryReadCommand*>(trace_ptr);
|
||||
trace_ptr += sizeof(*cmd);
|
||||
std::memcpy(memory()->Translate(cmd->base_ptr), trace_ptr,
|
||||
cmd->length);
|
||||
trace_ptr += cmd->length;
|
||||
break;
|
||||
}
|
||||
case TraceCommandType::kMemoryWrite: {
|
||||
auto cmd = reinterpret_cast<const MemoryWriteCommand*>(trace_ptr);
|
||||
trace_ptr += sizeof(*cmd);
|
||||
// ?
|
||||
trace_ptr += cmd->length;
|
||||
break;
|
||||
}
|
||||
case TraceCommandType::kEvent: {
|
||||
auto cmd = reinterpret_cast<const EventCommand*>(trace_ptr);
|
||||
trace_ptr += sizeof(*cmd);
|
||||
switch (cmd->event_type) {
|
||||
case EventType::kSwap: {
|
||||
if (playback_mode == TracePlaybackMode::kBreakOnSwap) {
|
||||
pending_break = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
return trace_ptr;
|
||||
|
||||
command_processor_->set_swap_mode(SwapMode::kNormal);
|
||||
});
|
||||
}
|
||||
|
||||
void GL4GraphicsSystem::MarkVblank() {
|
||||
|
||||
@@ -38,8 +38,8 @@ class GL4GraphicsSystem : public GraphicsSystem {
|
||||
|
||||
void RequestSwap() override;
|
||||
|
||||
const uint8_t* PlayTrace(const uint8_t* trace_data, size_t trace_size,
|
||||
TracePlaybackMode playback_mode) override;
|
||||
void PlayTrace(const uint8_t* trace_data, size_t trace_size,
|
||||
TracePlaybackMode playback_mode) override;
|
||||
|
||||
private:
|
||||
void MarkVblank();
|
||||
|
||||
@@ -91,6 +91,9 @@ LRESULT WGLControl::WndProc(HWND hWnd, UINT message, WPARAM wParam,
|
||||
current_paint_callback_ = nullptr;
|
||||
}
|
||||
|
||||
poly::ui::UIEvent e(this);
|
||||
OnPaint(e);
|
||||
|
||||
// TODO(benvanik): profiler present.
|
||||
Profiler::Present();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user