void sdl_window_info::update() { osd_ticks_t event_wait_ticks; ASSERT_MAIN_THREAD(); // adjust the cursor state //sdlwindow_update_cursor_state(machine, window); auto wp = std::make_unique<worker_param>(std::static_pointer_cast<sdl_window_info>(shared_from_this())); execute_async(&update_cursor_state_wt, std::move(wp)); // if we're visible and running and not in the middle of a resize, draw if (m_target != nullptr) { int tempwidth, tempheight; // see if the games video mode has changed m_target->compute_minimum_size(tempwidth, tempheight); if (osd_dim(tempwidth, tempheight) != m_minimum_dim) { m_minimum_dim = osd_dim(tempwidth, tempheight); if (!this->m_fullscreen) { //Don't resize window without user interaction; //window_resize(blitwidth, blitheight); } else if (video_config.switchres) { osd_dim tmp = this->pick_best_mode(); resize(tmp.width(), tmp.height()); } } if (video_config.waitvsync && video_config.syncrefresh) event_wait_ticks = osd_ticks_per_second(); // block at most a second else event_wait_ticks = 0; if (m_rendered_event.wait(event_wait_ticks)) { // ensure the target bounds are up-to-date, and then get the primitives render_primitive_list &primlist = *renderer().get_primitives(); // and redraw now auto wp = std::make_unique<worker_param>(std::static_pointer_cast<sdl_window_info>(shared_from_this()), primlist); execute_async(&draw_video_contents_wt, std::move(wp)); } } }
sdl_window_info::sdl_window_info( running_machine &a_machine, int index, std::shared_ptr<osd_monitor_info> a_monitor, const osd_window_config *config) : osd_window_t(*config) , m_next(nullptr) , m_startmaximized(0) // Following three are used by input code to defer resizes , m_minimum_dim(0, 0) , m_windowed_dim(0, 0) , m_rendered_event(0, 1) , m_target(nullptr) , m_extra_flags(0) , m_machine(a_machine) , m_monitor(a_monitor) , m_fullscreen(0) , m_mouse_captured(false) , m_mouse_hidden(false) { m_index = index; //FIXME: these should be per_window in config-> or even better a bit set m_fullscreen = !video_config.windowed; m_prescale = video_config.prescale; m_windowed_dim = osd_dim(config->width, config->height); m_original_mode = global_alloc(SDL_DM_Wrapper); }
bool target_manager::update_target_sizes(uint32_t screen, uint16_t width, uint16_t height, uint32_t style) { if (style == TARGET_STYLE_CUSTOM) return false; std::vector<osd_dim>& sizes = style == TARGET_STYLE_GUEST ? m_guest_dims : m_native_dims; // Ensure that there's an entry to fill while (sizes.size() <= screen) { sizes.push_back(osd_dim(0, 0)); } if (width != sizes[screen].width() || height != sizes[screen].height()) { sizes[screen] = osd_dim(width, height); rebuild_targets(screen, style); return true; } return false; }
osd_dim sdl_window_info::blit_surface_size() { osd_dim window_dim = get_size(); int newwidth, newheight; float xscale = 1, yscale = 1; INT32 target_width = window_dim.width(); INT32 target_height = window_dim.height(); // start with the minimum size m_target->compute_minimum_size(newwidth, newheight); // compute the appropriate visible area if we're trying to keepaspect if (video_config.keepaspect) { // make sure the monitor is up-to-date m_target->compute_visible_area(target_width, target_height, m_monitor->aspect(), m_target->orientation(), target_width, target_height); } // non-integer scaling - often gives more pleasing results in full screen if (!video_config.fullstretch) { // Use SwitchRes scaling float width = newwidth; float height = newheight; switchres_get_scale(m_target, target_width, target_height, width, height, xscale, yscale); newwidth = width; newheight = height; // ensure at least a scale factor of 1 if (xscale <= 0) xscale = 1; if (yscale <= 0) yscale = 1; // apply the final scale newwidth *= xscale; newheight *= yscale; } else { newwidth = target_width; newheight = target_height; } //FIXME: really necessary to distinguish for yuv_modes ? if (m_target->zoom_to_screen() && (video_config.scale_mode == VIDEO_SCALE_MODE_NONE )) newwidth = window_dim.width(); return osd_dim(newwidth, newheight); }
osd_dim sdl_window_info::get_min_bounds(int constrain) { INT32 minwidth, minheight; //assert(GetCurrentThreadId() == window_threadid); // get the minimum target size m_target->compute_minimum_size(minwidth, minheight); // expand to our minimum dimensions if (minwidth < MIN_WINDOW_DIM) minwidth = MIN_WINDOW_DIM; if (minheight < MIN_WINDOW_DIM) minheight = MIN_WINDOW_DIM; // account for extra window stuff minwidth += wnd_extra_width(); minheight += wnd_extra_height(); // if we want it constrained, figure out which one is larger if (constrain) { // first constrain with no height limit osd_rect test1(0,0,minwidth,10000); test1 = constrain_to_aspect_ratio(test1, WMSZ_BOTTOMRIGHT); // then constrain with no width limit osd_rect test2(0,0,10000,minheight); test2 = constrain_to_aspect_ratio(test2, WMSZ_BOTTOMRIGHT); // pick the larger if (test1.width() > test2.width()) { minwidth = test1.width(); minheight = test1.height(); } else { minwidth = test2.width(); minheight = test2.height(); } } // remove extra window stuff minwidth -= wnd_extra_width(); minheight -= wnd_extra_height(); return osd_dim(minwidth, minheight); }
void target_manager::update_screen_count(uint32_t count) { // Ensure that there's an entry to fill while (count > m_native_dims.size()) { m_native_dims.push_back(osd_dim(0, 0)); } if (count != m_screen_count) { uint32_t old_count = m_screen_count; m_screen_count = count; if (m_screen_count > old_count) { for (uint32_t screen = old_count; screen < m_screen_count; screen++) { create_target_if_nonexistent(screen, "output", false, false, TARGET_STYLE_NATIVE); } } } }
osd_dim sdl_window_info::pick_best_mode() { int minimum_width, minimum_height, target_width, target_height; int i; float size_score, best_score = 0.0f; int best_width = 0, best_height = 0; SDL_Rect **modes; // check if we already have a best mode modeline *mode = &this->machine().switchres.best_mode; if (mode->hactive) { ret = osd_dim(mode->type & MODE_ROTATED? mode->vactive : mode->hactive, mode->type & MODE_ROTATED? mode->hactive : mode->vactive); return ret; } // determine the minimum width/height for the selected target m_target->compute_minimum_size(minimum_width, minimum_height); // use those as the target for now target_width = minimum_width * MAX(1, prescale()); target_height = minimum_height * MAX(1, prescale()); // if we're not stretching, allow some slop on the minimum since we can handle it { minimum_width -= 4; minimum_height -= 4; } #if 1 // defined(SDLMAME_WIN32) /* * We need to do this here. If SDL_ListModes is * called in init_monitors, the call will crash * on win32 */ modes = SDL_ListModes(NULL, SDL_FULLSCREEN | SDL_DOUBLEBUF); #else modes = window->m_monitor->modes; #endif if (modes == (SDL_Rect **)0) { osd_printf_error("SDL: No modes available?!\n"); exit(-1); } else if (modes == (SDL_Rect **)-1) // all modes are possible { return osd_dim(m_win_config.width, m_win_config.height); } else { for (i = 0; modes[i]; ++i) { // compute initial score based on difference between target and current size_score = 1.0f / (1.0f + fabsf((INT32)modes[i]->w - target_width) + fabsf((INT32)modes[i]->h - target_height)); // if the mode is too small, give a big penalty if (modes[i]->w < minimum_width || modes[i]->h < minimum_height) size_score *= 0.01f; // if mode is smaller than we'd like, it only scores up to 0.1 if (modes[i]->w < target_width || modes[i]->h < target_height) size_score *= 0.1f; // if we're looking for a particular mode, that's a winner if (modes[i]->w == m_win_config.width && modes[i]->h == m_win_config.height) size_score = 2.0f; osd_printf_verbose("%4dx%4d -> %f\n", (int)modes[i]->w, (int)modes[i]->h, size_score); // best so far? if (size_score > best_score) { best_score = size_score; best_width = modes[i]->w; best_height = modes[i]->h; } } } return osd_dim(best_width, best_height); }
osd_dim sdl_window_info::pick_best_mode() { int minimum_width, minimum_height, target_width, target_height; int i; int num; float size_score, best_score = 0.0f; osd_dim ret(0,0); // check if we already have a best mode modeline *mode = &this->machine().switchres.best_mode; if (mode->hactive) { ret = osd_dim(mode->type & MODE_ROTATED? mode->vactive : mode->hactive, mode->type & MODE_ROTATED? mode->hactive : mode->vactive); return ret; } // determine the minimum width/height for the selected target m_target->compute_minimum_size(minimum_width, minimum_height); // use those as the target for now target_width = minimum_width * MAX(1, prescale()); target_height = minimum_height * MAX(1, prescale()); // if we're not stretching, allow some slop on the minimum since we can handle it { minimum_width -= 4; minimum_height -= 4; } // FIXME: this should be provided by monitor ! num = SDL_GetNumDisplayModes(*((UINT64 *)m_monitor->oshandle())); if (num == 0) { osd_printf_error("SDL: No modes available?!\n"); exit(-1); } else { for (i = 0; i < num; ++i) { SDL_DisplayMode mode; SDL_GetDisplayMode(*((UINT64 *)m_monitor->oshandle()), i, &mode); // compute initial score based on difference between target and current size_score = 1.0f / (1.0f + abs((INT32)mode.w - target_width) + abs((INT32)mode.h - target_height)); // if the mode is too small, give a big penalty if (mode.w < minimum_width || mode.h < minimum_height) size_score *= 0.01f; // if mode is smaller than we'd like, it only scores up to 0.1 if (mode.w < target_width || mode.h < target_height) size_score *= 0.1f; // if we're looking for a particular mode, that's a winner if (mode.w == m_win_config.width && mode.h == m_win_config.height) size_score = 2.0f; // refresh adds some points if (m_win_config.refresh) size_score *= 1.0f / (1.0f + abs(m_win_config.refresh - mode.refresh_rate) / 10.0f); osd_printf_verbose("%4dx%4d@%2d -> %f\n", (int)mode.w, (int)mode.h, (int) mode.refresh_rate, (double) size_score); // best so far? if (size_score > best_score) { best_score = size_score; ret = osd_dim(mode.w, mode.h); } } } return ret; }
void sdl_window_info::update() { osd_ticks_t event_wait_ticks; ASSERT_MAIN_THREAD(); // adjust the cursor state //sdlwindow_update_cursor_state(machine, window); execute_async(&update_cursor_state_wt, worker_param(this)); // if we're visible and running and not in the middle of a resize, draw if (m_target != NULL) { int tempwidth, tempheight; // see if the games video mode has changed m_target->compute_minimum_size(tempwidth, tempheight); if (video_config.switchres && m_fullscreen && machine().options().changeres() && machine().switchres.game.changeres) { switchres_resolution_change(this); return; } else if (osd_dim(tempwidth, tempheight) != m_minimum_dim) { m_minimum_dim = osd_dim(tempwidth, tempheight); if (!this->m_fullscreen) { //Don't resize window without user interaction; //window_resize(blitwidth, blitheight); } else if (video_config.switchres) { osd_dim tmp = this->pick_best_mode(); resize(tmp.width(), tmp.height()); } } int got_lock = false; got_lock = osd_lock_try(m_render_lock); // only render if we were able to get the lock if (got_lock) { // don't hold the lock; we just used it to see if rendering was still happening osd_lock_release(m_render_lock); // ensure the target bounds are up-to-date, and then get the primitives render_primitive_list &primlist = *m_renderer->get_primitives(); // and redraw now osd_event_reset(m_rendered_event); execute_async(&draw_video_contents_wt, worker_param(this, primlist)); if (video_config.waitvsync && machine().video().throttled()) { event_wait_ticks = osd_ticks_per_second(); // block at most a second osd_event_wait(m_rendered_event, event_wait_ticks); } } } }
void sdl_window_info::update() { osd_ticks_t event_wait_ticks; // adjust the cursor state //sdlwindow_update_cursor_state(machine, window); update_cursor_state(); // if we're visible and running and not in the middle of a resize, draw if (m_target != nullptr) { int tempwidth, tempheight; // see if the games video mode has changed m_target->compute_minimum_size(tempwidth, tempheight); if (osd_dim(tempwidth, tempheight) != m_minimum_dim) { m_minimum_dim = osd_dim(tempwidth, tempheight); if (!this->m_fullscreen) { //Don't resize window without user interaction; //window_resize(blitwidth, blitheight); } else if (video_config.switchres) { osd_dim tmp = this->pick_best_mode(); resize(tmp.width(), tmp.height()); } } if (video_config.waitvsync && video_config.syncrefresh) event_wait_ticks = osd_ticks_per_second(); // block at most a second else event_wait_ticks = 0; if (m_rendered_event.wait(event_wait_ticks)) { const int update = 1; // ensure the target bounds are up-to-date, and then get the primitives render_primitive_list &primlist = *renderer().get_primitives(); // and redraw now // Some configurations require events to be polled in the worker thread downcast< sdl_osd_interface& >(machine().osd()).process_events_buf(); // Check whether window has vector screens { const screen_device *screen = screen_device_iterator(machine().root_device()).byindex(m_index); if ((screen != nullptr) && (screen->screen_type() == SCREEN_TYPE_VECTOR)) renderer().set_flags(osd_renderer::FLAG_HAS_VECTOR_SCREEN); else renderer().clear_flags(osd_renderer::FLAG_HAS_VECTOR_SCREEN); } m_primlist = &primlist; // if no bitmap, just fill if (m_primlist == nullptr) { } // otherwise, render with our drawing system else { if( video_config.perftest ) measure_fps(update); else renderer().draw(update); } /* all done, ready for next */ m_rendered_event.set(); } } }
osd_dim sdl_window_info::get_size() { int w=0; int h=0; SDL_GetWindowSize(platform_window(), &w, &h); return osd_dim(w,h); }
int renderer_bgfx::create() { // create renderer osd_dim wdim = window().get_size(); m_width[window().m_index] = wdim.width(); m_height[window().m_index] = wdim.height(); if (window().m_index == 0) { if (!s_window_set) { s_window_set = true; ScreenVertex::init(); } else { bgfx::shutdown(); bgfx::PlatformData blank_pd; memset(&blank_pd, 0, sizeof(bgfx::PlatformData)); bgfx::setPlatformData(blank_pd); } #ifdef OSD_WINDOWS bgfx::winSetHwnd(window().m_hwnd); #else bgfx::sdlSetWindow(window().sdl_window()); #endif bgfx::init(); bgfx::reset(m_width[window().m_index], m_height[window().m_index], video_config.waitvsync ? BGFX_RESET_VSYNC : BGFX_RESET_NONE); // Enable debug text. bgfx::setDebug(BGFX_DEBUG_TEXT); //BGFX_DEBUG_STATS m_dimensions = osd_dim(m_width[0], m_height[0]); } m_textures = new texture_manager(); m_targets = new target_manager(*m_textures); m_shaders = new shader_manager(); m_effects = new effect_manager(*m_shaders); if (window().m_index != 0) { #ifdef OSD_WINDOWS m_framebuffer = m_targets->create_target("backbuffer", window().m_hwnd, m_width[window().m_index], m_height[window().m_index]); #else m_framebuffer = m_targets->create_target("backbuffer", sdlNativeWindowHandle(window().sdl_window()), m_width[window().m_index], m_height[window().m_index]); #endif bgfx::touch(window().m_index); } // Create program from shaders. m_gui_effect[0] = m_effects->effect("gui_opaque"); m_gui_effect[1] = m_effects->effect("gui_blend"); m_gui_effect[2] = m_effects->effect("gui_multiply"); m_gui_effect[3] = m_effects->effect("gui_add"); m_screen_effect[0] = m_effects->effect("screen_opaque"); m_screen_effect[1] = m_effects->effect("screen_blend"); m_screen_effect[2] = m_effects->effect("screen_multiply"); m_screen_effect[3] = m_effects->effect("screen_add"); uint32_t flags = BGFX_TEXTURE_U_CLAMP | BGFX_TEXTURE_V_CLAMP | BGFX_TEXTURE_MIN_POINT | BGFX_TEXTURE_MAG_POINT | BGFX_TEXTURE_MIP_POINT; m_texture_cache = m_textures->create_texture("#cache", bgfx::TextureFormat::RGBA8, CACHE_SIZE, CACHE_SIZE, nullptr, flags); memset(m_white, 0xff, sizeof(uint32_t) * 16 * 16); m_texinfo.push_back(rectangle_packer::packable_rectangle(WHITE_HASH, PRIMFLAG_TEXFORMAT(TEXFORMAT_ARGB32), 16, 16, 16, nullptr, m_white)); return 0; }
osd_dim sdl_window_info::blit_surface_size() { osd_dim window_dim = get_size(); int newwidth, newheight; int xscale = 1, yscale = 1; float desired_aspect = 1.0f; INT32 target_width = window_dim.width(); INT32 target_height = window_dim.height(); // start with the minimum size m_target->compute_minimum_size(newwidth, newheight); // compute the appropriate visible area if we're trying to keepaspect if (video_config.keepaspect) { // make sure the monitor is up-to-date m_target->compute_visible_area(target_width, target_height, m_monitor->aspect(), m_target->orientation(), target_width, target_height); desired_aspect = (float)target_width / (float)target_height; } // non-integer scaling - often gives more pleasing results in full screen if (!video_config.fullstretch) { // compute maximum integral scaling to fit the window xscale = (target_width + 2) / newwidth; yscale = (target_height + 2) / newheight; // try a little harder to keep the aspect ratio if desired if (video_config.keepaspect) { // if we could stretch more in the X direction, and that makes a better fit, bump the xscale while (newwidth * (xscale + 1) <= window_dim.width() && better_mode(newwidth * xscale, newheight * yscale, newwidth * (xscale + 1), newheight * yscale, desired_aspect)) xscale++; // if we could stretch more in the Y direction, and that makes a better fit, bump the yscale while (newheight * (yscale + 1) <= window_dim.height() && better_mode(newwidth * xscale, newheight * yscale, newwidth * xscale, newheight * (yscale + 1), desired_aspect)) yscale++; // now that we've maxed out, see if backing off the maximally stretched one makes a better fit if (window_dim.width() - newwidth * xscale < window_dim.height() - newheight * yscale) { while (better_mode(newwidth * xscale, newheight * yscale, newwidth * (xscale - 1), newheight * yscale, desired_aspect) && (xscale >= 0)) xscale--; } else { while (better_mode(newwidth * xscale, newheight * yscale, newwidth * xscale, newheight * (yscale - 1), desired_aspect) && (yscale >= 0)) yscale--; } } // ensure at least a scale factor of 1 if (xscale <= 0) xscale = 1; if (yscale <= 0) yscale = 1; // apply the final scale newwidth *= xscale; newheight *= yscale; } else { newwidth = target_width; newheight = target_height; } //FIXME: really necessary to distinguish for yuv_modes ? if (m_target->zoom_to_screen() && (video_config.scale_mode == VIDEO_SCALE_MODE_NONE )) newwidth = window_dim.width(); return osd_dim(newwidth, newheight); }