From 3f650ffdaff726959b853680be3715817da5ec9c Mon Sep 17 00:00:00 2001 From: Lorenzooone Date: Sat, 2 Nov 2024 04:39:29 +0100 Subject: [PATCH] Use direct texture conversions to lower cpu usage --- include/capture_structs.hpp | 8 +++-- .../CaptureDeviceSpecific/3dscapture_ftd3.cpp | 2 +- .../ISNitro/usb_is_nitro_acquisition.cpp | 10 ++---- .../usb_ds_3ds_capture.cpp | 33 ++++++++----------- source/WindowScreen.cpp | 19 ++++++++++- 5 files changed, 40 insertions(+), 32 deletions(-) diff --git a/include/capture_structs.hpp b/include/capture_structs.hpp index 4c561b6..cb58bc1 100755 --- a/include/capture_structs.hpp +++ b/include/capture_structs.hpp @@ -19,6 +19,7 @@ #define EXTRA_DATA_BUFFER_FTD3XX_SIZE (1 << 10) enum CaptureConnectionType { CAPTURE_CONN_FTD3, CAPTURE_CONN_USB, CAPTURE_CONN_FTD2, CAPTURE_CONN_IS_NITRO }; +enum InputVideoDataType { VIDEO_DATA_RGB, VIDEO_DATA_BGR, VIDEO_DATA_BGR16 }; enum CaptureScreensType { CAPTURE_SCREENS_BOTH, CAPTURE_SCREENS_TOP, CAPTURE_SCREENS_BOTTOM, CAPTURE_SCREENS_ENUM_END }; enum CaptureSpeedsType { CAPTURE_SPEEDS_FULL, CAPTURE_SPEEDS_HALF, CAPTURE_SPEEDS_THIRD, CAPTURE_SPEEDS_QUARTER, CAPTURE_SPEEDS_ENUM_END }; @@ -103,14 +104,15 @@ union CaptureReceived { }; struct CaptureDevice { - CaptureDevice(std::string serial_number, std::string name, CaptureConnectionType cc_type, const void* descriptor, bool is_3ds, bool has_3d, bool has_audio, int width, int height, int max_samples_in, int base_rotation, int top_screen_x, int top_screen_y, int bot_screen_x, int bot_screen_y) : serial_number(serial_number), name(name), cc_type(cc_type), descriptor(descriptor), is_3ds(is_3ds), has_3d(has_3d), has_audio(has_audio), width(width), height(height), max_samples_in(max_samples_in), base_rotation(base_rotation), top_screen_x(top_screen_x), top_screen_y(top_screen_y), bot_screen_x(bot_screen_x), bot_screen_y(bot_screen_y), path("") {} - CaptureDevice(std::string serial_number, std::string name, std::string path, CaptureConnectionType cc_type, const void* descriptor, bool is_3ds, bool has_3d, bool has_audio, int width, int height, int max_samples_in, int base_rotation, int top_screen_x, int top_screen_y, int bot_screen_x, int bot_screen_y) : serial_number(serial_number), name(name), cc_type(cc_type), descriptor(descriptor), is_3ds(is_3ds), has_3d(has_3d), has_audio(has_audio), width(width), height(height), max_samples_in(max_samples_in), base_rotation(base_rotation), top_screen_x(top_screen_x), top_screen_y(top_screen_y), bot_screen_x(bot_screen_x), bot_screen_y(bot_screen_y), path(path) {} - CaptureDevice(): serial_number(""), name(""), cc_type(CAPTURE_CONN_USB), descriptor(NULL), is_3ds(false), has_3d(false), has_audio(false), width(0), height(0), max_samples_in(0), base_rotation(0), top_screen_x(0), top_screen_y(0), bot_screen_x(0), bot_screen_y(0), path("") {} + CaptureDevice(std::string serial_number, std::string name, CaptureConnectionType cc_type, const void* descriptor, bool is_3ds, bool has_3d, bool has_audio, int width, int height, int max_samples_in, int base_rotation, int top_screen_x, int top_screen_y, int bot_screen_x, int bot_screen_y, InputVideoDataType video_data_type) : serial_number(serial_number), name(name), cc_type(cc_type), descriptor(descriptor), is_3ds(is_3ds), has_3d(has_3d), has_audio(has_audio), width(width), height(height), max_samples_in(max_samples_in), base_rotation(base_rotation), top_screen_x(top_screen_x), top_screen_y(top_screen_y), bot_screen_x(bot_screen_x), bot_screen_y(bot_screen_y), path(""), video_data_type(video_data_type) {} + CaptureDevice(std::string serial_number, std::string name, std::string path, CaptureConnectionType cc_type, const void* descriptor, bool is_3ds, bool has_3d, bool has_audio, int width, int height, int max_samples_in, int base_rotation, int top_screen_x, int top_screen_y, int bot_screen_x, int bot_screen_y, InputVideoDataType video_data_type) : serial_number(serial_number), name(name), cc_type(cc_type), descriptor(descriptor), is_3ds(is_3ds), has_3d(has_3d), has_audio(has_audio), width(width), height(height), max_samples_in(max_samples_in), base_rotation(base_rotation), top_screen_x(top_screen_x), top_screen_y(top_screen_y), bot_screen_x(bot_screen_x), bot_screen_y(bot_screen_y), path(path), video_data_type(video_data_type) {} + CaptureDevice(): serial_number(""), name(""), cc_type(CAPTURE_CONN_USB), descriptor(NULL), is_3ds(false), has_3d(false), has_audio(false), width(0), height(0), max_samples_in(0), base_rotation(0), top_screen_x(0), top_screen_y(0), bot_screen_x(0), bot_screen_y(0), path(""), video_data_type(VIDEO_DATA_RGB) {} std::string serial_number; std::string name; std::string path; CaptureConnectionType cc_type; + InputVideoDataType video_data_type; const void* descriptor; bool is_3ds; bool has_3d; diff --git a/source/CaptureDeviceSpecific/3dscapture_ftd3.cpp b/source/CaptureDeviceSpecific/3dscapture_ftd3.cpp index 097ceb0..8fc481f 100644 --- a/source/CaptureDeviceSpecific/3dscapture_ftd3.cpp +++ b/source/CaptureDeviceSpecific/3dscapture_ftd3.cpp @@ -107,7 +107,7 @@ void list_devices_ftd3(std::vector &devices_list, std::vector& devices_list, is_nitro_device_handlers* handlers, const is_nitro_usb_device* usb_device_desc, int& curr_serial_extra_id_is_nitro, std::string path) { - devices_list.emplace_back(get_serial(usb_device_desc, handlers, curr_serial_extra_id_is_nitro), usb_device_desc->name, path, CAPTURE_CONN_IS_NITRO, (void*)usb_device_desc, false, false, false, WIDTH_DS, HEIGHT_DS + HEIGHT_DS, 0, 0, 0, 0, 0, HEIGHT_DS); + devices_list.emplace_back(get_serial(usb_device_desc, handlers, curr_serial_extra_id_is_nitro), usb_device_desc->name, path, CAPTURE_CONN_IS_NITRO, (void*)usb_device_desc, false, false, false, WIDTH_DS, HEIGHT_DS + HEIGHT_DS, 0, 0, 0, 0, 0, HEIGHT_DS, VIDEO_DATA_BGR); } void is_nitro_insert_device(std::vector& devices_list, is_nitro_device_handlers* handlers, const is_nitro_usb_device* usb_device_desc, int& curr_serial_extra_id_is_nitro) { - devices_list.emplace_back(get_serial(usb_device_desc, handlers, curr_serial_extra_id_is_nitro), usb_device_desc->name, CAPTURE_CONN_IS_NITRO, (void*)usb_device_desc, false, false, false, WIDTH_DS, HEIGHT_DS + HEIGHT_DS, 0, 0, 0, 0, 0, HEIGHT_DS); + devices_list.emplace_back(get_serial(usb_device_desc, handlers, curr_serial_extra_id_is_nitro), usb_device_desc->name, CAPTURE_CONN_IS_NITRO, (void*)usb_device_desc, false, false, false, WIDTH_DS, HEIGHT_DS + HEIGHT_DS, 0, 0, 0, 0, 0, HEIGHT_DS, VIDEO_DATA_BGR); } static is_nitro_device_handlers* usb_find_by_serial_number(const is_nitro_usb_device* usb_device_desc, CaptureDevice* device) { @@ -222,11 +222,7 @@ void usb_is_nitro_convertVideoToOutput(CaptureReceived *p_in, VideoOutputData *p } if((capture_type == CAPTURE_SCREENS_BOTTOM) || (capture_type == CAPTURE_SCREENS_TOP)) memset(p_out->screen_data[out_clear_pos], 0, num_pixels * 3); - for(int i = 0; i < num_pixels; i++) { - p_out->screen_data[i + out_start_pos][0] = p_in->is_nitro_capture_received.video_in.screen_data[i][2]; - p_out->screen_data[i + out_start_pos][1] = p_in->is_nitro_capture_received.video_in.screen_data[i][1]; - p_out->screen_data[i + out_start_pos][2] = p_in->is_nitro_capture_received.video_in.screen_data[i][0]; - } + memcpy(p_out->screen_data[out_start_pos], p_in->is_nitro_capture_received.video_in.screen_data, num_pixels * 3); } bool is_nitro_is_capture(CaptureDevice* device) { diff --git a/source/CaptureDeviceSpecific/usb_ds_3ds_capture.cpp b/source/CaptureDeviceSpecific/usb_ds_3ds_capture.cpp index 0d57c45..ce1be22 100644 --- a/source/CaptureDeviceSpecific/usb_ds_3ds_capture.cpp +++ b/source/CaptureDeviceSpecific/usb_ds_3ds_capture.cpp @@ -150,9 +150,9 @@ static int insert_device(std::vector &devices_list, const usb_dev return result; std::string serial_str = get_serial(handle, usb_descriptor, curr_serial_extra_id); if(usb_device_desc->is_3ds) - devices_list.emplace_back(serial_str, "3DS", CAPTURE_CONN_USB, (void*)usb_device_desc, true, capture_get_has_3d(handle, usb_device_desc), true, HEIGHT_3DS, TOP_WIDTH_3DS + BOT_WIDTH_3DS, O3DS_SAMPLES_IN, 90, 0, 0, TOP_WIDTH_3DS, 0); + devices_list.emplace_back(serial_str, "3DS", CAPTURE_CONN_USB, (void*)usb_device_desc, true, capture_get_has_3d(handle, usb_device_desc), true, HEIGHT_3DS, TOP_WIDTH_3DS + BOT_WIDTH_3DS, O3DS_SAMPLES_IN, 90, 0, 0, TOP_WIDTH_3DS, 0, VIDEO_DATA_RGB); else - devices_list.emplace_back(serial_str, "DS", CAPTURE_CONN_USB, (void*)usb_device_desc, false, false, false, WIDTH_DS, HEIGHT_DS + HEIGHT_DS, 0, 0, 0, 0, 0, HEIGHT_DS); + devices_list.emplace_back(serial_str, "DS", CAPTURE_CONN_USB, (void*)usb_device_desc, false, false, false, WIDTH_DS, HEIGHT_DS + HEIGHT_DS, 0, 0, 0, 0, 0, HEIGHT_DS, VIDEO_DATA_BGR16); libusb_close(handle); return result; } @@ -264,37 +264,28 @@ static usb_capture_status capture_read_oldds_3ds(libusb_device_handle *handle, c return USB_CAPTURE_SUCCESS; } -static inline uint8_t xbits_to_8bits(uint8_t value, int num_bits) { - int left_shift = 8 - num_bits; - int right_shift = num_bits - left_shift; - return (value << left_shift) | (value >> right_shift); -} - -static inline void usb_oldDSconvertVideoToOutputRGBA(USBOldDSPixelData data, uint8_t* target) { - target[0] = xbits_to_8bits(data.r, OLD_DS_PIXEL_R_BITS); - target[1] = xbits_to_8bits(data.g, OLD_DS_PIXEL_G_BITS); - target[2] = xbits_to_8bits(data.b, OLD_DS_PIXEL_B_BITS); -} - static inline void usb_oldDSconvertVideoToOutputHalfLine(USBOldDSCaptureReceived *p_in, VideoOutputData *p_out, int input_halfline, int output_halfline) { //de-interleave pixels + uint16_t* out_ptr_top = (uint16_t*)p_out->screen_data; + uint16_t* out_ptr_bottom = out_ptr_top + (WIDTH_DS * HEIGHT_DS); + uint16_t* in_ptr = (uint16_t*)&p_in; for(int i = 0; i < WIDTH_DS / 2 ; i++) { uint32_t input_halfline_pixel = (input_halfline * (WIDTH_DS / 2)) + i; uint32_t output_halfline_pixel = (output_halfline * (WIDTH_DS / 2)) + i; - usb_oldDSconvertVideoToOutputRGBA(p_in->video_in.screen_data[input_halfline_pixel * 2], p_out->screen_data[output_halfline_pixel + (WIDTH_DS * HEIGHT_DS)]); - usb_oldDSconvertVideoToOutputRGBA(p_in->video_in.screen_data[(input_halfline_pixel * 2) + 1], p_out->screen_data[output_halfline_pixel]); + out_ptr_top[output_halfline_pixel] = in_ptr[input_halfline_pixel * 2]; + out_ptr_bottom[output_halfline_pixel] = in_ptr[(input_halfline_pixel * 2) + 1]; } } static void usb_oldDSconvertVideoToOutput(USBOldDSCaptureReceived *p_in, VideoOutputData *p_out) { #ifndef SIMPLE_DS_FRAME_SKIP if(!p_in->frameinfo.valid) { //LCD was off - memset(p_out->screen_data, 0, WIDTH_DS * (2 * HEIGHT_DS) * 3); + memset(p_out->screen_data, 0, WIDTH_DS * (2 * HEIGHT_DS) * sizeof(uint16_t)); return; } // Handle first line being off, if needed - memset(p_out->screen_data, 0, WIDTH_DS * 3); + memset(p_out->screen_data, 0, WIDTH_DS * sizeof(uint16_t)); int input_halfline = 0; for(int i = 0; i < 2; i++) { @@ -306,8 +297,10 @@ static void usb_oldDSconvertVideoToOutput(USBOldDSCaptureReceived *p_in, VideoOu if(p_in->frameinfo.half_line_flags[(i >> 3)] & (1 << (i & 7))) usb_oldDSconvertVideoToOutputHalfLine(p_in, p_out, input_halfline++, i); else { // deal with missing half-line - memcpy(p_out->screen_data[i * (WIDTH_DS / 2)], p_out->screen_data[(i - 2) * (WIDTH_DS / 2)], (WIDTH_DS / 2) * 3); - memcpy(p_out->screen_data[(i * (WIDTH_DS / 2)) + (WIDTH_DS * HEIGHT_DS)], p_out->screen_data[((i - 2) * (WIDTH_DS / 2)) + (WIDTH_DS * HEIGHT_DS)], (WIDTH_DS / 2) * 3); + uint16_t* out_ptr_top = (uint16_t*)&p_out->screen_data; + uint16_t* out_ptr_bottom = out_ptr_top + (WIDTH_DS * HEIGHT_DS); + memcpy(&out_ptr_top[i * (WIDTH_DS / 2)], &out_ptr_top[(i - 2) * (WIDTH_DS / 2)], (WIDTH_DS / 2) * sizeof(uint16_t)); + memcpy(&out_ptr_bottom[i * (WIDTH_DS / 2)], &out_ptr_bottom[(i - 2) * (WIDTH_DS / 2)], (WIDTH_DS / 2) * sizeof(uint16_t)); } } #else diff --git a/source/WindowScreen.cpp b/source/WindowScreen.cpp index e0f65f2..c88f460 100755 --- a/source/WindowScreen.cpp +++ b/source/WindowScreen.cpp @@ -432,13 +432,30 @@ std::string WindowScreen::title_factory() { return title; } +// These values may be undefined under Windows... +#ifndef GL_BGR +#define GL_BGR 0x80e0 +#endif + +#ifndef GL_UNSIGNED_SHORT_5_6_5_REV +#define GL_UNSIGNED_SHORT_5_6_5_REV 0x8364 +#endif + void WindowScreen::update_texture() { unsigned int m_texture = this->in_tex.getNativeHandle(); if (this->saved_buf && m_texture) { // Copy pixels from the given array to the texture glBindTexture(GL_TEXTURE_2D, m_texture); - glTexSubImage2D(GL_TEXTURE_2D, 0, static_cast(0), static_cast(0), static_cast(this->capture_status->device.width), static_cast(this->capture_status->device.height), GL_RGB, GL_UNSIGNED_BYTE, this->saved_buf); + GLenum format = GL_RGB; + GLenum type = GL_UNSIGNED_BYTE; + if(this->capture_status->device.video_data_type == VIDEO_DATA_BGR) + format = GL_BGR; + if(this->capture_status->device.video_data_type == VIDEO_DATA_BGR16) { + format = GL_RGB; + type = GL_UNSIGNED_SHORT_5_6_5_REV; + } + glTexSubImage2D(GL_TEXTURE_2D, 0, static_cast(0), static_cast(0), static_cast(this->capture_status->device.width), static_cast(this->capture_status->device.height), format, type, this->saved_buf); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); // Force an OpenGL flush, so that the texture data will appear updated