From aec8741cb44b4065249de7c15ebe38b4c86cb16c Mon Sep 17 00:00:00 2001 From: Lorenzooone Date: Thu, 10 Apr 2025 04:47:28 +0200 Subject: [PATCH] Add support for Optimize DS mode --- include/capture_structs.hpp | 38 ++- .../cypress_optimize_3ds_acquisition.cpp | 274 ++++++++++++------ source/conversions.cpp | 43 +++ 3 files changed, 260 insertions(+), 95 deletions(-) diff --git a/include/capture_structs.hpp b/include/capture_structs.hpp index c962358..d986b60 100755 --- a/include/capture_structs.hpp +++ b/include/capture_structs.hpp @@ -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 { diff --git a/source/CaptureDeviceSpecific/Optimize_3DS/cypress_optimize_3ds_acquisition.cpp b/source/CaptureDeviceSpecific/Optimize_3DS/cypress_optimize_3ds_acquisition.cpp index 18436bb..cdb7875 100644 --- a/source/CaptureDeviceSpecific/Optimize_3DS/cypress_optimize_3ds_acquisition.cpp +++ b/source/CaptureDeviceSpecific/Optimize_3DS/cypress_optimize_3ds_acquisition.cpp @@ -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,34 +247,62 @@ 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; - 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; + 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; - cypress_device_capture_recv_data_real->is_buffer_free_shared_mutex->specific_unlock(cypress_device_capture_recv_data_real->cb_data.internal_index); + 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) - return i * 2; - } + 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* 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 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; - *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; - } + 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); } - 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; diff --git a/source/conversions.cpp b/source/conversions.cpp index e864f58..1b0c458 100755 --- a/source/conversions.cpp +++ b/source/conversions.cpp @@ -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; }