Example #1
0
static bool d3d_construct(d3d_video_t *d3d,
      const video_info_t *info, const input_driver_t **input,
      void **input_data)
{
   gfx_ctx_input_t inp;
   unsigned full_x, full_y;
   settings_t    *settings     = config_get_ptr();

   d3d->should_resize = false;

#if defined(HAVE_MENU)
   d3d->menu                = new overlay_t();

   if (!d3d->menu)
      return false;

   d3d->menu->tex_coords[0]  = 0;
   d3d->menu->tex_coords[1]  = 0;
   d3d->menu->tex_coords[2]  = 1;
   d3d->menu->tex_coords[3]  = 1;
   d3d->menu->vert_coords[0] = 0;
   d3d->menu->vert_coords[1] = 1;
   d3d->menu->vert_coords[2] = 1;
   d3d->menu->vert_coords[3] = -1;
#endif

   memset(&d3d->windowClass, 0, sizeof(d3d->windowClass));
#ifdef HAVE_WINDOW
   d3d->windowClass.lpfnWndProc = WndProcD3D;
   win32_window_init(&d3d->windowClass, true, NULL);
#endif

#ifdef HAVE_MONITOR
   bool windowed_full;
   RECT mon_rect;
   MONITORINFOEX current_mon;
   HMONITOR hm_to_use;

   win32_monitor_info(&current_mon, &hm_to_use, &d3d->cur_mon_id);
   mon_rect = current_mon.rcMonitor;
   g_resize_width  = info->width;
   g_resize_height = info->height;

   windowed_full = settings->video.windowed_fullscreen;

   full_x = (windowed_full || info->width  == 0) ?
      (mon_rect.right  - mon_rect.left) : info->width;
   full_y = (windowed_full || info->height == 0) ?
      (mon_rect.bottom - mon_rect.top)  : info->height;
   RARCH_LOG("[D3D]: Monitor size: %dx%d.\n",
         (int)(mon_rect.right  - mon_rect.left),
         (int)(mon_rect.bottom - mon_rect.top));
#else
   {
      gfx_ctx_mode_t mode;

      video_context_driver_get_video_size(&mode);

      full_x   = mode.width;
      full_y   = mode.height;
   }
#endif
   {
      unsigned new_width  = info->fullscreen ? full_x : info->width;
      unsigned new_height = info->fullscreen ? full_y : info->height;
      video_driver_set_size(&new_width, &new_height);
   }

#ifdef HAVE_WINDOW
   DWORD style;
   unsigned win_width, win_height;
   RECT rect            = {0};

   video_driver_get_size(&win_width, &win_height);

   win32_set_style(&current_mon, &hm_to_use, &win_width, &win_height,
         info->fullscreen, windowed_full, &rect, &mon_rect, &style);

   win32_window_create(d3d, style, &mon_rect, win_width,
         win_height, info->fullscreen);

   win32_set_window(&win_width, &win_height, info->fullscreen,
	   windowed_full, &rect);
#endif

#ifdef HAVE_SHADERS
   /* This should only be done once here
    * to avoid set_shader() to be overridden
    * later. */
   enum rarch_shader_type type =
      video_shader_parse_type(settings->path.shader, RARCH_SHADER_NONE);
   if (settings->video.shader_enable && type == RARCH_SHADER_CG)
      d3d->shader_path = settings->path.shader;

   if (!d3d_process_shader(d3d))
      return false;
#endif

   d3d->video_info = *info;
   if (!d3d_initialize(d3d, &d3d->video_info))
      return false;

   inp.input      = input;
   inp.input_data = input_data;

   video_context_driver_input_driver(&inp);

   RARCH_LOG("[D3D]: Init complete.\n");
   return true;
}
Example #2
0
void d3d_make_d3dpp(void *data,
      const video_info_t *info, D3DPRESENT_PARAMETERS *d3dpp)
{
   d3d_video_t     *d3d = (d3d_video_t*)data;
   settings_t *settings = config_get_ptr();
#ifdef _XBOX
   /* TODO/FIXME - get rid of global state dependencies. */
   global_t *global     = global_get_ptr();
#endif

   memset(d3dpp, 0, sizeof(*d3dpp));

#ifdef _XBOX
   d3dpp->Windowed             = false;
#else
   d3dpp->Windowed             = settings->video.windowed_fullscreen 
      || !info->fullscreen;
#endif
   d3dpp->PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;

   if (info->vsync)
   {
      switch (settings->video.swap_interval)
      {
         default:
         case 1:
            d3dpp->PresentationInterval = D3DPRESENT_INTERVAL_ONE;
            break;
         case 2:
            d3dpp->PresentationInterval = D3DPRESENT_INTERVAL_TWO;
            break;
         case 3:
            d3dpp->PresentationInterval = D3DPRESENT_INTERVAL_THREE;
            break;
         case 4:
            d3dpp->PresentationInterval = D3DPRESENT_INTERVAL_FOUR;
            break;
      }
   }

   d3dpp->SwapEffect = D3DSWAPEFFECT_DISCARD;
   d3dpp->BackBufferCount = 2;
#ifdef _XBOX
   d3dpp->BackBufferFormat =
#ifdef _XBOX360
      global->console.screen.gamma_correction ?
      (D3DFORMAT)MAKESRGBFMT(info->rgb32 ? 
            D3DFMT_X8R8G8B8 : D3DFMT_LIN_R5G6B5) :
#endif
      info->rgb32 ? D3DFMT_X8R8G8B8 : D3DFMT_LIN_R5G6B5;
#else
   d3dpp->hDeviceWindow    = win32_get_window();
   d3dpp->BackBufferFormat = !d3dpp->Windowed ? 
      D3DFMT_X8R8G8B8 : D3DFMT_UNKNOWN;
#endif

   if (!d3dpp->Windowed)
   {
#ifdef _XBOX
      gfx_ctx_mode_t mode;
      unsigned width          = 0;
      unsigned height         = 0;

      video_context_driver_get_video_size(&mode);

      width                   = mode.width;
      height                  = mode.height;
      mode.width              = 0;
      mode.height             = 0;
      video_driver_set_size(&width, &height);
#endif
      video_driver_get_size(&d3dpp->BackBufferWidth,
            &d3dpp->BackBufferHeight);
   }

#ifdef _XBOX
   d3dpp->MultiSampleType         = D3DMULTISAMPLE_NONE;
   d3dpp->EnableAutoDepthStencil  = FALSE;
#if defined(_XBOX1)
   /* Get the "video mode" */
   DWORD video_mode               = XGetVideoFlags();

   /* Check if we are able to use progressive mode. */
   if (video_mode & XC_VIDEO_FLAGS_HDTV_480p)
      d3dpp->Flags = D3DPRESENTFLAG_PROGRESSIVE;
   else
      d3dpp->Flags = D3DPRESENTFLAG_INTERLACED;

   /* Only valid in PAL mode, not valid for HDTV modes. */
   if (XGetVideoStandard() == XC_VIDEO_STANDARD_PAL_I)
   {
      if (video_mode & XC_VIDEO_FLAGS_PAL_60Hz)
         d3dpp->FullScreen_RefreshRateInHz = 60;
      else
         d3dpp->FullScreen_RefreshRateInHz = 50;
   }

   if (XGetAVPack() == XC_AV_PACK_HDTV)
   {
      if (video_mode & XC_VIDEO_FLAGS_HDTV_480p)
         d3dpp->Flags = D3DPRESENTFLAG_PROGRESSIVE;
      else if (video_mode & XC_VIDEO_FLAGS_HDTV_720p)
         d3dpp->Flags = D3DPRESENTFLAG_PROGRESSIVE;
      else if (video_mode & XC_VIDEO_FLAGS_HDTV_1080i)
         d3dpp->Flags = D3DPRESENTFLAG_INTERLACED;
   }

   if (widescreen_mode)
      d3dpp->Flags |= D3DPRESENTFLAG_WIDESCREEN;
#elif defined(_XBOX360)
   if (!widescreen_mode)
      d3dpp->Flags |= D3DPRESENTFLAG_NO_LETTERBOX;

   if (global->console.screen.gamma_correction)
      d3dpp->FrontBufferFormat       = (D3DFORMAT)
         MAKESRGBFMT(D3DFMT_LE_X8R8G8B8);
   else
      d3dpp->FrontBufferFormat       = D3DFMT_LE_X8R8G8B8;
   d3dpp->MultiSampleQuality      = 0;
#endif
#endif
}
Example #3
0
static bool gl1_gfx_frame(void *data, const void *frame,
      unsigned frame_width, unsigned frame_height, uint64_t frame_count,
      unsigned pitch, const char *msg, video_frame_info_t *video_info)
{
   gfx_ctx_mode_t mode;
   const void *frame_to_copy = NULL;
   unsigned width            = 0;
   unsigned height           = 0;
   unsigned bits             = gl1_video_bits;
   bool draw                 = true;
   gl1_t *gl1                = (gl1_t*)data;
   unsigned pot_width        = 0;
   unsigned pot_height       = 0;

   gl1_context_bind_hw_render(gl1, false);

   /* FIXME: Force these settings off as they interfere with the rendering */
   video_info->xmb_shadows_enable   = false;
   video_info->menu_shader_pipeline = 0;

   if (!frame || !frame_width || !frame_height)
      return true;

   if (gl1->should_resize)
   {
      gfx_ctx_mode_t mode;

      gl1->should_resize = false;

      mode.width        = width;
      mode.height       = height;

      video_info->cb_set_resize(video_info->context_data,
            mode.width, mode.height);

      gl1_gfx_set_viewport(gl1, video_info, video_info->width, video_info->height, false, true);
   }

   glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
   glClear(GL_COLOR_BUFFER_BIT);

   glEnable(GL_BLEND);
   glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

   if (  gl1_video_width  != frame_width  ||
         gl1_video_height != frame_height ||
         gl1_video_pitch  != pitch)
   {
      if (frame_width > 4 && frame_height > 4)
      {
         gl1_video_width  = frame_width;
         gl1_video_height = frame_height;
         gl1_video_pitch  = pitch;

         pot_width = get_pot(frame_width);
         pot_height = get_pot(frame_height);

         if (gl1_video_buf)
            free(gl1_video_buf);

         gl1_video_buf = (unsigned char*)malloc(pot_width * pot_height * 4);
      }
   }

   width         = gl1_video_width;
   height        = gl1_video_height;
   pitch         = gl1_video_pitch;

   pot_width = get_pot(width);
   pot_height = get_pot(height);

   if (  frame_width  == 4 &&
         frame_height == 4 &&
         (frame_width < width && frame_height < height)
      )
      draw = false;

   if (draw && gl1_video_buf)
   {
      if (bits == 32)
      {
         unsigned y;
         /* copy lines into top-left portion of larger (power-of-two) buffer */
         for (y = 0; y < height; y++)
            memcpy(gl1_video_buf + ((pot_width * (bits / 8)) * y), (const unsigned char*)frame + (pitch * y), width * (bits / 8));
      }
      else if (bits == 16)
         conv_rgb565_argb8888(gl1_video_buf, frame, width, height, pot_width * sizeof(unsigned), pitch);

      frame_to_copy = gl1_video_buf;
   }

   if (gl1->video_width != width || gl1->video_height != height)
   {
      gl1->video_width  = width;
      gl1->video_height = height;
   }

   video_context_driver_get_video_size(&mode);

   gl1->screen_width           = mode.width;
   gl1->screen_height          = mode.height;

   if (draw)
   {
      if (frame_to_copy)
      {
         draw_tex(gl1, pot_width, pot_height, width, height, gl1->tex, frame_to_copy);
      }
   }

   if (gl1_menu_frame && video_info->menu_is_alive)
   {
      frame_to_copy = NULL;
      width         = gl1_menu_width;
      height        = gl1_menu_height;
      pitch         = gl1_menu_pitch;
      bits          = gl1_menu_bits;

      pot_width = get_pot(width);
      pot_height = get_pot(height);

      if (gl1_menu_size_changed)
      {
         gl1_menu_size_changed = false;

         if (gl1_menu_video_buf)
         {
            free(gl1_menu_video_buf);
            gl1_menu_video_buf = NULL;
         }
      }

      if (!gl1_menu_video_buf)
         gl1_menu_video_buf = (unsigned char*)malloc(pot_width * pot_height * 4);

      if (bits == 16 && gl1_menu_video_buf)
      {
         conv_rgba4444_argb8888(gl1_menu_video_buf, gl1_menu_frame, width, height, pot_width * sizeof(unsigned), pitch);

         frame_to_copy = gl1_menu_video_buf;

         if (gl1->menu_texture_full_screen)
         {
            glViewport(0, 0, video_info->width, video_info->height);
            draw_tex(gl1, pot_width, pot_height, width, height, gl1->menu_tex, frame_to_copy);
            glViewport(gl1->vp.x, gl1->vp.y, gl1->vp.width, gl1->vp.height);
         }
         else
            draw_tex(gl1, pot_width, pot_height, width, height, gl1->menu_tex, frame_to_copy);
      }
   }

#ifdef HAVE_MENU
   if (gl1->menu_texture_enable)
      menu_driver_frame(video_info);
   else if (video_info->statistics_show)
   {
      struct font_params *osd_params = (struct font_params*)
         &video_info->osd_stat_params;

      if (osd_params)
      {
         font_driver_render_msg(video_info, NULL, video_info->stat_text,
               (const struct font_params*)&video_info->osd_stat_params);
#if 0
         osd_params->y               = 0.350f;
         osd_params->scale           = 0.75f;
         font_driver_render_msg(video_info, NULL, video_info->chat_text,
               (const struct font_params*)&video_info->osd_stat_params);
#endif
      }
   }

#ifdef HAVE_MENU_WIDGETS
   menu_widgets_frame(video_info);
#endif
#endif

#ifdef HAVE_OVERLAY
   if (gl1->overlay_enable)
      gl1_render_overlay(gl1, video_info);
#endif

   if (msg)
      font_driver_render_msg(video_info, NULL, msg, NULL);

   video_info->cb_update_window_title(
         video_info->context_data, video_info);

   /* Screenshots. */
   if (gl1->readback_buffer_screenshot)
      gl1_readback(gl1,
            4, GL_RGBA, GL_UNSIGNED_BYTE,
            gl1->readback_buffer_screenshot);

   /* emscripten has to do black frame insertion in its main loop */
#ifndef EMSCRIPTEN
   /* Disable BFI during fast forward, slow-motion,
    * and pause to prevent flicker. */
   if (
         video_info->black_frame_insertion
         && !video_info->input_driver_nonblock_state
         && !video_info->runloop_is_slowmotion
         && !video_info->runloop_is_paused)
   {
      video_info->cb_swap_buffers(video_info->context_data, video_info);
      glClear(GL_COLOR_BUFFER_BIT);
   }
#endif

   video_info->cb_swap_buffers(video_info->context_data, video_info);

   /* check if we are fast forwarding or in menu, if we are ignore hard sync */
   if (video_info->hard_sync
         && !video_info->input_driver_nonblock_state
         && !gl1->menu_texture_enable)
   {
      glClear(GL_COLOR_BUFFER_BIT);
      glFinish();
   }

   gl1_context_bind_hw_render(gl1, true);

   return true;
}
Example #4
0
static void *gl1_gfx_init(const video_info_t *video,
      const input_driver_t **input, void **input_data)
{
   unsigned full_x, full_y;
   gfx_ctx_input_t inp;
   gfx_ctx_mode_t mode;
   void *ctx_data                       = NULL;
   const gfx_ctx_driver_t *ctx_driver   = NULL;
   unsigned win_width = 0, win_height   = 0;
   unsigned temp_width = 0, temp_height = 0;
   settings_t *settings                 = config_get_ptr();
   gl1_t *gl1                           = (gl1_t*)calloc(1, sizeof(*gl1));
   const char *vendor                   = NULL;
   const char *renderer                 = NULL;
   const char *version                  = NULL;
   const char *extensions               = NULL;
   int interval                         = 0;
   struct retro_hw_render_callback *hwr = NULL;

   if (!gl1)
      return NULL;

   *input                               = NULL;
   *input_data                          = NULL;

   gl1_video_width                      = video->width;
   gl1_video_height                     = video->height;
   gl1_rgb32                            = video->rgb32;

   gl1_video_bits                       = video->rgb32 ? 32 : 16;

   if (video->rgb32)
      gl1_video_pitch = video->width * 4;
   else
      gl1_video_pitch = video->width * 2;

   ctx_driver = video_context_driver_init_first(gl1,
         settings->arrays.video_context_driver,
         GFX_CTX_OPENGL_API, 1, 1, false, &ctx_data);

   if (!ctx_driver)
      goto error;

   if (ctx_data)
      gl1->ctx_data = ctx_data;

   gl1->ctx_driver  = ctx_driver;

   video_context_driver_set((const gfx_ctx_driver_t*)ctx_driver);

   RARCH_LOG("[GL1]: Found GL1 context: %s\n", ctx_driver->ident);

   video_context_driver_get_video_size(&mode);

   full_x      = mode.width;
   full_y      = mode.height;
   mode.width  = 0;
   mode.height = 0;

   /* Clear out potential error flags in case we use cached context. */
   glGetError();

   if (string_is_equal(ctx_driver->ident, "null"))
      goto error;

   RARCH_LOG("[GL1]: Detecting screen resolution %ux%u.\n", full_x, full_y);

   win_width   = video->width;
   win_height  = video->height;

   if (video->fullscreen && (win_width == 0) && (win_height == 0))
   {
      win_width  = full_x;
      win_height = full_y;
   }

   mode.width      = win_width;
   mode.height     = win_height;
   mode.fullscreen = video->fullscreen;

   interval = video->swap_interval;

   video_context_driver_swap_interval(&interval);

   if (!video_context_driver_set_video_mode(&mode))
      goto error;

   gl1->fullscreen = video->fullscreen;

   mode.width     = 0;
   mode.height    = 0;

   video_context_driver_get_video_size(&mode);

   temp_width     = mode.width;
   temp_height    = mode.height;
   mode.width     = 0;
   mode.height    = 0;

   /* Get real known video size, which might have been altered by context. */

   if (temp_width != 0 && temp_height != 0)
      video_driver_set_size(&temp_width, &temp_height);

   video_driver_get_size(&temp_width, &temp_height);

   RARCH_LOG("[GL1]: Using resolution %ux%u\n", temp_width, temp_height);

   vendor   = (const char*)glGetString(GL_VENDOR);
   renderer = (const char*)glGetString(GL_RENDERER);
   version  = (const char*)glGetString(GL_VERSION);
   extensions = (const char*)glGetString(GL_EXTENSIONS);

   if (!string_is_empty(version))
      sscanf(version, "%d.%d", &gl1->version_major, &gl1->version_minor);

   if (!string_is_empty(extensions))
      gl1->extensions = string_split(extensions, " ");

   RARCH_LOG("[GL1]: Vendor: %s, Renderer: %s.\n", vendor, renderer);
   RARCH_LOG("[GL1]: Version: %s.\n", version);
   RARCH_LOG("[GL1]: Extensions: %s\n", extensions);

   {
      char device_str[128];

      device_str[0] = '\0';

      if (!string_is_empty(vendor))
      {
         strlcpy(device_str, vendor, sizeof(device_str));
         strlcat(device_str, " ", sizeof(device_str));
      }

      if (!string_is_empty(renderer))
         strlcat(device_str, renderer, sizeof(device_str));

      video_driver_set_gpu_device_string(device_str);

      if (!string_is_empty(version))
         video_driver_set_gpu_api_version_string(version);
   }

   inp.input      = input;
   inp.input_data = input_data;

   video_context_driver_input_driver(&inp);

   if (settings->bools.video_font_enable)
      font_driver_init_osd(gl1, false,
            video->is_threaded,
            FONT_DRIVER_RENDER_OPENGL1_API);

   gl1->smooth = settings->bools.video_smooth;
   gl1->supports_bgra = string_list_find_elem(gl1->extensions, "GL_EXT_bgra");

   glDisable(GL_BLEND);
   glDisable(GL_DEPTH_TEST);
   glDisable(GL_CULL_FACE);
   glDisable(GL_STENCIL_TEST);
   glDisable(GL_SCISSOR_TEST);
   glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
   glGenTextures(1, &gl1->tex);
   glGenTextures(1, &gl1->menu_tex);

   hwr = video_driver_get_hw_context();

   memcpy(gl1->tex_info.coord, gl1_tex_coords, sizeof(gl1->tex_info.coord));
   gl1->vertex_ptr        = hwr->bottom_left_origin
      ? gl1_vertexes : gl1_vertexes_flipped;
   gl1->textures              = 4;
   gl1->white_color_ptr       = gl1_white_color;
   gl1->coords.vertex         = gl1->vertex_ptr;
   gl1->coords.tex_coord      = gl1->tex_info.coord;
   gl1->coords.color          = gl1->white_color_ptr;
   gl1->coords.lut_tex_coord  = gl1_tex_coords;
   gl1->coords.vertices       = 4;

   RARCH_LOG("[GL1]: Init complete.\n");

   return gl1;

error:
   video_context_driver_destroy();
   if (gl1)
   {
      if (gl1->extensions)
         string_list_free(gl1->extensions);
      free(gl1);
   }
   return NULL;
}
Example #5
0
static void *gdi_gfx_init(const video_info_t *video,
      const input_driver_t **input, void **input_data)
{
   unsigned full_x, full_y;
   gfx_ctx_input_t inp;
   gfx_ctx_mode_t mode;
   const gfx_ctx_driver_t *ctx_driver   = NULL;
   unsigned win_width = 0, win_height   = 0;
   unsigned temp_width = 0, temp_height = 0;
   settings_t *settings                 = config_get_ptr();
   gdi_t *gdi                           = (gdi_t*)calloc(1, sizeof(*gdi));

   *input                               = NULL;
   *input_data                          = NULL;

   gdi_video_width                      = video->width;
   gdi_video_height                     = video->height;
   gdi_rgb32                            = video->rgb32;

   gdi_video_bits                       = video->rgb32 ? 32 : 16;

   if (video->rgb32)
      gdi_video_pitch = video->width * 4;
   else
      gdi_video_pitch = video->width * 2;

   gdi_gfx_create();

   ctx_driver = video_context_driver_init_first(gdi,
         settings->arrays.video_context_driver,
         GFX_CTX_GDI_API, 1, 0, false);
   if (!ctx_driver)
      goto error;

   video_context_driver_set((const gfx_ctx_driver_t*)ctx_driver);

   RARCH_LOG("[GDI]: Found GDI context: %s\n", ctx_driver->ident);

   video_context_driver_get_video_size(&mode);

   full_x      = mode.width;
   full_y      = mode.height;
   mode.width  = 0;
   mode.height = 0;

   RARCH_LOG("[GDI]: Detecting screen resolution %ux%u.\n", full_x, full_y);

   win_width   = video->width;
   win_height  = video->height;

   if (video->fullscreen && (win_width == 0) && (win_height == 0))
   {
      win_width  = full_x;
      win_height = full_y;
   }

   mode.width      = win_width;
   mode.height     = win_height;
   mode.fullscreen = video->fullscreen;

   if (!video_context_driver_set_video_mode(&mode))
      goto error;

   mode.width     = 0;
   mode.height    = 0;

   video_context_driver_get_video_size(&mode);

   temp_width     = mode.width;
   temp_height    = mode.height;
   mode.width     = 0;
   mode.height    = 0;

   /* Get real known video size, which might have been altered by context. */

   if (temp_width != 0 && temp_height != 0)
      video_driver_set_size(&temp_width, &temp_height);

   video_driver_get_size(&temp_width, &temp_height);

   RARCH_LOG("[GDI]: Using resolution %ux%u\n", temp_width, temp_height);

   inp.input      = input;
   inp.input_data = input_data;

   video_context_driver_input_driver(&inp);

   if (settings->bools.video_font_enable)
      font_driver_init_osd(gdi, false,
            video->is_threaded,
            FONT_DRIVER_RENDER_GDI);

   RARCH_LOG("[GDI]: Init complete.\n");

   return gdi;

error:
   video_context_driver_destroy();
   if (gdi)
      free(gdi);
   return NULL;
}
Example #6
0
static bool gdi_gfx_frame(void *data, const void *frame,
      unsigned frame_width, unsigned frame_height, uint64_t frame_count,
      unsigned pitch, const char *msg, video_frame_info_t *video_info)
{
   gfx_ctx_mode_t mode;
   const void *frame_to_copy = frame;
   unsigned width            = 0;
   unsigned height           = 0;
   unsigned bits             = gdi_video_bits;
   bool draw                 = true;
   gdi_t *gdi                = (gdi_t*)data;
   HWND hwnd                 = win32_get_window();

   if (!frame || !frame_width || !frame_height)
      return true;

#ifdef HAVE_MENU
   menu_driver_frame(video_info);
#endif

   if (gdi_video_width != frame_width || gdi_video_height != frame_height || gdi_video_pitch != pitch)
   {
      if (frame_width > 4 && frame_height > 4)
      {
         gdi_video_width = frame_width;
         gdi_video_height = frame_height;
         gdi_video_pitch = pitch;
      }
   }

   if (gdi_menu_frame && video_info->menu_is_alive)
   {
      frame_to_copy = gdi_menu_frame;
      width         = gdi_menu_width;
      height        = gdi_menu_height;
      pitch         = gdi_menu_pitch;
      bits          = gdi_menu_bits;
   }
   else
   {
      width         = gdi_video_width;
      height        = gdi_video_height;
      pitch         = gdi_video_pitch;

      if (frame_width == 4 && frame_height == 4 && (frame_width < width && frame_height < height))
         draw = false;

      if (video_info->menu_is_alive)
         draw = false;
   }

   if (hwnd && !gdi->winDC)
   {
      gdi->winDC = GetDC(hwnd);
      gdi->memDC = CreateCompatibleDC(gdi->winDC);
      gdi->video_width = width;
      gdi->video_height = height;
      gdi->bmp = CreateCompatibleBitmap(gdi->winDC, gdi->video_width, gdi->video_height);
   }

   gdi->bmp_old  = (HBITMAP)SelectObject(gdi->memDC, gdi->bmp);

   if (gdi->video_width != width || gdi->video_height != height)
   {
      SelectObject(gdi->memDC, gdi->bmp_old);
      DeleteObject(gdi->bmp);

      gdi->video_width = width;
      gdi->video_height = height;
      gdi->bmp = CreateCompatibleBitmap(gdi->winDC, gdi->video_width, gdi->video_height);
      gdi->bmp_old = (HBITMAP)SelectObject(gdi->memDC, gdi->bmp);
   }

   video_context_driver_get_video_size(&mode);

   gdi->screen_width = mode.width;
   gdi->screen_height = mode.height;

   BITMAPINFO *info = (BITMAPINFO*)calloc(1, sizeof(*info) + (3 * sizeof(RGBQUAD)));

   info->bmiHeader.biBitCount  = bits;
   info->bmiHeader.biWidth     = pitch / (bits / 8);
   info->bmiHeader.biHeight    = -height;
   info->bmiHeader.biPlanes    = 1;
   info->bmiHeader.biSize      = sizeof(BITMAPINFOHEADER);
   info->bmiHeader.biSizeImage = 0;

   if (bits == 16)
   {
      unsigned *masks = (unsigned*)info->bmiColors;

      info->bmiHeader.biCompression = BI_BITFIELDS;

      /* default 16-bit format on Windows is XRGB1555 */
      if (frame_to_copy == gdi_menu_frame)
      {
         /* map RGB444 color bits for RGUI */
         masks[0] = 0xF000;
         masks[1] = 0x0F00;
         masks[2] = 0x00F0;
      }
      else
      {
         /* map RGB565 color bits for core */
         masks[0] = 0xF800;
         masks[1] = 0x07E0;
         masks[2] = 0x001F;
      }
   }
   else
      info->bmiHeader.biCompression = BI_RGB;

   if (draw)
   {
      StretchDIBits(gdi->memDC, 0, 0, width, height, 0, 0, width, height,
            frame_to_copy, info, DIB_RGB_COLORS, SRCCOPY);
   }

   SelectObject(gdi->memDC, gdi->bmp_old);

   free(info);

   if (msg)
      font_driver_render_msg(video_info, NULL, msg, NULL);

   InvalidateRect(hwnd, NULL, false);

   video_info->cb_update_window_title(
         video_info->context_data, video_info);

   return true;
}