Add support for Optimize DS mode

This commit is contained in:
Lorenzooone 2025-04-10 04:47:28 +02:00
parent 8e87c7afd1
commit aec8741cb4
3 changed files with 260 additions and 95 deletions

View File

@ -82,13 +82,21 @@ struct PACKED USB3DSOptimizeSingleSoundData {
uint16_t sample_r;
};
struct PACKED USB3DSOptimizeHeaderSoundData {
struct PACKED USB3DSOptimizeColumnInfo {
// Order is Little Endian
uint16_t magic;
uint16_t unk_fixed_1 : 1;
uint16_t buffer_num : 1;
uint16_t unk : 4;
uint16_t column_index : 10;
uint16_t unk : 4;
uint16_t buffer_num : 1;
uint16_t has_extra_header_data : 1;
};
struct PACKED USB3DSOptimizeHeaderData {
uint16_t magic;
USB3DSOptimizeColumnInfo column_info;
};
struct PACKED USB3DSOptimizeHeaderSoundData {
USB3DSOptimizeHeaderData header_info;
USB3DSOptimizeSingleSoundData samples[2];
};
@ -223,6 +231,22 @@ struct ALIGNED(16) PACKED USB8883DSOptimizeCaptureReceived_3D {
USB8883DSOptimizePixelData bottom_only_column[HEIGHT_3DS][3];
};
struct ALIGNED(16) PACKED USB5653DSOptimizeCaptureReceivedExtraHeader {
USB5653DSOptimizeInputColumnData columns_data[TOP_WIDTH_3DS + 1];
};
struct ALIGNED(16) PACKED USB5653DSOptimizeCaptureReceived_3DExtraHeader {
USB5653DSOptimizeInputColumnData3D columns_data[TOP_WIDTH_3DS + 1];
};
struct ALIGNED(16) PACKED USB8883DSOptimizeCaptureReceivedExtraHeader {
USB8883DSOptimizeInputColumnData columns_data[TOP_WIDTH_3DS + 1];
};
struct ALIGNED(16) PACKED USB8883DSOptimizeCaptureReceived_3DExtraHeader {
USB8883DSOptimizeInputColumnData3D columns_data[TOP_WIDTH_3DS + 1];
};
#pragma pack(pop)
struct ALIGNED(16) FTD2OldDSCaptureReceivedNormalPlusRaw {
@ -245,6 +269,10 @@ union CaptureReceived {
USB5653DSOptimizeCaptureReceived_3D cypress_optimize_received_565_3d;
USB8883DSOptimizeCaptureReceived cypress_optimize_received_888;
USB8883DSOptimizeCaptureReceived_3D cypress_optimize_received_888_3d;
USB5653DSOptimizeCaptureReceivedExtraHeader cypress_optimize_received_565_extra_header;
USB5653DSOptimizeCaptureReceived_3DExtraHeader cypress_optimize_received_565_3d_extra_header;
USB8883DSOptimizeCaptureReceivedExtraHeader cypress_optimize_received_888_extra_header;
USB8883DSOptimizeCaptureReceived_3DExtraHeader cypress_optimize_received_888_3d_extra_header;
};
struct CaptureDevice {

View File

@ -42,7 +42,8 @@ struct CypressOptimize3DSDeviceCaptureReceivedData {
bool* is_ring_buffer_slice_data_ready_arr;
int ring_buffer_slice_index;
int* last_ring_buffer_slice_allocated;
int* last_used_ring_buffer_slice_index;
int* first_usable_ring_buffer_slice_index;
bool* is_synchronized;
size_t* last_used_ring_buffer_slice_pos;
int* buffer_ring_slice_to_array_ptr;
InputVideoDataType* stored_video_data_type;
@ -201,6 +202,18 @@ uint64_t cyop_device_get_video_in_size(bool is_3d, InputVideoDataType video_data
return sizeof(USB5653DSOptimizeCaptureReceived);
}
uint64_t cyop_device_get_video_in_size_extra_header(bool is_3d, InputVideoDataType video_data_type) {
bool is_rgb888 = video_data_type == VIDEO_DATA_RGB;
if(is_rgb888) {
if(is_3d)
return sizeof(USB8883DSOptimizeCaptureReceived_3DExtraHeader);
return sizeof(USB8883DSOptimizeCaptureReceivedExtraHeader);
}
if(is_3d)
return sizeof(USB5653DSOptimizeCaptureReceived_3DExtraHeader);
return sizeof(USB5653DSOptimizeCaptureReceivedExtraHeader);
}
uint64_t cyop_device_get_video_in_size(CaptureStatus* status, bool is_3d, InputVideoDataType video_data_type) {
return cyop_device_get_video_in_size(is_3d, video_data_type);
@ -234,35 +247,63 @@ static int cypress_device_read_frame_request(CaptureData* capture_data, CypressO
return ReadFrameAsync((cy_device_device_handlers*)capture_data->handle, buffer, (int)read_size, usb_device_info, &cypress_device_capture_recv_data->cb_data);
}
static void unlock_buffer_directly(CypressOptimize3DSDeviceCaptureReceivedData* cypress_device_capture_recv_data_real) {
static void unlock_buffer_directly(CypressOptimize3DSDeviceCaptureReceivedData* cypress_device_capture_recv_data_real, bool reset_slice_data_arr_info) {
int slice_index = cypress_device_capture_recv_data_real->ring_buffer_slice_index;
if(reset_slice_data_arr_info) {
cypress_device_capture_recv_data_real->is_ring_buffer_slice_data_ready_arr[slice_index] = false;
cypress_device_capture_recv_data_real->is_ring_buffer_slice_data_in_use_arr[slice_index] = false;
}
cypress_device_capture_recv_data_real->buffer_ring_slice_to_array_ptr[slice_index] = -1;
cypress_device_capture_recv_data_real->in_use = false;
if(!cypress_device_capture_recv_data_real->to_process)
cypress_device_capture_recv_data_real->is_buffer_free_shared_mutex->specific_unlock(cypress_device_capture_recv_data_real->cb_data.internal_index);
}
static void unlock_buffer_slice_index(CypressOptimize3DSDeviceCaptureReceivedData* cypress_device_capture_recv_data, size_t slice_index) {
static void unlock_buffer_slice_index(CypressOptimize3DSDeviceCaptureReceivedData* cypress_device_capture_recv_data, size_t slice_index, bool reset_slice_data_arr_info) {
int index = cypress_device_capture_recv_data->buffer_ring_slice_to_array_ptr[slice_index];
if(index == -1)
if(index == -1) {
if(reset_slice_data_arr_info) {
cypress_device_capture_recv_data->is_ring_buffer_slice_data_ready_arr[slice_index] = false;
cypress_device_capture_recv_data->is_ring_buffer_slice_data_in_use_arr[slice_index] = false;
}
return;
unlock_buffer_directly(&cypress_device_capture_recv_data->array_ptr[index]);
}
unlock_buffer_directly(&cypress_device_capture_recv_data->array_ptr[index], reset_slice_data_arr_info);
}
static void end_cypress_device_read_frame_cb(CypressOptimize3DSDeviceCaptureReceivedData* cypress_device_capture_recv_data, bool to_unlock) {
cypress_device_capture_recv_data->to_process = false;
if(to_unlock)
unlock_buffer_directly(cypress_device_capture_recv_data);
unlock_buffer_directly(cypress_device_capture_recv_data, true);
cypress_device_capture_recv_data->to_process = false;
if(!cypress_device_capture_recv_data->in_use)
cypress_device_capture_recv_data->is_buffer_free_shared_mutex->specific_unlock(cypress_device_capture_recv_data->cb_data.internal_index);
}
static USB3DSOptimizeColumnInfo convert_to_column_info(uint16_t value) {
// The macos compiler requires this... :/
USB3DSOptimizeColumnInfo column_info;
column_info.has_extra_header_data = (value >> 15) & 1;
column_info.buffer_num = (value >> 14) & 1;
column_info.unk = (value >> 10) & 0xF;
column_info.column_index = value & 0x3FF;
return column_info;
}
static bool get_expect_extra_header_in_buffer(uint16_t value) {
return convert_to_column_info(value).has_extra_header_data;
}
static bool get_is_pos_first_synch_in_buffer(uint8_t* buffer, size_t pos_to_check) {
if(read_le16(buffer + pos_to_check) != SYNCH_VALUE_OPTIMIZE)
return false;
return convert_to_column_info(read_le16(buffer + pos_to_check + 2)).column_index == 0;
}
static size_t get_pos_first_synch_in_buffer(uint8_t* buffer) {
for(int i = 0; i < (SINGLE_RING_BUFFER_SLICE_SIZE / 2); i++) {
if(read_le16(buffer, i) == SYNCH_VALUE_OPTIMIZE) {
if((read_le16(buffer, i + 1) & 0x3FF) == 0)
if(get_is_pos_first_synch_in_buffer(buffer, i * 2))
return i * 2;
}
}
return SINGLE_RING_BUFFER_SLICE_SIZE + 1;
}
@ -276,18 +317,27 @@ static int get_num_consecutive_ready_ring_buffer_slices(CypressOptimize3DSDevice
return NUM_TOTAL_OPTIMIZE_3DS_CYPRESS_BUFFERS;
}
static void unlock_buffers_from_x(CypressOptimize3DSDeviceCaptureReceivedData* cypress_device_capture_recv_data, int pos_to_unlock, int num_buffers_to_unlock, bool reset_slice_data_arr_info) {
for(int i = 0; i < num_buffers_to_unlock; i++)
unlock_buffer_slice_index(cypress_device_capture_recv_data, (pos_to_unlock + i) % NUM_TOTAL_OPTIMIZE_3DS_CYPRESS_BUFFERS, reset_slice_data_arr_info);
}
static void copy_slice_data_to_buffer(uint8_t* dst, uint8_t *src, size_t start_slice_index, size_t start_slice_pos, size_t copy_size) {
size_t start_byte = (start_slice_index * SINGLE_RING_BUFFER_SLICE_SIZE) + start_slice_pos;
if((start_byte + copy_size) <= (NUM_TOTAL_OPTIMIZE_3DS_CYPRESS_BUFFERS * SINGLE_RING_BUFFER_SLICE_SIZE))
memcpy(dst, src + start_byte, copy_size);
else {
size_t upper_read_size = (NUM_TOTAL_OPTIMIZE_3DS_CYPRESS_BUFFERS * SINGLE_RING_BUFFER_SLICE_SIZE) - start_byte;
size_t start_read_size = copy_size - upper_read_size;
memcpy(dst, src + start_byte, upper_read_size);
memcpy(dst + upper_read_size, src, start_read_size);
}
}
static void cypress_output_to_thread(CaptureData* capture_data, uint8_t *buffer_arr, size_t start_slice_index, size_t start_slice_pos, int internal_index, std::chrono::time_point<std::chrono::high_resolution_clock>* clock_start, size_t read_size) {
// Output to the other threads...
CaptureDataSingleBuffer* data_buf = capture_data->data_buffers.GetWriterBuffer(internal_index);
size_t start_byte = (start_slice_index * SINGLE_RING_BUFFER_SLICE_SIZE) + start_slice_pos;
if((start_byte + read_size) <= (NUM_TOTAL_OPTIMIZE_3DS_CYPRESS_BUFFERS * SINGLE_RING_BUFFER_SLICE_SIZE))
memcpy(&data_buf->capture_buf, buffer_arr + start_byte, read_size);
else {
size_t upper_read_size = (NUM_TOTAL_OPTIMIZE_3DS_CYPRESS_BUFFERS * SINGLE_RING_BUFFER_SLICE_SIZE) - start_byte;
size_t start_read_size = read_size - upper_read_size;
memcpy(&data_buf->capture_buf, buffer_arr + start_byte, upper_read_size);
memcpy(((uint8_t*)&data_buf->capture_buf) + upper_read_size, buffer_arr, start_read_size);
}
copy_slice_data_to_buffer((uint8_t*)&data_buf->capture_buf, buffer_arr, start_slice_index, start_slice_pos, read_size);
const auto curr_time = std::chrono::high_resolution_clock::now();
const std::chrono::duration<double> diff = curr_time - (*clock_start);
*clock_start = curr_time;
@ -298,6 +348,88 @@ static void cypress_output_to_thread(CaptureData* capture_data, uint8_t *buffer_
capture_data->status.audio_wait.unlock();
}
static bool cypress_device_read_frame_not_synchronized(CypressOptimize3DSDeviceCaptureReceivedData* cypress_device_capture_recv_data, int &error) {
volatile int first_slice_to_check = *cypress_device_capture_recv_data->first_usable_ring_buffer_slice_index;
bool found = false;
// Determine which buffer is the first which needs to still be checked
for(int i = 0; i < NUM_OPTIMIZE_3DS_CYPRESS_CONCURRENTLY_RUNNING_BUFFERS; i++) {
int index_to_check = (first_slice_to_check + i) % NUM_TOTAL_OPTIMIZE_3DS_CYPRESS_BUFFERS;
if(cypress_device_capture_recv_data->is_ring_buffer_slice_data_in_use_arr[index_to_check]) {
first_slice_to_check = index_to_check;
found = true;
break;
}
}
// Too many have been checked... Just fail.
if(!found) {
error = LIBUSB_ERROR_OTHER;
return false;
}
for(int i = 0; i < NUM_TOTAL_OPTIMIZE_3DS_CYPRESS_BUFFERS; i++) {
int check_index = (first_slice_to_check + i) % NUM_TOTAL_OPTIMIZE_3DS_CYPRESS_BUFFERS;
// Search for the synch values. If they're not there, free the buffer.
// If they are there, enque the buffer and switch mode.
// Checks all available buffers which have data (but in order).
if(cypress_device_capture_recv_data->is_ring_buffer_slice_data_ready_arr[check_index]) {
size_t result = get_pos_first_synch_in_buffer(&cypress_device_capture_recv_data->ring_slice_buffer_arr[check_index * SINGLE_RING_BUFFER_SLICE_SIZE]);
if(result >= SINGLE_RING_BUFFER_SLICE_SIZE) {
unlock_buffer_slice_index(cypress_device_capture_recv_data, check_index, true);
}
else {
*cypress_device_capture_recv_data->first_usable_ring_buffer_slice_index = check_index;
*cypress_device_capture_recv_data->last_used_ring_buffer_slice_pos = result;
*cypress_device_capture_recv_data->is_synchronized = true;
break;
}
}
else
break;
}
return true;
}
static void cypress_device_read_frame_synchronized(CypressOptimize3DSDeviceCaptureReceivedData* cypress_device_capture_recv_data) {
volatile int read_slice_index = *cypress_device_capture_recv_data->first_usable_ring_buffer_slice_index;
volatile size_t read_slice_pos = *cypress_device_capture_recv_data->last_used_ring_buffer_slice_pos;
int num_consecutive_ready_buffers = get_num_consecutive_ready_ring_buffer_slices(cypress_device_capture_recv_data, read_slice_index);
size_t video_in_size = (size_t)cyop_device_get_video_in_size(*cypress_device_capture_recv_data->stored_is_3d, *cypress_device_capture_recv_data->stored_video_data_type);
size_t curr_consecutive_available_bytes = (num_consecutive_ready_buffers * SINGLE_RING_BUFFER_SLICE_SIZE) - read_slice_pos;
if(curr_consecutive_available_bytes >= sizeof(USB3DSOptimizeHeaderData)) {
uint8_t tmp_buffer[sizeof(USB3DSOptimizeHeaderData)];
copy_slice_data_to_buffer(tmp_buffer, cypress_device_capture_recv_data->ring_slice_buffer_arr, read_slice_index, read_slice_pos, sizeof(USB3DSOptimizeHeaderData));
if(!get_is_pos_first_synch_in_buffer(tmp_buffer, 0)) {
*cypress_device_capture_recv_data->is_synchronized = false;
return;
}
else {
if(get_expect_extra_header_in_buffer(read_le16(tmp_buffer, 1)))
video_in_size = (size_t)cyop_device_get_video_in_size_extra_header(*cypress_device_capture_recv_data->stored_is_3d, *cypress_device_capture_recv_data->stored_video_data_type);
}
}
if(curr_consecutive_available_bytes >= video_in_size) {
// Enough data. Time to do output...
cypress_output_to_thread(cypress_device_capture_recv_data->capture_data, cypress_device_capture_recv_data->ring_slice_buffer_arr, read_slice_index, read_slice_pos, 0, cypress_device_capture_recv_data->clock_start, video_in_size);
// Keep the ring buffer going.
size_t raw_new_pos = read_slice_pos + video_in_size;
int new_slice_index = (int)(read_slice_index + (raw_new_pos / SINGLE_RING_BUFFER_SLICE_SIZE));
size_t new_slice_pos = raw_new_pos % SINGLE_RING_BUFFER_SLICE_SIZE;
new_slice_index %= NUM_TOTAL_OPTIMIZE_3DS_CYPRESS_BUFFERS;
// Fully unlock used buffers
unlock_buffers_from_x(cypress_device_capture_recv_data, read_slice_index, (new_slice_index + NUM_TOTAL_OPTIMIZE_3DS_CYPRESS_BUFFERS - read_slice_index) % NUM_TOTAL_OPTIMIZE_3DS_CYPRESS_BUFFERS, true);
// Update the position of the data
*cypress_device_capture_recv_data->first_usable_ring_buffer_slice_index = new_slice_index;
*cypress_device_capture_recv_data->last_used_ring_buffer_slice_pos = new_slice_pos;
}
// Partially unlock buffers already with data.
// Unlocks the transfers to be used for more.
// This is possible under the assumption that there are significantly
// more buffers than transfers!!!
// Without said assumption, you'd risk the two stepping on each other.
read_slice_index = *cypress_device_capture_recv_data->first_usable_ring_buffer_slice_index;
num_consecutive_ready_buffers = get_num_consecutive_ready_ring_buffer_slices(cypress_device_capture_recv_data, read_slice_index);
unlock_buffers_from_x(cypress_device_capture_recv_data, read_slice_index, num_consecutive_ready_buffers, false);
}
static void cypress_device_read_frame_cb(void* user_data, int transfer_length, int transfer_status) {
CypressOptimize3DSDeviceCaptureReceivedData* cypress_device_capture_recv_data = (CypressOptimize3DSDeviceCaptureReceivedData*)user_data;
if((*cypress_device_capture_recv_data->status) < 0)
@ -310,66 +442,27 @@ static void cypress_device_read_frame_cb(void* user_data, int transfer_length, i
return end_cypress_device_read_frame_cb(cypress_device_capture_recv_data, true);
}
cypress_device_capture_recv_data->is_ring_buffer_slice_data_ready_arr[cypress_device_capture_recv_data->ring_buffer_slice_index] = true;
// First case
// Not synchronized case
bool to_free = false;
volatile int read_slice_index = *cypress_device_capture_recv_data->last_used_ring_buffer_slice_index;
if(read_slice_index == -1) {
size_t first_to_check = 0;
for(int i = 0; i < NUM_TOTAL_OPTIMIZE_3DS_CYPRESS_BUFFERS; i++) {
if(!cypress_device_capture_recv_data->is_ring_buffer_slice_data_in_use_arr[i])
first_to_check++;
else
break;
}
if(first_to_check > NUM_OPTIMIZE_3DS_CYPRESS_CONCURRENTLY_RUNNING_BUFFERS) {
int error = LIBUSB_ERROR_OTHER;
bool continue_looping = true;
int remaining_iters_before_force_exit = 4;
volatile bool read_is_synchronized = *cypress_device_capture_recv_data->is_synchronized;
while(continue_looping) {
if(read_is_synchronized)
cypress_device_read_frame_synchronized(cypress_device_capture_recv_data);
else {
int error = 0;
bool retval = cypress_device_read_frame_not_synchronized(cypress_device_capture_recv_data, error);
if(!retval) {
*cypress_device_capture_recv_data->status = error;
return end_cypress_device_read_frame_cb(cypress_device_capture_recv_data, true);
}
for(int i = 0; i < NUM_TOTAL_OPTIMIZE_3DS_CYPRESS_BUFFERS; i++) {
size_t check_index = (first_to_check + i) % NUM_TOTAL_OPTIMIZE_3DS_CYPRESS_BUFFERS;
if(cypress_device_capture_recv_data->is_ring_buffer_slice_data_ready_arr[check_index]) {
size_t result = get_pos_first_synch_in_buffer(&cypress_device_capture_recv_data->ring_slice_buffer_arr[check_index * SINGLE_RING_BUFFER_SLICE_SIZE]);
if(result >= SINGLE_RING_BUFFER_SLICE_SIZE) {
unlock_buffer_slice_index(cypress_device_capture_recv_data, check_index);
}
else {
*cypress_device_capture_recv_data->last_used_ring_buffer_slice_index = (int)check_index;
*cypress_device_capture_recv_data->last_used_ring_buffer_slice_pos = result;
break;
}
}
else
break;
}
}
// Generic case
read_slice_index = *cypress_device_capture_recv_data->last_used_ring_buffer_slice_index;
volatile size_t read_slice_pos = *cypress_device_capture_recv_data->last_used_ring_buffer_slice_pos;
if(read_slice_index != -1) {
int num_consecutive_ready_buffers = get_num_consecutive_ready_ring_buffer_slices(cypress_device_capture_recv_data, read_slice_index);
size_t video_in_size = (size_t)cyop_device_get_video_in_size(*cypress_device_capture_recv_data->stored_is_3d, *cypress_device_capture_recv_data->stored_video_data_type);
size_t raw_new_pos = read_slice_pos + video_in_size;
int num_needed_buffers = (int)((raw_new_pos + SINGLE_RING_BUFFER_SLICE_SIZE - 1) / SINGLE_RING_BUFFER_SLICE_SIZE);
if(num_consecutive_ready_buffers >= num_needed_buffers) {
// Enough data. Time to do output...
cypress_output_to_thread(cypress_device_capture_recv_data->capture_data, cypress_device_capture_recv_data->ring_slice_buffer_arr, read_slice_index, read_slice_pos, 0, cypress_device_capture_recv_data->clock_start, video_in_size);
// Keep the ring buffer going.
int new_slice_index = read_slice_index + num_needed_buffers - 1;
size_t new_slice_pos = raw_new_pos % SINGLE_RING_BUFFER_SLICE_SIZE;
if(new_slice_pos == 0)
new_slice_index += 1;
new_slice_index %= NUM_TOTAL_OPTIMIZE_3DS_CYPRESS_BUFFERS;
// Unlock the buffers already processed
int pos_to_unlock = read_slice_index;
while(pos_to_unlock != new_slice_index) {
unlock_buffer_slice_index(cypress_device_capture_recv_data, pos_to_unlock);
pos_to_unlock = (pos_to_unlock + 1) % NUM_TOTAL_OPTIMIZE_3DS_CYPRESS_BUFFERS;
}
// Update the position of the data
*cypress_device_capture_recv_data->last_used_ring_buffer_slice_index = new_slice_index;
*cypress_device_capture_recv_data->last_used_ring_buffer_slice_pos = new_slice_pos;
}
volatile bool new_read_is_synchronized = *cypress_device_capture_recv_data->is_synchronized;
remaining_iters_before_force_exit--;
if((new_read_is_synchronized == read_is_synchronized) || (remaining_iters_before_force_exit == 0))
continue_looping = false;
read_is_synchronized = new_read_is_synchronized;
}
return end_cypress_device_read_frame_cb(cypress_device_capture_recv_data, to_free);
}
@ -403,10 +496,9 @@ static void error_too_much_time_passed(CaptureData* capture_data, CypressOptimiz
}
}
static void check_unlock_waiting_with_error(CypressOptimize3DSDeviceCaptureReceivedData* cypress_device_capture_recv_data) {
if(get_cypress_device_status(cypress_device_capture_recv_data) < 0) {
if(cypress_device_capture_recv_data->is_ring_buffer_slice_data_ready_arr[cypress_device_capture_recv_data->ring_buffer_slice_index])
unlock_buffer_directly(cypress_device_capture_recv_data);
static void unlock_buffer_in_error_case(CypressOptimize3DSDeviceCaptureReceivedData* cypress_device_capture_recv_data, int status) {
if((status < 0) && (!cypress_device_capture_recv_data->to_process)) {
unlock_buffer_directly(cypress_device_capture_recv_data, true);
}
}
@ -419,7 +511,7 @@ static void wait_all_cypress_device_buffers_free(CaptureData* capture_data, Cypr
for(int i = 0; i < NUM_OPTIMIZE_3DS_CYPRESS_CONCURRENTLY_RUNNING_BUFFERS; i++)
while(cypress_device_capture_recv_data[i].in_use) {
error_too_much_time_passed(capture_data, cypress_device_capture_recv_data, async_read_closed, start_time);
check_unlock_waiting_with_error(&cypress_device_capture_recv_data[i]);
unlock_buffer_in_error_case(&cypress_device_capture_recv_data[i], get_cypress_device_status(cypress_device_capture_recv_data));
cypress_device_capture_recv_data[i].is_buffer_free_shared_mutex->specific_timed_lock(i);
}
}
@ -429,7 +521,7 @@ static void wait_one_cypress_device_buffer_free(CaptureData* capture_data, Cypre
const auto start_time = std::chrono::high_resolution_clock::now();
while(!done) {
for(int i = 0; i < NUM_OPTIMIZE_3DS_CYPRESS_CONCURRENTLY_RUNNING_BUFFERS; i++) {
if(!cypress_device_capture_recv_data[i].in_use)
if((!cypress_device_capture_recv_data[i].in_use) && (!cypress_device_capture_recv_data[i].to_process))
done = true;
}
if(!done) {
@ -448,7 +540,7 @@ static CypressOptimize3DSDeviceCaptureReceivedData* cypress_device_get_free_buff
if(get_cypress_device_status(cypress_device_capture_recv_data) < 0)
return NULL;
for(int i = 0; i < NUM_OPTIMIZE_3DS_CYPRESS_CONCURRENTLY_RUNNING_BUFFERS; i++)
if(!cypress_device_capture_recv_data[i].in_use) {
if((!cypress_device_capture_recv_data[i].in_use) && (!cypress_device_capture_recv_data[i].to_process)) {
return &cypress_device_capture_recv_data[i];
}
return NULL;
@ -478,7 +570,7 @@ static bool cyop_device_acquisition_loop(CaptureData* capture_data, CypressOptim
capture_error_print(true, capture_data, "Capture Start: Failed");
return false;
}
CypressSetMaxTransferSize(handlers, get_cy_usb_info(usb_device_desc), (size_t)cyop_device_get_video_in_size(stored_is_3d, stored_video_data_type));
CypressSetMaxTransferSize(handlers, get_cy_usb_info(usb_device_desc), (size_t)cyop_device_get_video_in_size_extra_header(stored_is_3d, stored_video_data_type));
for(int i = 0; i < NUM_OPTIMIZE_3DS_CYPRESS_CONCURRENTLY_RUNNING_BUFFERS; i++) {
CypressOptimize3DSDeviceCaptureReceivedData* chosen_buffer = cypress_device_get_free_buffer(capture_data, cypress_device_capture_recv_data);
ret = cypress_device_read_frame_request(capture_data, chosen_buffer, index++, stored_is_3d, stored_video_data_type);
@ -536,7 +628,8 @@ void cyop_device_acquisition_main_loop(CaptureData* capture_data) {
is_ring_buffer_slice_data_in_use[i] = false;
buffer_ring_slice_to_array[i] = -1;
}
int last_used_ring_buffer_slice_index = -1;
int first_usable_ring_buffer_slice_index = 0;
bool is_synchronized = false;
size_t last_used_ring_buffer_slice_pos = 0;
int last_ring_buffer_slice_allocated = -1;
@ -557,7 +650,8 @@ void cyop_device_acquisition_main_loop(CaptureData* capture_data) {
cypress_device_capture_recv_data[i].is_ring_buffer_slice_data_in_use_arr = is_ring_buffer_slice_data_in_use;
cypress_device_capture_recv_data[i].is_ring_buffer_slice_data_ready_arr = is_ring_buffer_slice_data_ready;
cypress_device_capture_recv_data[i].last_ring_buffer_slice_allocated = &last_ring_buffer_slice_allocated;
cypress_device_capture_recv_data[i].last_used_ring_buffer_slice_index = &last_used_ring_buffer_slice_index;
cypress_device_capture_recv_data[i].first_usable_ring_buffer_slice_index = &first_usable_ring_buffer_slice_index;
cypress_device_capture_recv_data[i].is_synchronized = &is_synchronized;
cypress_device_capture_recv_data[i].last_used_ring_buffer_slice_pos = &last_used_ring_buffer_slice_pos;
cypress_device_capture_recv_data[i].buffer_ring_slice_to_array_ptr = buffer_ring_slice_to_array;
cypress_device_capture_recv_data[i].capture_data = capture_data;

View File

@ -432,6 +432,14 @@ static inline void usb_oldDSconvertVideoToOutputHalfLineDirectOptBE(USBOldDSCapt
usb_rgb565convertInterleaveVideoToOutputDirectOptBE(out_ptr_top, out_ptr_bottom, in_ptr, halfline_iters, input_halfline, output_halfline);
}
static inline bool usb_OptimizeHasExtraHeaderSoundData(USB3DSOptimizeHeaderSoundData* header_sound_data) {
// The macos compiler requires this... :/
uint16_t base_data = read_le16((uint8_t*)&header_sound_data->header_info.column_info);
USB3DSOptimizeColumnInfo column_info;
column_info.has_extra_header_data = (base_data >> 15) & 1;
return column_info.has_extra_header_data;
}
static inline void usb_3DS565OptimizeconvertVideoToOutputLineDirectOptLE(USB5653DSOptimizeCaptureReceived *p_in, VideoOutputData *p_out, uint16_t column) {
//de-interleave pixels
const int pixels_size = 2;
@ -444,6 +452,8 @@ static inline void usb_3DS565OptimizeconvertVideoToOutputLineDirectOptLE(USB5653
interleaved_rgb565_pixels* in_ptr = (interleaved_rgb565_pixels*)p_in->bottom_only_column;
if(column < column_last_bot_pos)
in_ptr = (interleaved_rgb565_pixels*)p_in->columns_data[column].pixel;
else if(usb_OptimizeHasExtraHeaderSoundData(&p_in->columns_data[0].header_sound))
in_ptr = (interleaved_rgb565_pixels*)(((USB5653DSOptimizeCaptureReceivedExtraHeader*)p_in)->columns_data[column].pixel);
const uint32_t num_iters = HEIGHT_3DS;
if(column == column_last_bot_pos)
usb_rgb565convertInterleaveVideoToOutputDirectOptLEMonoBottom(out_ptr_bottom, in_ptr, num_iters, 0, BOT_WIDTH_3DS - 1);
@ -471,6 +481,8 @@ static inline void usb_3DS565OptimizeconvertVideoToOutputLineDirectOptBE(USB5653
interleaved_rgb565_pixels* in_ptr = (interleaved_rgb565_pixels*)p_in->bottom_only_column;
if(column < column_last_bot_pos)
in_ptr = (interleaved_rgb565_pixels*)p_in->columns_data[column].pixel;
else if(usb_OptimizeHasExtraHeaderSoundData(&p_in->columns_data[0].header_sound))
in_ptr = (interleaved_rgb565_pixels*)(((USB5653DSOptimizeCaptureReceivedExtraHeader*)p_in)->columns_data[column].pixel);
const uint32_t num_iters = HEIGHT_3DS;
if(column == column_last_bot_pos)
usb_rgb565convertInterleaveVideoToOutputDirectOptBEMonoBottom(out_ptr_bottom, in_ptr, num_iters, 0, BOT_WIDTH_3DS - 1);
@ -499,6 +511,8 @@ static inline void usb_3DS565Optimizeconvert3DVideoToOutputLineDirectOptLE(USB56
interleaved_3d_rgb565_pixels* in_ptr = (interleaved_3d_rgb565_pixels*)p_in->bottom_only_column;
if(column < column_last_bot_pos)
in_ptr = (interleaved_3d_rgb565_pixels*)p_in->columns_data[column].pixel;
else if(usb_OptimizeHasExtraHeaderSoundData(&p_in->columns_data[0].header_sound))
in_ptr = (interleaved_3d_rgb565_pixels*)(((USB5653DSOptimizeCaptureReceived_3DExtraHeader*)p_in)->columns_data[column].pixel);
int multiplier_top = 1;
if(interleaved_3d) {
multiplier_top = 2;
@ -533,6 +547,8 @@ static inline void usb_3DS565Optimizeconvert3DVideoToOutputLineDirectOptBE(USB56
interleaved_3d_rgb565_pixels* in_ptr = (interleaved_3d_rgb565_pixels*)p_in->bottom_only_column;
if(column < column_last_bot_pos)
in_ptr = (interleaved_3d_rgb565_pixels*)p_in->columns_data[column].pixel;
else if(usb_OptimizeHasExtraHeaderSoundData(&p_in->columns_data[0].header_sound))
in_ptr = (interleaved_3d_rgb565_pixels*)(((USB5653DSOptimizeCaptureReceived_3DExtraHeader*)p_in)->columns_data[column].pixel);
int multiplier_top = 1;
if(interleaved_3d) {
multiplier_top = 2;
@ -566,6 +582,8 @@ static inline void usb_3DS888OptimizeconvertVideoToOutputLineDirectOpt(USB8883DS
interleaved_rgb888_u16_pixels* in_ptr = (interleaved_rgb888_u16_pixels*)p_in->bottom_only_column;
if(column < column_last_bot_pos)
in_ptr = (interleaved_rgb888_u16_pixels*)p_in->columns_data[column].pixel;
else if(usb_OptimizeHasExtraHeaderSoundData(&p_in->columns_data[0].header_sound))
in_ptr = (interleaved_rgb888_u16_pixels*)(((USB8883DSOptimizeCaptureReceivedExtraHeader*)p_in)->columns_data[column].pixel);
const uint32_t num_iters = HEIGHT_3DS;
if(column == column_last_bot_pos)
usb_rgb888convertInterleaveU16VideoToOutputDirectOptMonoBottom(out_ptr_bottom, in_ptr, num_iters, 0, BOT_WIDTH_3DS - 1);
@ -594,6 +612,8 @@ static inline void usb_3DS888Optimizeconvert3DVideoToOutputLineDirectOpt(USB8883
interleaved_3d_rgb888_u16_pixels* in_ptr = (interleaved_3d_rgb888_u16_pixels*)p_in->bottom_only_column;
if(column < column_last_bot_pos)
in_ptr = (interleaved_3d_rgb888_u16_pixels*)p_in->columns_data[column].pixel;
else if(usb_OptimizeHasExtraHeaderSoundData(&p_in->columns_data[0].header_sound))
in_ptr = (interleaved_3d_rgb888_u16_pixels*)(((USB8883DSOptimizeCaptureReceived_3DExtraHeader*)p_in)->columns_data[column].pixel);
int multiplier_top = 1;
if(interleaved_3d) {
multiplier_top = 2;
@ -851,6 +871,17 @@ static USB3DSOptimizeHeaderSoundData* getAudioHeaderPtrOptimize3DS(CaptureReceiv
return &buffer->cypress_optimize_received_888_3d.columns_data[column].header_sound;
}
static USB3DSOptimizeHeaderSoundData* getAudioHeaderPtrOptimize3DSExtraHeader(CaptureReceived* buffer, bool is_rgb888, bool is_data_3d, uint16_t column) {
if(!is_rgb888) {
if(!is_data_3d)
return &buffer->cypress_optimize_received_565_extra_header.columns_data[column].header_sound;
return &buffer->cypress_optimize_received_565_3d_extra_header.columns_data[column].header_sound;
}
if(!is_data_3d)
return &buffer->cypress_optimize_received_888_extra_header.columns_data[column].header_sound;
return &buffer->cypress_optimize_received_888_3d_extra_header.columns_data[column].header_sound;
}
static inline uint16_t read_sample_indexLE(USB3DSOptimizeSingleSoundData* sample) {
return sample->sample_index % OPTIMIZE_3DS_AUDIO_BUFFER_MAX_SIZE;
}
@ -887,6 +918,12 @@ static void copyAudioOptimize3DSLE(std::int16_t *p_out, uint64_t &n_samples, uin
copyAudioFromSoundDataOptimize3DSLE(p_out, &curr_column_data->samples[0], num_inserted, last_inserted_index);
copyAudioFromSoundDataOptimize3DSLE(p_out, &curr_column_data->samples[1], num_inserted, last_inserted_index);
}
USB3DSOptimizeHeaderSoundData* initial_column_data = getAudioHeaderPtrOptimize3DS(buffer, is_rgb888, is_data_3d, 0);
if(usb_OptimizeHasExtraHeaderSoundData(initial_column_data)) {
USB3DSOptimizeHeaderSoundData* curr_column_data = getAudioHeaderPtrOptimize3DSExtraHeader(buffer, is_rgb888, is_data_3d, TOP_WIDTH_3DS);
copyAudioFromSoundDataOptimize3DSLE(p_out, &curr_column_data->samples[0], num_inserted, last_inserted_index);
copyAudioFromSoundDataOptimize3DSLE(p_out, &curr_column_data->samples[1], num_inserted, last_inserted_index);
}
last_buffer_index = last_inserted_index;
n_samples = num_inserted * 2;
}
@ -899,6 +936,12 @@ static void copyAudioOptimize3DSBE(std::int16_t *p_out, uint64_t &n_samples, uin
copyAudioFromSoundDataOptimize3DSBE(p_out, &curr_column_data->samples[0], num_inserted, last_inserted_index);
copyAudioFromSoundDataOptimize3DSBE(p_out, &curr_column_data->samples[1], num_inserted, last_inserted_index);
}
USB3DSOptimizeHeaderSoundData* initial_column_data = getAudioHeaderPtrOptimize3DS(buffer, is_rgb888, is_data_3d, 0);
if(usb_OptimizeHasExtraHeaderSoundData(initial_column_data)) {
USB3DSOptimizeHeaderSoundData* curr_column_data = getAudioHeaderPtrOptimize3DSExtraHeader(buffer, is_rgb888, is_data_3d, TOP_WIDTH_3DS);
copyAudioFromSoundDataOptimize3DSBE(p_out, &curr_column_data->samples[0], num_inserted, last_inserted_index);
copyAudioFromSoundDataOptimize3DSBE(p_out, &curr_column_data->samples[1], num_inserted, last_inserted_index);
}
last_buffer_index = last_inserted_index;
n_samples = num_inserted * 2;
}