From 6433b8f68997bda3a0aa150cd29b980d1697659f Mon Sep 17 00:00:00 2001 From: BearOso Date: Mon, 6 Jun 2022 17:52:04 -0500 Subject: [PATCH] Gtk: Clean up and modernize a bit. --- filter/hq2x.cpp | 6 +- filter/hq2x.h | 6 +- gtk/CMakeLists.txt | 2 + gtk/src/filter_epx_unsafe.cpp | 14 +- gtk/src/filter_epx_unsafe.h | 4 +- gtk/src/filter_xbrz.cpp | 6 +- gtk/src/filter_xbrz.h | 6 +- gtk/src/gtk_display.cpp | 920 ++++++-------------------- gtk/src/gtk_display.h | 33 +- gtk/src/gtk_display_driver_gtk.cpp | 2 +- gtk/src/gtk_display_driver_opengl.cpp | 1 - gtk/src/gtk_display_driver_xv.cpp | 23 +- gtk/src/threadpool.cpp | 85 +++ gtk/src/threadpool.h | 29 + 14 files changed, 344 insertions(+), 793 deletions(-) create mode 100644 gtk/src/threadpool.cpp create mode 100644 gtk/src/threadpool.h diff --git a/filter/hq2x.cpp b/filter/hq2x.cpp index bbe5072f..ff363f48 100644 --- a/filter/hq2x.cpp +++ b/filter/hq2x.cpp @@ -392,7 +392,7 @@ static inline bool Diff (int c1, int c2) return (false); } -void HQ2X_16 (uint8 *srcPtr, uint32 srcPitch, uint8 *dstPtr, uint32 dstPitch, int width, int height) +void HQ2X_16 (uint8 *srcPtr, int srcPitch, uint8 *dstPtr, int dstPitch, int width, int height) { int w1, w2, w3, w4, w5, w6, w7, w8, w9; uint32 src1line = srcPitch >> 1; @@ -3091,7 +3091,7 @@ void HQ2X_16 (uint8 *srcPtr, uint32 srcPitch, uint8 *dstPtr, uint32 dstPitch, in } } -void HQ3X_16 (uint8 *srcPtr, uint32 srcPitch, uint8 *dstPtr, uint32 dstPitch, int width, int height) +void HQ3X_16 (uint8 *srcPtr, int srcPitch, uint8 *dstPtr, int dstPitch, int width, int height) { int w1, w2, w3, w4, w5, w6, w7, w8, w9; uint32 src1line = srcPitch >> 1; @@ -6763,7 +6763,7 @@ void HQ3X_16 (uint8 *srcPtr, uint32 srcPitch, uint8 *dstPtr, uint32 dstPitch, in } } -void HQ4X_16 (uint8 *srcPtr, uint32 srcPitch, uint8 *dstPtr, uint32 dstPitch, int width, int height) +void HQ4X_16 (uint8 *srcPtr, int srcPitch, uint8 *dstPtr, int dstPitch, int width, int height) { int w1, w2, w3, w4, w5, w6, w7, w8, w9; uint32 src1line = srcPitch >> 1; diff --git a/filter/hq2x.h b/filter/hq2x.h index ad9b08a6..f7561d8a 100644 --- a/filter/hq2x.h +++ b/filter/hq2x.h @@ -9,8 +9,8 @@ bool8 S9xBlitHQ2xFilterInit (void); void S9xBlitHQ2xFilterDeinit (void); -void HQ2X_16 (uint8 *, uint32, uint8 *, uint32, int, int); -void HQ3X_16 (uint8 *, uint32, uint8 *, uint32, int, int); -void HQ4X_16 (uint8 *, uint32, uint8 *, uint32, int, int); +void HQ2X_16 (uint8 *, int, uint8 *, int, int, int); +void HQ3X_16 (uint8 *, int, uint8 *, int, int, int); +void HQ4X_16 (uint8 *, int, uint8 *, int, int, int); #endif diff --git a/gtk/CMakeLists.txt b/gtk/CMakeLists.txt index 6d1bcf18..f8386501 100644 --- a/gtk/CMakeLists.txt +++ b/gtk/CMakeLists.txt @@ -192,6 +192,8 @@ list(APPEND SOURCES src/gtk_display_driver_gtk.h src/gtk_display_driver.h src/gtk_display.h + src/threadpool.cpp + src/threadpool.h src/gtk_file.cpp src/gtk_file.h src/gtk_builder_window.cpp diff --git a/gtk/src/filter_epx_unsafe.cpp b/gtk/src/filter_epx_unsafe.cpp index 5140666a..76c38bac 100644 --- a/gtk/src/filter_epx_unsafe.cpp +++ b/gtk/src/filter_epx_unsafe.cpp @@ -23,11 +23,11 @@ #define AVERAGE_565(el0, el1) (((el0) & (el1)) + ((((el0) ^ (el1)) & 0xF7DE) >> 1)) /* Allows vertical overlap. We need this to avoid seams when threading */ -void EPX_16_unsafe (uint8 *srcPtr, - uint32 srcPitch, - uint8 *dstPtr, - uint32 dstPitch, - int width, +void EPX_16_unsafe (uint8 *srcPtr, + int srcPitch, + uint8 *dstPtr, + int dstPitch, + int width, int height) { uint16 colorX, colorA, colorB, colorC, colorD; @@ -120,9 +120,9 @@ void EPX_16_unsafe (uint8 *srcPtr, /* Blends with edge pixel instead of just using it directly. */ void EPX_16_smooth_unsafe (uint8 *srcPtr, - uint32 srcPitch, + int srcPitch, uint8 *dstPtr, - uint32 dstPitch, + int dstPitch, int width, int height) { diff --git a/gtk/src/filter_epx_unsafe.h b/gtk/src/filter_epx_unsafe.h index f8ce032d..6ce545c9 100644 --- a/gtk/src/filter_epx_unsafe.h +++ b/gtk/src/filter_epx_unsafe.h @@ -7,7 +7,7 @@ #ifndef __FILTER_EPX_UNSAFE_H #define __FILTER_EPX_UNSAFE_H -void EPX_16_unsafe (uint8 *, uint32, uint8 *, uint32, int, int); -void EPX_16_smooth_unsafe (uint8 *, uint32, uint8 *, uint32, int, int); +void EPX_16_unsafe (uint8 *, int, uint8 *, int, int, int); +void EPX_16_smooth_unsafe (uint8 *, int, uint8 *, int, int, int); #endif /* __FILTER_EPX_UNSAFE_H */ diff --git a/gtk/src/filter_xbrz.cpp b/gtk/src/filter_xbrz.cpp index 235b12a7..4f99a94a 100644 --- a/gtk/src/filter_xbrz.cpp +++ b/gtk/src/filter_xbrz.cpp @@ -103,17 +103,17 @@ void xBRZ(uint8 *srcPtr, uint32 srcPitch, uint8 *dstPtr, uint32 dstPitch, int wi } } -void filter_2xBRZ(uint8 *srcPtr, uint32 srcPitch, uint8 *dstPtr, uint32 dstPitch, int width, int height) +void filter_2xBRZ(uint8 *srcPtr, int srcPitch, uint8 *dstPtr, int dstPitch, int width, int height) { xBRZ(srcPtr, srcPitch, dstPtr, dstPitch, width, height, 2); } -void filter_3xBRZ(uint8 *srcPtr, uint32 srcPitch, uint8 *dstPtr, uint32 dstPitch, int width, int height) +void filter_3xBRZ(uint8 *srcPtr, int srcPitch, uint8 *dstPtr, int dstPitch, int width, int height) { xBRZ(srcPtr, srcPitch, dstPtr, dstPitch, width, height, 3); } -void filter_4xBRZ(uint8 *srcPtr, uint32 srcPitch, uint8 *dstPtr, uint32 dstPitch, int width, int height) +void filter_4xBRZ(uint8 *srcPtr, int srcPitch, uint8 *dstPtr, int dstPitch, int width, int height) { xBRZ(srcPtr, srcPitch, dstPtr, dstPitch, width, height, 4); } diff --git a/gtk/src/filter_xbrz.h b/gtk/src/filter_xbrz.h index 3e48467b..d9542985 100644 --- a/gtk/src/filter_xbrz.h +++ b/gtk/src/filter_xbrz.h @@ -7,8 +7,8 @@ #ifndef _filter_xbrz_h_ #define _filter_xbrz_h_ -void filter_2xBRZ (uint8 *, uint32, uint8 *, uint32, int, int); -void filter_3xBRZ (uint8 *, uint32, uint8 *, uint32, int, int); -void filter_4xBRZ (uint8 *, uint32, uint8 *, uint32, int, int); +void filter_2xBRZ (uint8 *, int, uint8 *, int, int, int); +void filter_3xBRZ (uint8 *, int, uint8 *, int, int, int); +void filter_4xBRZ (uint8 *, int, uint8 *, int, int, int); #endif diff --git a/gtk/src/gtk_display.cpp b/gtk/src/gtk_display.cpp index bfb73371..78ebb345 100644 --- a/gtk/src/gtk_display.cpp +++ b/gtk/src/gtk_display.cpp @@ -5,7 +5,7 @@ \*****************************************************************************/ #include "gtk_compat.h" -#include +#include "threadpool.h" #include "gtk_s9x.h" #include "gtk_display.h" @@ -25,14 +25,43 @@ #include "gtk_display_driver_opengl.h" +void filter_scanlines(uint8 *, int, uint8 *, int, int, int); +void filter_2x(uint8 *, int, uint8 *, int, int, int); +void filter_3x(uint8 *, int, uint8 *, int, int, int); +void filter_4x(uint8 *, int, uint8 *, int, int, int); + +static struct +{ + int index; + void (*filter_func)(uint8 *, int, uint8 *, int, int, int); + int xscale; + int yscale; +} filter_data[NUM_FILTERS] = { + { FILTER_NONE, nullptr, 1, 1 }, + { FILTER_SUPEREAGLE, SuperEagle, 2, 2 }, + { FILTER_2XSAI, _2xSaI, 2, 2 }, + { FILTER_SUPER2XSAI, Super2xSaI, 2, 2 }, + { FILTER_EPX, EPX_16_unsafe, 2, 2 }, + { FILTER_EPX_SMOOTH, EPX_16_smooth_unsafe, 2, 2 }, + { FILTER_NTSC, nullptr, 1, 1 }, + { FILTER_SCANLINES, filter_scanlines, 1, 2 }, + { FILTER_SIMPLE2X, filter_2x, 2, 2 }, + { FILTER_SIMPLE3X, filter_3x, 3, 3 }, + { FILTER_SIMPLE4X, filter_4x, 4, 4 }, + { FILTER_HQ2X, HQ2X_16, 2, 2 }, + { FILTER_HQ3X, HQ3X_16, 3, 3 }, + { FILTER_HQ4X, HQ4X_16, 4, 4 }, + { FILTER_2XBRZ, filter_2xBRZ, 2, 2 }, + { FILTER_3XBRZ, filter_3xBRZ, 3, 3 }, + { FILTER_4XBRZ, filter_4xBRZ, 4, 4 }, +}; + static S9xDisplayDriver *driver; static snes_ntsc_t snes_ntsc; static int burst_phase = 0; -static thread_job_t job[8]; -static GThreadPool *pool; static uint8 *y_table, *u_table, *v_table; -static int endianess = ENDIAN_NORMAL; static std::vector scaled_image; +static std::unique_ptr pool; /* Scanline constants for the NTSC filter */ static const unsigned int scanline_offsets[] = { @@ -59,28 +88,26 @@ static const uint8 scanline_shifts[] = { 0 }; -void S9xSetEndianess(int type) -{ - endianess = type; -} - double S9xGetAspect() { double native_aspect = 256.0 / (gui_config->overscan ? 239.0 : 224.0); double aspect; - switch (gui_config->aspect_ratio / 2) + switch (gui_config->aspect_ratio) { case 0: /* Square pixels */ + case 1: aspect = native_aspect; break; - case 1: /* 4:3 */ + case 2: /* 4:3 */ + case 3: aspect = native_aspect * 7 / 6; break; - case 2: - default: /* Correct */ + case 4: /* NTSC 64:49 */ + case 5: + default: aspect = native_aspect * 8 / 7; break; } @@ -178,49 +205,28 @@ static void internal_convert_16_yuv(void *src_buffer, int src_pitch, int dst_pitch, int width, - int height) + int height, + int bpp) { int x, y; uint16 *src; uint8 *dst; uint16 p0, p1; - if (endianess == ENDIAN_SWAPPED) + for (y = 0; y < height; y++) { - for (y = 0; y < height; y++) + src = (uint16 *)(((uint8 *)src_buffer) + src_pitch * y); + dst = (uint8 *)(((uint8 *)dst_buffer) + dst_pitch * y); + + for (x = 0; x < width / 2; x++) { - src = (uint16 *)(((uint8 *)src_buffer) + src_pitch * y); - dst = (uint8 *)(((uint8 *)dst_buffer) + dst_pitch * y); + p0 = *src++; + p1 = *src++; - for (x = 0; x < width / 2; x++) - { - p0 = *src++; - p1 = *src++; - - *dst++ = (v_table[p0] + v_table[p1]) >> 1; - *dst++ = y_table[p1]; - *dst++ = (u_table[p0] + u_table[p1]) >> 1; - *dst++ = y_table[p0]; - } - } - } - else - { - for (y = 0; y < height; y++) - { - src = (uint16 *)(((uint8 *)src_buffer) + src_pitch * y); - dst = (uint8 *)(((uint8 *)dst_buffer) + dst_pitch * y); - - for (x = 0; x < width / 2; x++) - { - p0 = *src++; - p1 = *src++; - - *dst++ = y_table[p0]; - *dst++ = (u_table[p0] + u_table[p1]) >> 1; - *dst++ = y_table[p1]; - *dst++ = (v_table[p0] + v_table[p1]) >> 1; - } + *dst++ = y_table[p0]; + *dst++ = (u_table[p0] + u_table[p1]) >> 1; + *dst++ = y_table[p1]; + *dst++ = (v_table[p0] + v_table[p1]) >> 1; } } } @@ -236,167 +242,38 @@ static void internal_convert_mask(void *src_buffer, unsigned int inv_bshift, unsigned int bpp) { -#ifdef __BIG_ENDIAN__ - if (endianess == ENDIAN_SWAPPED) -#else - if (endianess == ENDIAN_NORMAL) -#endif + switch (bpp) { - switch (bpp) + case 15: + case 16: + for (int y = 0; y < height; y++) { - case 15: - case 16: - for (int y = 0; y < height; y++) + uint16 *data = (uint16 *)((uint8 *)dst_buffer + y * dst_pitch); + uint16 *snes = (uint16 *)(((uint8 *)src_buffer) + y * src_pitch); + + for (int x = 0; x < width; x++) { - uint16 *data = (uint16 *)((uint8 *)dst_buffer + y * dst_pitch); - uint16 *snes = (uint16 *)(((uint8 *)src_buffer) + y * src_pitch); + uint32 pixel = *snes++; - for (int x = 0; x < width; x++) - { - uint32 pixel = *snes++; - - *data++ = ((pixel & 0xf800) << 0) >> inv_rshift | ((pixel & 0x07e0) << 5) >> inv_gshift | ((pixel & 0x001f) << 11) >> inv_bshift; - } + *data++ = ((pixel & 0xf800) << 0) >> inv_rshift | ((pixel & 0x07e0) << 5) >> inv_gshift | ((pixel & 0x001f) << 11) >> inv_bshift; } - break; - - case 24: -#ifdef __BIG_ENDIAN__ - if (inv_rshift > 8) -#else - if (!(inv_rshift > 8)) -#endif - { - for (int y = 0; y < height; y++) - { - uint8 *data = (uint8 *)dst_buffer + y * dst_pitch; - uint16 *snes = (uint16 *)(((uint8 *)src_buffer) + y * src_pitch); - - for (int x = 0; x < width; x++) - { - uint32 pixel = *snes++; - *data++ = ((pixel & 0x001f) << 3); - *data++ = ((pixel & 0x07e0) >> 3); - *data++ = ((pixel & 0xf800) >> 8); - } - } - } - else - { - for (int y = 0; y < height; y++) - { - uint8 *data = (uint8 *)dst_buffer + y * dst_pitch; - - uint16 *snes = (uint16 *)(((uint8 *)src_buffer) + y * src_pitch); - - for (int x = 0; x < width; x++) - { - uint32 pixel = *snes++; - *data++ = ((pixel & 0xf800) >> 8); - *data++ = ((pixel & 0x07e0) >> 3); - *data++ = ((pixel & 0x001f) << 3); - } - } - } - break; - - case 32: - for (int y = 0; y < height; y++) - { - uint32 *data = (uint32 *)((uint8 *)dst_buffer + y * dst_pitch); - uint16 *snes = (uint16 *)(((uint8 *)src_buffer) + y * src_pitch); - - for (int x = 0; x < width; x++) - { - uint32 pixel = *snes++; - - *data++ = ((uint32)(pixel & 0xf800) << 16) >> inv_rshift | ((uint32)(pixel & 0x07e0) << 21) >> inv_gshift | ((uint32)(pixel & 0x001f) << 27) >> inv_bshift; - } - } - break; } - } + break; - else /* Byte-order is inverted from native */ - { - switch (bpp) + case 32: + for (int y = 0; y < height; y++) { - case 15: - case 16: - for (int y = 0; y < height; y++) + uint32 *data = (uint32 *)((uint8 *)dst_buffer + y * dst_pitch); + uint16 *snes = (uint16 *)(((uint8 *)src_buffer) + y * src_pitch); + + for (int x = 0; x < width; x++) { - uint16 *data = (uint16 *)((uint8 *)dst_buffer + y * dst_pitch); - uint16 *snes = (uint16 *)(((uint8 *)src_buffer) + y * src_pitch); + uint32 pixel = *snes++; - for (int x = 0; x < width; x++) - { - uint32 pixel = *snes++; - uint16 value; - - value = ((pixel & 0xf800) << 0) >> inv_rshift | ((pixel & 0x07e0) << 5) >> inv_gshift | ((pixel & 0x001f) << 11) >> inv_bshift; - - *data++ = ((value & 0xff) << 8) | ((value & 0xff00) >> 8); - } + *data++ = ((uint32)(pixel & 0xf800) << 16) >> inv_rshift | ((uint32)(pixel & 0x07e0) << 21) >> inv_gshift | ((uint32)(pixel & 0x001f) << 27) >> inv_bshift; } - break; - - case 24: -#ifdef __BIG_ENDIAN__ - if (inv_rshift > 8) -#else - if (!(inv_rshift > 8)) -#endif - { - for (int y = 0; y < height; y++) - { - uint8 *data = (uint8 *)dst_buffer + y * dst_pitch; - uint16 *snes = (uint16 *)(((uint8 *)src_buffer) + y * src_pitch); - - for (int x = 0; x < width; x++) - { - uint32 pixel = *snes++; - *data++ = ((pixel & 0xf800) >> 8); - *data++ = ((pixel & 0x07e0) >> 3); - *data++ = ((pixel & 0x001f) << 3); - } - } - } - else - { - for (int y = 0; y < height; y++) - { - uint8 *data = (uint8 *)dst_buffer + y * dst_pitch; - uint16 *snes = (uint16 *)(((uint8 *)src_buffer) + y * src_pitch); - - for (int x = 0; x < width; x++) - { - uint32 pixel = *snes++; - *data++ = ((pixel & 0x001f) << 3); - *data++ = ((pixel & 0x07e0) >> 3); - *data++ = ((pixel & 0xf800) >> 8); - } - } - } - break; - - case 32: - for (int y = 0; y < height; y++) - { - uint32 *data = (uint32 *)((uint8 *)dst_buffer + y * dst_pitch); - uint16 *snes = (uint16 *)(((uint8 *)src_buffer) + y * src_pitch); - - for (int x = 0; x < width; x++) - { - uint32 pixel = *snes++; - uint32 value; - - value = ((uint32)(pixel & 0xf800) << 16) >> inv_rshift | ((uint32)(pixel & 0x07e0) << 21) >> inv_gshift | ((uint32)(pixel & 0x001f) << 27) >> inv_bshift; - - *data++ = ((value & 0x000000ff) << 24) | ((value & 0x0000ff00) << 8) | ((value & 0x00ff0000) >> 8) | ((value & 0xff000000) >> 24); - } - } - break; } + break; } } @@ -408,124 +285,32 @@ static void internal_convert(void *src_buffer, int height, int bpp) { - if (endianess == ENDIAN_SWAPPED) + + if (bpp == 32) { - if (bpp == 24) + /* Format in fourcc is xxxxxxxx rrrrrrrr gggggggg bbbbbbbb */ + for (int y = 0; y < height; y++) { - for (int y = 0; y < height; y++) + uint8 *data = (uint8 *)dst_buffer + y * dst_pitch; + + uint16 *snes = (uint16 *)(((uint8 *)src_buffer) + y * src_pitch); + + for (int x = 0; x < width; x++) { - uint8 *data = (uint8 *)dst_buffer + y * dst_pitch; + uint16 pixel = *snes++; - uint16 *snes = (uint16 *)(((uint8 *)src_buffer) + y * src_pitch); - - for (int x = 0; x < width; x++) - { - uint16 pixel = *snes++; - *data++ = ((pixel & 0xf800) >> 8) | ((pixel >> 13) & 0x07); /* Red */ - *data++ = ((pixel & 0x07e0) >> 3) | ((pixel >> 9) & 0x03); /* Green */ - *data++ = ((pixel & 0x001f) << 3) | ((pixel >> 2) & 0x07); /* Blue */ - } - } - } - - else if (bpp == 32) - { - /* Format in fourcc is xxxxxxxx rrrrrrrr gggggggg bbbbbbbb */ - for (int y = 0; y < height; y++) - { - uint8 *data = (uint8 *)dst_buffer + y * dst_pitch; - - uint16 *snes = (uint16 *)(((uint8 *)src_buffer) + y * src_pitch); - - for (int x = 0; x < width; x++) - { - uint16 pixel = *snes++; - *data++ = 0xff; /* Null */ - *data++ = ((pixel & 0xf800) >> 8) | ((pixel >> 13) & 0x07); /* Red */ - *data++ = ((pixel & 0x07e0) >> 3) | ((pixel >> 9) & 0x03); /* Green */ - *data++ = ((pixel & 0x001f) << 3) | ((pixel >> 2) & 0x07); /* Blue */ - } - } - } - } - - else /* Least significant byte first :-P */ - { - if (bpp == 24) - { - /* Format in fourcc is rrrrrrrr gggggggg bbbbbbbb */ - /* Format in fourcc is xxxxxxxx rrrrrrrr gggggggg bbbbbbbb */ - for (int y = 0; y < height; y++) - { - uint8 *data = (uint8 *)dst_buffer + y * dst_pitch; - - uint16 *snes = (uint16 *)(((uint8 *)src_buffer) + y * src_pitch); - - for (int x = 0; x < width; x++) - { - uint16 pixel = *snes++; - - *data++ = ((pixel & 0x001f) << 3) | ((pixel >> 2) & 0x07); /* Blue */ - *data++ = ((pixel & 0x07e0) >> 3) | ((pixel >> 9) & 0x03); /* Green */ - *data++ = ((pixel & 0xf800) >> 8) | ((pixel >> 13) & 0x07); /* Red */ - } - } - } - - else if (bpp == 32) - { - /* Format in fourcc is xxxxxxxx rrrrrrrr gggggggg bbbbbbbb */ - for (int y = 0; y < height; y++) - { - uint8 *data = (uint8 *)dst_buffer + y * dst_pitch; - - uint16 *snes = (uint16 *)(((uint8 *)src_buffer) + y * src_pitch); - - for (int x = 0; x < width; x++) - { - uint16 pixel = *snes++; - - *data++ = ((pixel & 0x001f) << 3) | ((pixel >> 2) & 0x07); /* Blue */ - *data++ = ((pixel & 0x07e0) >> 3) | ((pixel >> 9) & 0x03); /* Green */ - *data++ = ((pixel & 0xf800) >> 8) | ((pixel >> 13) & 0x07); /* Red */ - *data++ = 0xff; /* Null */ - } + *data++ = ((pixel & 0x001f) << 3) | ((pixel >> 2) & 0x07); /* Blue */ + *data++ = ((pixel & 0x07e0) >> 3) | ((pixel >> 9) & 0x03); /* Green */ + *data++ = ((pixel & 0xf800) >> 8) | ((pixel >> 13) & 0x07); /* Red */ + *data++ = 0xff; /* Null */ } } } } -static void S9xForceHires(void *buffer, - int pitch, - int &width, - int &height) +static void S9xForceHires(void *buffer, int pitch, int &width, int &height) { - int double_width = 0, - double_height = 0; - if (width <= 256) - double_width++; - - /*if (height <= 224) - double_height++; */ - - if (double_width && double_height) - { - for (int y = (height * 2) - 1; y >= 0; y--) - { - uint16 *src_line = (uint16 *)((uint8 *)buffer + (y >> 1) * pitch); - uint16 *dst_line = (uint16 *)((uint8 *)buffer + y * pitch); - - for (int x = (width * 2) - 1; x >= 0; x--) - { - *(dst_line + x) = *(src_line + (x >> 1)); - } - } - - width *= 2; - height *= 2; - } - else if (double_width && !double_height) { for (int y = (height)-1; y >= 0; y--) { @@ -539,18 +324,6 @@ static void S9xForceHires(void *buffer, width *= 2; } - else if (!double_width && double_height) - { - for (int y = (height * 2) - 1; y >= 0; y--) - { - uint16 *src_line = (uint16 *)((uint8 *)buffer + (y >> 1) * pitch); - uint16 *dst_line = (uint16 *)((uint8 *)buffer + y * pitch); - - memcpy(dst_line, src_line, width * 2); - } - - height *= 2; - } } static inline uint16 average_565(uint16 colora, uint16 colorb) @@ -558,15 +331,10 @@ static inline uint16 average_565(uint16 colora, uint16 colorb) return (((colora) & (colorb)) + ((((colora) ^ (colorb)) & 0xF7DE) >> 1)); } -static void S9xMergeHires(void *buffer, - int pitch, - int &width, - int &height) +static void S9xMergeHires(void *buffer, int pitch, int &width, int &height) { if (width < 512) - { return; - } for (int y = 0; y < height; y++) { @@ -583,21 +351,19 @@ static void S9xMergeHires(void *buffer, width >>= 1; } -void filter_2x(void *src, +void filter_2x(uint8 *src, int src_pitch, - void *dst, + uint8 *dst, int dst_pitch, int width, int height) { - int x, y; - - for (y = 0; y < height; y++) + for (int y = 0; y < height; y++) { uint16 *in = (uint16 *)((uint8 *)src + y * src_pitch); uint16 *out = (uint16 *)((uint8 *)dst + (y * 2) * dst_pitch); - for (x = 0; x < width; x++) + for (int x = 0; x < width; x++) { uint16 pixel = *in++; @@ -611,21 +377,19 @@ void filter_2x(void *src, } } -void filter_3x(void *src, +void filter_3x(uint8 *src, int src_pitch, - void *dst, + uint8 *dst, int dst_pitch, int width, int height) { - int x, y, z; - - for (y = 0; y < height; y++) + for (int y = 0; y < height; y++) { uint16 *in = (uint16 *)((uint8 *)src + y * src_pitch); uint16 *out = (uint16 *)((uint8 *)dst + (y * 3) * dst_pitch); - for (x = 0; x < width; x++) + for (int x = 0; x < width; x++) { uint16 pixel = *in++; @@ -634,30 +398,28 @@ void filter_3x(void *src, *out++ = pixel; } - for (z = 1; z <= 2; z++) + for (int line = 1; line <= 2; line++) { - memcpy((uint8 *)dst + ((y * 3) + z) * dst_pitch, + memcpy((uint8 *)dst + ((y * 3) + line) * dst_pitch, (uint8 *)dst + ((y * 3)) * dst_pitch, width * 2 * 3); } } } -void filter_4x(void *src, +void filter_4x(uint8 *src, int src_pitch, - void *dst, + uint8 *dst, int dst_pitch, int width, int height) { - int x, y, z; - - for (y = 0; y < height; y++) + for (int y = 0; y < height; y++) { uint16 *in = (uint16 *)((uint8 *)src + y * src_pitch); uint16 *out = (uint16 *)((uint8 *)dst + (y * 4) * dst_pitch); - for (x = 0; x < width; x++) + for (int x = 0; x < width; x++) { uint16 pixel = *in++; @@ -667,35 +429,32 @@ void filter_4x(void *src, *out++ = pixel; } - for (z = 1; z <= 3; z++) + for (int line = 1; line <= 3; line++) { - memcpy((uint8 *)dst + ((y * 4) + z) * dst_pitch, + memcpy((uint8 *)dst + ((y * 4) + line) * dst_pitch, (uint8 *)dst + (y * 4) * dst_pitch, width * 2 * 4); } } } -void filter_scanlines(void *src_buffer, +void filter_scanlines(uint8 *src_buffer, int src_pitch, - void *dst_buffer, + uint8 *dst_buffer, int dst_pitch, int width, int height) { - int x, y; - uint16 *src, *dst_a, *dst_b; - uint8 shift = scanline_shifts[gui_config->scanline_filter_intensity]; uint16 mask = scanline_masks[gui_config->scanline_filter_intensity + 1]; - src = (uint16 *)src_buffer; - dst_a = (uint16 *)dst_buffer; - dst_b = ((uint16 *)dst_buffer) + (dst_pitch >> 1); + uint16 *src = (uint16 *)src_buffer; + uint16 *dst_a = (uint16 *)dst_buffer; + uint16 *dst_b = ((uint16 *)dst_buffer) + (dst_pitch >> 1); - for (y = 0; y < height; y++) + for (int y = 0; y < height; y++) { - for (x = 0; x < width; x++) + for (int x = 0; x < width; x++) { dst_a[x] = src[x]; dst_b[x] = (src[x] - (src[x] >> shift & mask)); @@ -707,229 +466,35 @@ void filter_scanlines(void *src_buffer, } } -void get_filter_scale(int &width, int &height) +void apply_filter_scale(int &width, int &height) { - switch (gui_config->scale_method) + if (gui_config->scale_method == FILTER_NTSC) { - case FILTER_SUPEREAGLE: - width *= 2; + width = SNES_NTSC_OUT_WIDTH(width); height *= 2; - break; - - case FILTER_2XSAI: - width *= 2; - height *= 2; - break; - - case FILTER_SUPER2XSAI: - width *= 2; - height *= 2; - break; - -#ifdef USE_HQ2X - case FILTER_HQ4X: - width *= 4; - height *= 4; - break; - case FILTER_HQ3X: - width *= 3; - height *= 3; - break; - case FILTER_HQ2X: - width *= 2; - height *= 2; - break; -#endif /* USE_HQ2X */ - -#ifdef USE_XBRZ - case FILTER_4XBRZ: - width *= 4; - height *= 4; - break; - case FILTER_3XBRZ: - width *= 3; - height *= 3; - break; - case FILTER_2XBRZ: - width *= 2; - height *= 2; - break; -#endif /* USE_XBRZ */ - - case FILTER_SIMPLE4X: - width *= 4; - height *= 4; - break; - case FILTER_SIMPLE3X: - width *= 3; - height *= 3; - break; - case FILTER_SIMPLE2X: - width *= 2; - height *= 2; - break; - - case FILTER_EPX: - width *= 2; - height *= 2; - break; - - case FILTER_NTSC: - if (width > 256) - width = SNES_NTSC_OUT_WIDTH(width / 2); - else - width = SNES_NTSC_OUT_WIDTH(width); - height *= 2; - break; - - case FILTER_SCANLINES: - height *= 2; - break; - - case FILTER_EPX_SMOOTH: - width *= 2; - height *= 2; - break; + return; } + + const auto &filter = filter_data[gui_config->scale_method]; + width *= filter.xscale; + height *= filter.yscale; + return; } static void internal_filter(uint8 *src_buffer, int src_pitch, uint8 *dst_buffer, int dst_pitch, - int &width, - int &height) + int width, + int height) { - switch (gui_config->scale_method) + if (gui_config->scale_method == FILTER_NONE) { - case FILTER_SUPEREAGLE: - SuperEagle(src_buffer, - src_pitch, - dst_buffer, - dst_pitch, - width, - height); - break; + return; + } - case FILTER_2XSAI: - _2xSaI(src_buffer, - src_pitch, - dst_buffer, - dst_pitch, - width, - height); - break; - - case FILTER_SUPER2XSAI: - Super2xSaI(src_buffer, - src_pitch, - dst_buffer, - dst_pitch, - width, - height); - break; - -#ifdef USE_HQ2X - case FILTER_HQ4X: - HQ4X_16(src_buffer, - src_pitch, - dst_buffer, - dst_pitch, - width, - height); - break; - case FILTER_HQ3X: - HQ3X_16(src_buffer, - src_pitch, - dst_buffer, - dst_pitch, - width, - height); - break; - case FILTER_HQ2X: - HQ2X_16(src_buffer, - src_pitch, - dst_buffer, - dst_pitch, - width, - height); - break; -#endif /* USE_HQ2X */ - -#ifdef USE_XBRZ - case FILTER_4XBRZ: - filter_4xBRZ(src_buffer, - src_pitch, - dst_buffer, - dst_pitch, - width, - height); - break; - case FILTER_3XBRZ: - filter_3xBRZ(src_buffer, - src_pitch, - dst_buffer, - dst_pitch, - width, - height); - break; - case FILTER_2XBRZ: - filter_2xBRZ(src_buffer, - src_pitch, - dst_buffer, - dst_pitch, - width, - height); - break; -#endif /* USE_XBRZ */ - - case FILTER_SIMPLE4X: - filter_4x(src_buffer, - src_pitch, - dst_buffer, - dst_pitch, - width, - height); - break; - case FILTER_SIMPLE3X: - - filter_3x(src_buffer, - src_pitch, - dst_buffer, - dst_pitch, - width, - height); - break; - case FILTER_SIMPLE2X: - filter_2x(src_buffer, - src_pitch, - dst_buffer, - dst_pitch, - width, - height); - break; - - case FILTER_EPX: - EPX_16_unsafe(src_buffer, - src_pitch, - dst_buffer, - dst_pitch, - width, - height); - break; - - case FILTER_EPX_SMOOTH: - - EPX_16_smooth_unsafe(src_buffer, - src_pitch, - dst_buffer, - dst_pitch, - width, - height); - - break; - - case FILTER_NTSC: + if (gui_config->scale_method == FILTER_NTSC) + { if (width > 256) snes_ntsc_blit_hires_scanlines(&snes_ntsc, (SNES_NTSC_IN_T *)src_buffer, @@ -948,103 +513,28 @@ static void internal_filter(uint8 *src_buffer, height, (void *)dst_buffer, dst_pitch); - break; - - case FILTER_SCANLINES: - filter_scanlines(src_buffer, - src_pitch, - dst_buffer, - dst_pitch, - width, - height); - break; } - - get_filter_scale(width, height); -} - -static void thread_worker(gpointer data, - gpointer user_data) -{ - thread_job_t *job = ((thread_job_t *)data); - - switch (job->operation_type) + else { - case JOB_FILTER: - internal_filter(job->src_buffer, - job->src_pitch, - job->dst_buffer, - job->dst_pitch, - job->width, - job->height); - break; - - case JOB_CONVERT: - internal_convert(job->src_buffer, - job->dst_buffer, - job->src_pitch, - job->dst_pitch, - job->width, - job->height, - job->bpp); - break; - - case JOB_CONVERT_YUV: - internal_convert_16_yuv(job->src_buffer, - job->dst_buffer, - job->src_pitch, - job->dst_pitch, - job->width, - job->height); - break; - - case JOB_CONVERT_MASK: - internal_convert_mask(job->src_buffer, - job->dst_buffer, - job->src_pitch, - job->dst_pitch, - job->width, - job->height, - job->inv_rmask, - job->inv_bmask, - job->inv_gmask, - job->bpp); - break; + filter_data[gui_config->scale_method].filter_func(src_buffer, + src_pitch, + dst_buffer, + dst_pitch, + width, + height); } - - job->complete = true; } -static void -create_thread_pool() +static void create_thread_pool() { - if (pool == NULL) + if (!pool) { - pool = g_thread_pool_new(thread_worker, - NULL, - gui_config->num_threads - 1, - true, - NULL); + pool = std::make_unique(); + pool->start(gui_config->num_threads); } } -static void wait_for_jobs_to_complete() -{ - while (1) - { - int complete = 1; - for (int i = 0; i < gui_config->num_threads; i++) - complete = complete && job[i].complete; - - if (complete) - break; - - sched_yield(); - } -} - -static void -internal_threaded_convert(void *src_buffer, +static void internal_threaded_convert(void *src_buffer, void *dst_buffer, int src_pitch, int dst_pitch, @@ -1054,27 +544,26 @@ internal_threaded_convert(void *src_buffer, { create_thread_pool(); + auto func = (bpp == -1) ? internal_convert_16_yuv : internal_convert; + int coverage = 0; + for (int i = 0; i < gui_config->num_threads; i++) { - job[i].operation_type = (bpp == -1 ? JOB_CONVERT_YUV : JOB_CONVERT); - job[i].src_buffer = - ((uint8 *)src_buffer) + (src_pitch * i * (height / gui_config->num_threads)); - job[i].src_pitch = src_pitch; - job[i].dst_buffer = - ((uint8 *)dst_buffer) + (dst_pitch * i * (height / gui_config->num_threads)); - job[i].dst_pitch = dst_pitch; - job[i].width = width; - job[i].height = height / gui_config->num_threads; - job[i].bpp = bpp; - job[i].complete = false; + int job_height = (height / gui_config->num_threads) & 3; + job_height = height - coverage; - if (i == gui_config->num_threads - 1) - job[i].height = height - ((gui_config->num_threads - 1) * (height / gui_config->num_threads)); - - g_thread_pool_push(pool, (gpointer) & (job[i]), NULL); + pool->queue([=] { + func((uint8 *)src_buffer + (src_pitch * coverage), + (uint8 *)dst_buffer + (dst_pitch * coverage), + src_pitch, + dst_pitch, + width, + job_height, + bpp); + }); } - wait_for_jobs_to_complete(); + pool->wait_idle(); } static void internal_threaded_convert_mask(void *src_buffer, @@ -1090,69 +579,61 @@ static void internal_threaded_convert_mask(void *src_buffer, { create_thread_pool(); + int lines_handled = 0; + int job_height = height / gui_config->num_threads; + for (int i = 0; i < gui_config->num_threads; i++) { - job[i].operation_type = (bpp == -1 ? JOB_CONVERT_YUV : JOB_CONVERT); - job[i].src_buffer = - ((uint8 *)src_buffer) + (src_pitch * i * (height / gui_config->num_threads)); - job[i].src_pitch = src_pitch; - job[i].dst_buffer = - ((uint8 *)dst_buffer) + (dst_pitch * i * (height / gui_config->num_threads)); - job[i].dst_pitch = dst_pitch; - job[i].width = width; - job[i].height = height / gui_config->num_threads; - job[i].bpp = bpp; - job[i].inv_rmask = inv_rmask; - job[i].inv_gmask = inv_gmask; - job[i].inv_bmask = inv_bmask; - job[i].complete = false; - if (i == gui_config->num_threads - 1) - job[i].height = height - ((gui_config->num_threads - 1) * (height / gui_config->num_threads)); - - g_thread_pool_push(pool, (gpointer) & (job[i]), NULL); + job_height = height - lines_handled; + pool->queue([=] { + internal_convert_mask((uint8 *)src_buffer + (src_pitch * lines_handled), + (uint8 *)dst_buffer + (dst_pitch * lines_handled), + src_pitch, + dst_pitch, + width, + job_height, + inv_rmask, + inv_gmask, + inv_bmask, + bpp); + }); } - wait_for_jobs_to_complete(); + pool->wait_idle(); } static void internal_threaded_filter(uint8 *src_buffer, int src_pitch, uint8 *dst_buffer, int dst_pitch, - int &width, - int &height) + int width, + int height) { - int dst_width = width, dst_height = height; - /* If the threadpool doesn't exist, create it */ create_thread_pool(); - get_filter_scale(dst_width, dst_height); - - int yscale = dst_height / height; + int yscale = filter_data[gui_config->scale_method].yscale; int coverage = 0; for (int i = 0; i < gui_config->num_threads; i++) { - job[i].operation_type = JOB_FILTER; - job[i].complete = false; - job[i].width = width; - job[i].src_pitch = src_pitch; - job[i].dst_pitch = dst_pitch; - job[i].src_buffer = src_buffer + (src_pitch * coverage); - job[i].dst_buffer = dst_buffer + (dst_pitch * coverage * yscale); - job[i].height = (height / gui_config->num_threads) & ~3; /* Cut to multiple of 4 */ + int job_height = height / gui_config->num_threads & ~3; if (i == gui_config->num_threads - 1) - job[i].height = height - coverage; - coverage += job[i].height; + job_height = height - coverage; - g_thread_pool_push(pool, (gpointer) & (job[i]), NULL); + pool->queue([=] { + internal_filter(src_buffer + (src_pitch * coverage), + src_pitch, + dst_buffer + (dst_pitch * coverage * yscale), + dst_pitch, + width, + job_height); + }); + coverage += job_height; } - wait_for_jobs_to_complete(); - - get_filter_scale(width, height); + pool->wait_idle(); } void S9xFilter(uint8 *src_buffer, @@ -1177,6 +658,8 @@ void S9xFilter(uint8 *src_buffer, dst_pitch, width, height); + + apply_filter_scale(width, height); } void S9xConvertYUV(void *src_buffer, @@ -1200,7 +683,8 @@ void S9xConvertYUV(void *src_buffer, src_pitch, dst_pitch, width, - height); + height, + -1); } void S9xConvert(void *src, @@ -1283,7 +767,8 @@ void S9xDisplayReconfigure() if (pool) { - g_thread_pool_set_max_threads(pool, gui_config->num_threads - 1, NULL); + pool->stop(); + pool = nullptr; } } @@ -1321,7 +806,7 @@ bool8 S9xDeinitUpdate(int width, int height) if (top_level->last_height > height) { - memset(GFX.Screen + (GFX.Pitch >> 1) * height, + memset(GFX.Screen + GFX.RealPPL * height, 0, GFX.Pitch * (top_level->last_height - height)); } @@ -1356,19 +841,19 @@ bool8 S9xDeinitUpdate(int width, int height) } } - uint16_t *screen_view = GFX.Screen + yoffset * 512; + uint16_t *screen_view = GFX.Screen + yoffset * GFX.RealPPL; if (!Settings.Paused && !NetPlay.Paused) { if (gui_config->hires_effect == HIRES_SCALE) { - S9xForceHires(screen_view, 512 * 2, width, height); + S9xForceHires(screen_view, GFX.Pitch, width, height); top_level->last_width = width; } else if (gui_config->hires_effect == HIRES_MERGE) { - S9xMergeHires(screen_view, 512 * 2, width, height); + S9xMergeHires(screen_view, GFX.Pitch, width, height); top_level->last_width = width; } } @@ -1378,20 +863,20 @@ bool8 S9xDeinitUpdate(int width, int height) int scaled_width = width; int scaled_height = height; - get_filter_scale(scaled_width, scaled_height); + apply_filter_scale(scaled_width, scaled_height); if ((int)scaled_image.size() < (scaled_width * scaled_height * 2)) { scaled_image.resize(scaled_width * scaled_height * 2); } - S9xFilter((uint8_t *)screen_view, 512 * 2, &scaled_image[0], scaled_width * 2, width, height); + S9xFilter((uint8_t *)screen_view, GFX.Pitch, &scaled_image[0], scaled_width * 2, width, height); driver->update((uint16_t *)&scaled_image[0], width, height, scaled_width); return true; } - driver->update(screen_view, width, height, 512); + driver->update(screen_view, width, height, GFX.RealPPL); return true; } @@ -1453,7 +938,10 @@ void S9xDeinitDisplay() delete driver; if (pool) - g_thread_pool_free(pool, false, true); + { + pool->stop(); + pool = nullptr; + } } void S9xReinitDisplay() diff --git a/gtk/src/gtk_display.h b/gtk/src/gtk_display.h index 6607b526..4a70feb7 100644 --- a/gtk/src/gtk_display.h +++ b/gtk/src/gtk_display.h @@ -47,36 +47,6 @@ enum { NTSC_RGB = 2 }; -enum { - ENDIAN_NORMAL = 0, - ENDIAN_SWAPPED = 1 -}; - -enum { - JOB_FILTER = 0, - JOB_CONVERT = 1, - JOB_SCALE_AND_CONVERT = 2, - JOB_CONVERT_YUV = 3, - JOB_CONVERT_MASK = 4 -}; - -typedef struct thread_job_t -{ - int operation_type; - uint8 *src_buffer; - int src_pitch; - uint8 *dst_buffer; - int dst_pitch; - int width; - int height; - int bpp; - int inv_rmask; - int inv_gmask; - int inv_bmask; - - volatile bool complete; -} thread_job_t; - struct S9xRect { int x; @@ -86,7 +56,6 @@ struct S9xRect }; void S9xRegisterYUVTables(uint8 *y, uint8 *u, uint8 *v); -void S9xSetEndianess(int type); double S9xGetAspect(); S9xRect S9xApplyAspect(int, int, int, int); void S9xConvertYUV(void *src_buffer, @@ -118,7 +87,7 @@ void S9xFilter(uint8 *src_buffer, int dst_pitch, int &width, int &height); -void get_filter_scale(int &width, int &height); +void apply_filter_scale(int &width, int &height); void S9xDisplayRefresh(int width, int height); void S9xReinitDisplay(); void S9xDisplayReconfigure(); diff --git a/gtk/src/gtk_display_driver_gtk.cpp b/gtk/src/gtk_display_driver_gtk.cpp index e7206b17..48b42ca1 100644 --- a/gtk/src/gtk_display_driver_gtk.cpp +++ b/gtk/src/gtk_display_driver_gtk.cpp @@ -107,7 +107,7 @@ void S9xGTKDisplayDriver::clear() S9xRect dst; dst.w = window->last_width; dst.h = window->last_height; - get_filter_scale(dst.w, dst.h); + apply_filter_scale(dst.w, dst.h); dst = S9xApplyAspect(dst.w, dst.h, width, height); if (dst.x > 0) diff --git a/gtk/src/gtk_display_driver_opengl.cpp b/gtk/src/gtk_display_driver_opengl.cpp index 6f0e7115..31276536 100644 --- a/gtk/src/gtk_display_driver_opengl.cpp +++ b/gtk/src/gtk_display_driver_opengl.cpp @@ -161,7 +161,6 @@ void S9xOpenGLDisplayDriver::update(uint16_t *buffer, int width, int height, int pbo_memory = glMapBuffer(GL_PIXEL_UNPACK_BUFFER, GL_WRITE_ONLY); /* Pixel swizzling in software */ - S9xSetEndianess(ENDIAN_NORMAL); S9xConvert(buffer, pbo_memory, stride_in_pixels * 2, width * 4, width, height, 32); glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER); diff --git a/gtk/src/gtk_display_driver_xv.cpp b/gtk/src/gtk_display_driver_xv.cpp index 674811e8..784b3131 100644 --- a/gtk/src/gtk_display_driver_xv.cpp +++ b/gtk/src/gtk_display_driver_xv.cpp @@ -294,12 +294,6 @@ int S9xXVDisplayDriver::init() this->rshift = this->bshift; this->bshift = copy; } - - /* on big-endian Xv still seems to like LSB order */ - if (config->force_inverted_byte_order) - S9xSetEndianess(ENDIAN_SWAPPED); - else - S9xSetEndianess(ENDIAN_NORMAL); } } } @@ -313,21 +307,6 @@ int S9xXVDisplayDriver::init() format = formats[i].id; depth = formats[i].depth; - if (formats[i].byte_order == LSBFirst) - { - if (config->force_inverted_byte_order) - S9xSetEndianess(ENDIAN_SWAPPED); - else - S9xSetEndianess(ENDIAN_NORMAL); - } - else - { - if (config->force_inverted_byte_order) - S9xSetEndianess(ENDIAN_NORMAL); - else - S9xSetEndianess(ENDIAN_SWAPPED); - } - break; } } @@ -454,7 +433,7 @@ void S9xXVDisplayDriver::clear() S9xRect dst; dst.w = window->last_width; dst.h = window->last_height; - get_filter_scale(dst.w, dst.h); + apply_filter_scale(dst.w, dst.h); dst = S9xApplyAspect(dst.w, dst.h, width, height); if (dst.x > 0) diff --git a/gtk/src/threadpool.cpp b/gtk/src/threadpool.cpp new file mode 100644 index 00000000..bd6754b7 --- /dev/null +++ b/gtk/src/threadpool.cpp @@ -0,0 +1,85 @@ +#include "threadpool.h" +#include + +void threadpool::thread_func() +{ + while (1) + { + std::unique_lock lock(mutex); + cond.wait_for(lock, std::chrono::microseconds(100), [this] { + return (die || !jobs.empty()); + }); + + if (die) + return; + + if (jobs.empty()) + continue; + + auto job = std::move(jobs.front()); + jobs.pop(); + lock.unlock(); + + job(); + } +} + +void threadpool::start(int num_threads) +{ + die = false; + + while (!jobs.empty()) + jobs.pop(); + + threads.resize(num_threads); + + for (int i = 0; i < num_threads; i++) + threads.at(i) = std::thread(&threadpool::thread_func, this); + + started = true; +} + +void threadpool::wait_idle() +{ + while (!futures.empty()) + { + futures.front().wait(); + std::unique_lock lock(mutex); + futures.pop(); + } +} + +void threadpool::stop() +{ + if (!started) + return; + + std::unique_lock lock(mutex); + die = true; + lock.unlock(); + + cond.notify_all(); + for (auto &t : threads) + t.join(); + threads.clear(); + + while (!jobs.empty()) + jobs.pop(); + + started = false; +} + +void threadpool::queue(std::function func) +{ + std::unique_lock lock(mutex); + + std::packaged_task job(func); + + futures.push(job.get_future().share()); + jobs.push(std::move(job)); + + lock.unlock(); + + cond.notify_all(); + return; +} \ No newline at end of file diff --git a/gtk/src/threadpool.h b/gtk/src/threadpool.h new file mode 100644 index 00000000..65bf40ab --- /dev/null +++ b/gtk/src/threadpool.h @@ -0,0 +1,29 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include + +class threadpool +{ +public: + void start(int num_threads); + void stop(); + void queue(std::function func); + void wait_idle(); + +private: + void thread_func(); + + std::vector threads; + std::queue> jobs; + std::queue> futures; + std::mutex mutex; + std::condition_variable cond; + bool die = false; + bool started = false; +}; \ No newline at end of file