diff --git a/BasiliskII/src/SDL/video_sdl.cpp b/BasiliskII/src/SDL/video_sdl.cpp index d7a46479..395778a0 100644 --- a/BasiliskII/src/SDL/video_sdl.cpp +++ b/BasiliskII/src/SDL/video_sdl.cpp @@ -155,6 +155,11 @@ static SDL_mutex *frame_buffer_lock = NULL; #define LOCK_FRAME_BUFFER SDL_LockMutex(frame_buffer_lock) #define UNLOCK_FRAME_BUFFER SDL_UnlockMutex(frame_buffer_lock) +// Previously set gamma tables +static uint16 last_gamma_red[256]; +static uint16 last_gamma_green[256]; +static uint16 last_gamma_blue[256]; + // Video refresh function static void VideoRefreshInit(void); static void (*video_refresh)(void); @@ -1363,9 +1368,51 @@ void SDL_monitor_desc::set_palette(uint8 *pal, int num_in) { const VIDEO_MODE &mode = get_current_mode(); - // FIXME: how can we handle the gamma ramp? - if ((int)VIDEO_MODE_DEPTH > VIDEO_DEPTH_8BIT) + if ((int)VIDEO_MODE_DEPTH > VIDEO_DEPTH_8BIT) { + // handle the gamma ramp + + if (pal[0] == 127 && pal[num_in*3-1] == 127) // solid grey + return; // ignore + + uint16 red[256]; + uint16 green[256]; + uint16 blue[256]; + + int repeats = 256 / num_in; + + for (int i = 0; i < num_in; i++) { + for (int j = 0; j < repeats; j++) { + red[i*repeats + j] = pal[i*3 + 0] << 8; + green[i*repeats + j] = pal[i*3 + 1] << 8; + blue[i*repeats + j] = pal[i*3 + 2] << 8; + } + } + + // fill remaining entries (if any) with last value + for (int i = num_in * repeats; i < 256; i++) { + red[i] = pal[(num_in - 1) * 3] << 8; + green[i] = pal[(num_in - 1) * 3 + 1] << 8; + blue[i] = pal[(num_in - 1) * 3 + 2] << 8; + } + + bool changed = (memcmp(red, last_gamma_red, 512) != 0 || + memcmp(green, last_gamma_green, 512) != 0 || + memcmp(blue, last_gamma_blue, 512) != 0); + + if (changed) { + int result = SDL_SetGammaRamp(red, green, blue); + + if (result < 0) { + fprintf(stderr, "SDL_SetGammaRamp returned %d, SDL error: %s\n", result, SDL_GetError()); + } + + memcpy(last_gamma_red, red, 512); + memcpy(last_gamma_green, green, 512); + memcpy(last_gamma_blue, blue, 512); + } + return; + } LOCK_PALETTE; diff --git a/BasiliskII/src/SDL/video_sdl2.cpp b/BasiliskII/src/SDL/video_sdl2.cpp index dcd71dc7..22723ed4 100644 --- a/BasiliskII/src/SDL/video_sdl2.cpp +++ b/BasiliskII/src/SDL/video_sdl2.cpp @@ -168,6 +168,11 @@ static SDL_mutex *frame_buffer_lock = NULL; #define LOCK_FRAME_BUFFER SDL_LockMutex(frame_buffer_lock) #define UNLOCK_FRAME_BUFFER SDL_UnlockMutex(frame_buffer_lock) +// Previously set gamma tables +static uint16 last_gamma_red[256]; +static uint16 last_gamma_green[256]; +static uint16 last_gamma_blue[256]; + // Video refresh function static void VideoRefreshInit(void); static void (*video_refresh)(void); @@ -1751,9 +1756,51 @@ void SDL_monitor_desc::set_palette(uint8 *pal, int num_in) { const VIDEO_MODE &mode = get_current_mode(); - // FIXME: how can we handle the gamma ramp? - if ((int)VIDEO_MODE_DEPTH > VIDEO_DEPTH_8BIT) + if ((int)VIDEO_MODE_DEPTH > VIDEO_DEPTH_8BIT) { + // handle the gamma ramp + + if (pal[0] == 127 && pal[num_in*3-1] == 127) // solid grey + return; // ignore + + uint16 red[256]; + uint16 green[256]; + uint16 blue[256]; + + int repeats = 256 / num_in; + + for (int i = 0; i < num_in; i++) { + for (int j = 0; j < repeats; j++) { + red[i*repeats + j] = pal[i*3 + 0] << 8; + green[i*repeats + j] = pal[i*3 + 1] << 8; + blue[i*repeats + j] = pal[i*3 + 2] << 8; + } + } + + // fill remaining entries (if any) with last value + for (int i = num_in * repeats; i < 256; i++) { + red[i] = pal[(num_in - 1) * 3] << 8; + green[i] = pal[(num_in - 1) * 3 + 1] << 8; + blue[i] = pal[(num_in - 1) * 3 + 2] << 8; + } + + bool changed = (memcmp(red, last_gamma_red, 512) != 0 || + memcmp(green, last_gamma_green, 512) != 0 || + memcmp(blue, last_gamma_blue, 512) != 0); + + if (changed && sdl_window) { + int result = SDL_SetWindowGammaRamp(sdl_window, red, green, blue); + + if (result < 0) { + fprintf(stderr, "SDL_SetWindowGammaRamp returned %d, SDL error: %s\n", result, SDL_GetError()); + } + + memcpy(last_gamma_red, red, 512); + memcpy(last_gamma_green, green, 512); + memcpy(last_gamma_blue, blue, 512); + } + return; + } LOCK_PALETTE; diff --git a/SheepShaver/src/video.cpp b/SheepShaver/src/video.cpp index 60ef8c13..dd787008 100644 --- a/SheepShaver/src/video.cpp +++ b/SheepShaver/src/video.cpp @@ -211,6 +211,10 @@ static bool allocate_gamma_table(VidLocals *csSave, uint32 size) return true; } + static inline uint8 max(uint8 a, uint8 b) { + return a > b? a : b; + } + static int16 set_gamma(VidLocals *csSave, uint32 gamma) { if (gamma == 0) { // Build linear ramp, 256 entries @@ -229,8 +233,11 @@ static int16 set_gamma(VidLocals *csSave, uint32 gamma) // Build the linear ramp uint32 p = csSave->gammaTable + gFormulaData; - for (int i=0; i<256; i++) + + for (int i=0; i<256; i++) { WriteMacInt8(p + i, i); + mac_pal[i].red = mac_pal[i].green = mac_pal[i].blue = i; + } } else { // User-supplied gamma table @@ -256,7 +263,41 @@ static int16 set_gamma(VidLocals *csSave, uint32 gamma) // Copy table Mac2Mac_memcpy(csSave->gammaTable, gamma, size); + + // Save new gamma data for video impl + if (data_width != 8) { + // FIXME: handle bit-packed data + } else { + uint32 p = csSave->gammaTable + gFormulaData + gFormulaSize; + + uint32 p_red; + uint32 p_green; + uint32 p_blue; + + // make values increasing as some implementations really don't like it when gamma tables aren't + uint8 max_red = 0; + uint8 max_green = 0; + uint8 max_blue = 0; + + if (chan_cnt == 3) { + p_red = p; + p_green = p + data_cnt; + p_blue = p + data_cnt * 2; + } else { + p_red = p_green = p_blue = p; + } + for (int i=0; i < data_cnt; i++) { + max_red = max(max_red, ReadMacInt8(p_red++)); + max_green = max(max_green, ReadMacInt8(p_green++)); + max_blue = max(max_blue, ReadMacInt8(p_blue++)); + mac_pal[i].red = max_red; + mac_pal[i].green = max_green; + mac_pal[i].blue = max_blue; + } + } } + + video_set_palette(); return noErr; }