<commit_before>/**
 ******************************************************************************
 * Xenia : Xbox 360 Emulator Research Project                                 *
 ******************************************************************************
 * Copyright 2013 <NAME>. All rights reserved.                             *
 * Released under the BSD license - see LICENSE in the root for more details. *
 ******************************************************************************
 */

#include <xenia/gpu/ring_buffer_worker.h>

#include <xenia/gpu/graphics_driver.h>
#include <xenia/gpu/xenos/packets.h>
#include <xenia/gpu/xenos/registers.h>


using namespace xe;
using namespace xe::gpu;
using namespace xe::gpu::xenos;


RingBufferWorker::RingBufferWorker(xe_memory_ref memory) :
    memory_(memory), driver_(0) {
  write_ptr_index_event_ = CreateEvent(
      NULL, TRUE, FALSE, NULL);

  primary_buffer_ptr_     = 0;
  primary_buffer_size_    = 0;
  read_ptr_index_         = 0;
  read_ptr_update_freq_   = 0;
  read_ptr_writeback_ptr_ = 0;
  write_ptr_index_        = 0;
}

RingBufferWorker::~RingBufferWorker() {
  SetEvent(write_ptr_index_event_);
  CloseHandle(write_ptr_index_event_);
}

void RingBufferWorker::Initialize(GraphicsDriver* driver,
                                  uint32_t ptr, uint32_t page_count) {
  driver_               = driver;
  primary_buffer_ptr_   = ptr;
  primary_buffer_size_  = page_count * 4 * 1024;
  read_ptr_index_       = 0;
}

void RingBufferWorker::EnableReadPointerWriteBack(uint32_t ptr,
                                                  uint32_t block_size) {
  // CP_RB_RPTR_ADDR Ring Buffer Read Pointer Address 0x70C
  // ptr = RB_RPTR_ADDR, pointer to write back the address to.
  read_ptr_writeback_ptr_ = (primary_buffer_ptr_ & ~0x1FFFFFFF) + ptr;
  // CP_RB_CNTL Ring Buffer Control 0x704
  // block_size = RB_BLKSZ, number of quadwords read between updates of the
  //              read pointer.
  read_ptr_update_freq_ = (uint32_t)pow(2.0, (double)block_size) / 4;
}

void RingBufferWorker::UpdateWritePointer(uint32_t value) {
  write_ptr_index_ = value;
  SetEvent(write_ptr_index_event_);
}

void RingBufferWorker::Pump() {
  uint8_t* p = xe_memory_addr(memory_);

  if (write_ptr_index_ == 0xBAADF00D ||
      read_ptr_index_ == write_ptr_index_) {
    // Check if the pointer has moved.
    // We wait a short bit here to yield time. Since we are also running the
    // main window display we don't want to pause too long, though.
    const int wait_time_ms = 1;
    if (WaitForSingleObject(write_ptr_index_event_,
                            wait_time_ms) == WAIT_TIMEOUT) {
      return;
    }
  }
  if (read_ptr_index_ == write_ptr_index_) {
    return;
  }
  ResetEvent(write_ptr_index_event_);

  // Process the new commands.
  XELOGGPU("Ring buffer thread work");

  // TODO(benvanik): handle wrapping around
  // read_ptr_index_ = (read_ptr_index_ + 1) % (primary_buffer_size_ / 4);
  XEASSERT(write_ptr_index_ > read_ptr_index_);
  uint32_t length = write_ptr_index_ - read_ptr_index_;
  if (length) {
    ExecuteSegment(primary_buffer_ptr_ + read_ptr_index_ * 4, length);
    read_ptr_index_ = write_ptr_index_;
  }

  // TODO(benvanik): use read_ptr_update_freq_ and only issue after moving
  //     that many indices.
  if (read_ptr_writeback_ptr_) {
    XESETUINT32BE(p + read_ptr_writeback_ptr_, read_ptr_index_);
  }
}

void RingBufferWorker::ExecuteSegment(uint32_t ptr, uint32_t length) {
  uint8_t* p = xe_memory_addr(memory_);<commit_msg>Manual reset was not the solution. Bah.<commit_after>/**
 ******************************************************************************
 * Xenia : Xbox 360 Emulator Research Project                                 *
 ******************************************************************************
 * Copyright 2013 <NAME>. All rights reserved.                             *
 * Released under the BSD license - see LICENSE in the root for more details. *
 ******************************************************************************
 */

#include <xenia/gpu/ring_buffer_worker.h>

#include <xenia/gpu/graphics_driver.h>
#include <xenia/gpu/xenos/packets.h>
#include <xenia/gpu/xenos/registers.h>


using namespace xe;
using namespace xe::gpu;
using namespace xe::gpu::xenos;


RingBufferWorker::RingBufferWorker(xe_memory_ref memory) :
    memory_(memory), driver_(0) {
  write_ptr_index_event_ = CreateEvent(
      NULL, FALSE, FALSE, NULL);

  primary_buffer_ptr_     = 0;
  primary_buffer_size_    = 0;
  read_ptr_index_         = 0;
  read_ptr_update_freq_   = 0;
  read_ptr_writeback_ptr_ = 0;
  write_ptr_index_        = 0;
}

RingBufferWorker::~RingBufferWorker() {
  SetEvent(write_ptr_index_event_);
  CloseHandle(write_ptr_index_event_);
}

void RingBufferWorker::Initialize(GraphicsDriver* driver,
                                  uint32_t ptr, uint32_t page_count) {
  driver_               = driver;
  primary_buffer_ptr_   = ptr;
  primary_buffer_size_  = page_count * 4 * 1024;
  read_ptr_index_       = 0;
}

void RingBufferWorker::EnableReadPointerWriteBack(uint32_t ptr,
                                                  uint32_t block_size) {
  // CP_RB_RPTR_ADDR Ring Buffer Read Pointer Address 0x70C
  // ptr = RB_RPTR_ADDR, pointer to write back the address to.
  read_ptr_writeback_ptr_ = (primary_buffer_ptr_ & ~0x1FFFFFFF) + ptr;
  // CP_RB_CNTL Ring Buffer Control 0x704
  // block_size = RB_BLKSZ, number of quadwords read between updates of the
  //              read pointer.
  read_ptr_update_freq_ = (uint32_t)pow(2.0, (double)block_size) / 4;
}

void RingBufferWorker::UpdateWritePointer(uint32_t value) {
  write_ptr_index_ = value;
  SetEvent(write_ptr_index_event_);
}

void RingBufferWorker::Pump() {
  uint8_t* p = xe_memory_addr(memory_);

  if (write_ptr_index_ == 0xBAADF00D ||
      read_ptr_index_ == write_ptr_index_) {
    // Check if the pointer has moved.
    // We wait a short bit here to yield time. Since we are also running the
    // main window display we don't want to pause too long, though.
    const int wait_time_ms = 1;
    if (WaitForSingleObject(write_ptr_index_event_,
                            wait_time_ms) == WAIT_TIMEOUT) {
      return;
    }
  }
  if (read_ptr_index_ == write_ptr_index_) {
    return;
  }

  // Process the new commands.
  XELOGGPU("Ring buffer thread work");

  // TODO(benvanik): handle wrapping around
  // read_ptr_index_ = (read_ptr_index_ + 1) % (primary_buffer_size_ / 4);
  XEASSERT(write_ptr_index_ > read_ptr_index_);
  uint32_t length = write_ptr_index_ - read_ptr_index_;
  if (length) {
    ExecuteSegment(primary_buffer_ptr_ + read_ptr_index_ * 4, length);
    read_ptr_index_ = write_ptr_index_;
  }

  // TODO(benvanik): use read_ptr_update_freq_ and only issue after moving
  //     that many indices.
  if (read_ptr_writeback_ptr_) {
    XESETUINT32BE(p + read_ptr_writeback_ptr_, read_ptr_index_);
  }
}

void RingBufferWorker::ExecuteSegment(uint32_t ptr, uint32_t length) {
  uint8_t* p = xe_memory_addr(memory_);
{'fraction_non_alphanumeric': 0.14997875655006374, 'fraction_numerical': 0.017278005948165982, 'mean_word_length': 3.41375, 'pattern_counts': {'":': 0, '<': 13, '<?xml version=': 0, '>': 15, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 2, 'word_list_counts': {'cursed_substrings.json': 6, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3380915', 'n_tokens_mistral': 2374, 'n_tokens_neox': 2215, 'n_words': 500}