コード例 #1
0
static bool video_frame_scale(const void *data,
      unsigned width, unsigned height,
      size_t pitch)
{
   driver_t *driver = driver_get_ptr();

   RARCH_PERFORMANCE_INIT(video_frame_conv);

   if (!data)
      return false;
   if (video_driver_get_pixel_format() != RETRO_PIXEL_FORMAT_0RGB1555)
      return false;
   if (data == RETRO_HW_FRAME_BUFFER_VALID)
      return false;

   RARCH_PERFORMANCE_START(video_frame_conv);

   driver->scaler.in_width      = width;
   driver->scaler.in_height     = height;
   driver->scaler.out_width     = width;
   driver->scaler.out_height    = height;
   driver->scaler.in_stride     = pitch;
   driver->scaler.out_stride    = width * sizeof(uint16_t);

   scaler_ctx_scale(&driver->scaler, driver->scaler_out, data);

   RARCH_PERFORMANCE_STOP(video_frame_conv);
   
   return true;
}
コード例 #2
0
bool init_video_pixel_converter(unsigned size)
{
    /* This function can be called multiple times
     * without deiniting first on consoles. */
    deinit_pixel_converter();

    /* If pixel format is not 0RGB1555, we don't need to do
     * any internal pixel conversion. */
    if (video_driver_get_pixel_format() != RETRO_PIXEL_FORMAT_0RGB1555)
        return true;

    RARCH_WARN("0RGB1555 pixel format is deprecated, and will be slower. For 15/16-bit, RGB565 format is preferred.\n");

    scaler_ptr = (video_pixel_scaler_t*)calloc(1, sizeof(*scaler_ptr));

    if (!scaler_ptr)
        goto error;

    scaler_ptr->scaler = (struct scaler_ctx*)calloc(1, sizeof(*scaler_ptr->scaler));

    if (!scaler_ptr->scaler)
        goto error;

    scaler_ptr->scaler->scaler_type = SCALER_TYPE_POINT;
    scaler_ptr->scaler->in_fmt      = SCALER_FMT_0RGB1555;

    /* TODO: Pick either ARGB8888 or RGB565 depending on driver. */
    scaler_ptr->scaler->out_fmt     = SCALER_FMT_RGB565;

    if (!scaler_ctx_gen_filter(scaler_ptr->scaler))
        goto error;

    scaler_ptr->scaler_out = calloc(sizeof(uint16_t), size * size);

    if (!scaler_ptr->scaler_out)
        goto error;

    return true;

error:
    if (scaler_ptr->scaler_out)
        free(scaler_ptr->scaler_out);
    if (scaler_ptr->scaler)
        free(scaler_ptr->scaler);
    if (scaler_ptr)
        free(scaler_ptr);

    scaler_ptr = NULL;

    return false;
}
コード例 #3
0
ファイル: record_driver.c プロジェクト: Ced2911/RetroArch
/**
 * recording_init:
 *
 * Initializes recording.
 *
 * Returns: true (1) if successful, otherwise false (0).
 **/
bool recording_init(void)
{
   char recording_file[PATH_MAX_LENGTH] = {0};
   struct ffemu_params params           = {0};
   global_t *global                     = global_get_ptr();
   settings_t *settings                 = config_get_ptr();
   struct retro_system_av_info *av_info = video_viewport_get_system_av_info();
   const struct retro_hw_render_callback *hw_render = 
      (const struct retro_hw_render_callback*)video_driver_callback();
   bool *recording_enabled              = recording_is_enabled();

   if (!*recording_enabled)
      return false;

   if (global->inited.core.type == CORE_TYPE_DUMMY)
   {
      RARCH_WARN("%s\n", msg_hash_to_str(MSG_USING_LIBRETRO_DUMMY_CORE_RECORDING_SKIPPED));
      return false;
   }

   if (!settings->video.gpu_record && hw_render->context_type)
   {
      RARCH_WARN("%s.\n", msg_hash_to_str(MSG_HW_RENDERED_MUST_USE_POSTSHADED_RECORDING));
      return false;
   }

   RARCH_LOG("%s: FPS: %.4f, Sample rate: %.4f\n",
         msg_hash_to_str(MSG_CUSTOM_TIMING_GIVEN),
         (float)av_info->timing.fps,
         (float)av_info->timing.sample_rate);

   strlcpy(recording_file, global->record.path, sizeof(recording_file));

   if (global->record.use_output_dir)
      fill_pathname_join(recording_file,
            global->record.output_dir,
            global->record.path, sizeof(recording_file));

   params.out_width  = av_info->geometry.base_width;
   params.out_height = av_info->geometry.base_height;
   params.fb_width   = av_info->geometry.max_width;
   params.fb_height  = av_info->geometry.max_height;
   params.channels   = 2;
   params.filename   = recording_file;
   params.fps        = av_info->timing.fps;
   params.samplerate = av_info->timing.sample_rate;
   params.pix_fmt    = (video_driver_get_pixel_format() == RETRO_PIXEL_FORMAT_XRGB8888) ?
      FFEMU_PIX_ARGB8888 : FFEMU_PIX_RGB565;
   params.config     = NULL;
   
   if (*global->record.config)
      params.config = global->record.config;

   if (video_driver_ctl(RARCH_DISPLAY_CTL_SUPPORTS_RECORDING, NULL))
   {
      unsigned gpu_size;
      struct video_viewport vp = {0};

      video_driver_viewport_info(&vp);

      if (!vp.width || !vp.height)
      {
         RARCH_ERR("Failed to get viewport information from video driver. "
               "Cannot start recording ...\n");
         return false;
      }

      params.out_width  = vp.width;
      params.out_height = vp.height;
      params.fb_width   = next_pow2(vp.width);
      params.fb_height  = next_pow2(vp.height);

      if (settings->video.force_aspect &&
            (video_driver_get_aspect_ratio() > 0.0f))
         params.aspect_ratio  = video_driver_get_aspect_ratio();
      else
         params.aspect_ratio  = (float)vp.width / vp.height;

      params.pix_fmt             = FFEMU_PIX_BGR24;
      global->record.gpu_width   = vp.width;
      global->record.gpu_height  = vp.height;

      RARCH_LOG("%s %u x %u\n", msg_hash_to_str(MSG_DETECTED_VIEWPORT_OF),
            vp.width, vp.height);

      gpu_size = vp.width * vp.height * 3;
      if (!video_driver_ctl(RARCH_DISPLAY_CTL_GPU_RECORD_INIT, &gpu_size))
         return false;
   }
   else
   {
      if (global->record.width || global->record.height)
      {
         params.out_width  = global->record.width;
         params.out_height = global->record.height;
      }

      if (settings->video.force_aspect &&
            (video_driver_get_aspect_ratio() > 0.0f))
         params.aspect_ratio = video_driver_get_aspect_ratio();
      else
         params.aspect_ratio = (float)params.out_width / params.out_height;

      if (settings->video.post_filter_record && video_driver_ctl(RARCH_DISPLAY_CTL_FRAME_FILTER_ALIVE, NULL))
      {
         unsigned max_width  = 0;
         unsigned max_height = 0;
         
         params.pix_fmt    = FFEMU_PIX_RGB565;

         if (video_driver_ctl(RARCH_DISPLAY_CTL_FRAME_FILTER_IS_32BIT, NULL))
            params.pix_fmt = FFEMU_PIX_ARGB8888;

         rarch_softfilter_get_max_output_size(
               video_driver_frame_filter_get_ptr(),
               &max_width, &max_height);
         params.fb_width  = next_pow2(max_width);
         params.fb_height = next_pow2(max_height);
      }
   }

   RARCH_LOG("%s %s @ %ux%u. (FB size: %ux%u pix_fmt: %u)\n",
         msg_hash_to_str(MSG_RECORDING_TO),
         global->record.path,
         params.out_width, params.out_height,
         params.fb_width, params.fb_height,
         (unsigned)params.pix_fmt);

   if (!record_driver_init_first(&recording_driver, &recording_data, &params))
   {
      RARCH_ERR("%s\n", msg_hash_to_str(MSG_FAILED_TO_START_RECORDING));
      event_command(EVENT_CMD_GPU_RECORD_DEINIT);

      return false;
   }

   return true;
}
コード例 #4
0
ファイル: task_screenshot.c プロジェクト: lollo78/RetroArch
/* Take frame bottom-up. */
static bool screenshot_dump(
      const char *global_name_base,
      const char *folder,
      const void *frame,
      unsigned width,
      unsigned height,
      int pitch, bool bgr24)
{
   char filename[PATH_MAX_LENGTH] = {0};
   char shotname[256]             = {0};
   bool ret                       = false;
   settings_t *settings           = config_get_ptr();
#if defined(HAVE_ZLIB_DEFLATE) && defined(HAVE_RPNG)
   uint8_t *out_buffer            = NULL;
   struct scaler_ctx scaler       = {0};
#endif

   if (settings->auto_screenshot_filename)
   {
      fill_dated_filename(shotname, IMG_EXT, sizeof(shotname));
      fill_pathname_join(filename, folder, shotname, sizeof(filename));
   }
   else
   {
      snprintf(shotname, sizeof(shotname),"%s.png", path_basename(global_name_base));
      fill_pathname_join(filename, folder, shotname, sizeof(filename));
   }

#ifdef _XBOX1
   d3d_video_t *d3d = (d3d_video_t*)video_driver_get_ptr(true);
   D3DSurface *surf = NULL;

   d3d->dev->GetBackBuffer(-1, D3DBACKBUFFER_TYPE_MONO, &surf);
   if (XGWriteSurfaceToFile(surf, filename) == S_OK)
      ret = true;
   surf->Release();
#elif defined(HAVE_ZLIB_DEFLATE) && defined(HAVE_RPNG)
   out_buffer = (uint8_t*)malloc(width * height * 3);
   if (!out_buffer)
      return false;

   video_frame_convert_to_bgr24(
         &scaler,
         out_buffer,
         (const uint8_t*)frame + ((int)height - 1) * pitch,
         width, height,
         -pitch,
         bgr24);

   scaler_ctx_gen_reset(&scaler);

   ret = rpng_save_image_bgr24(
         filename,
         out_buffer,
         width,
         height,
         width * 3
         );
   free(out_buffer);
#elif defined(HAVE_RBMP)
   enum rbmp_source_type bmp_type = RBMP_SOURCE_TYPE_DONT_CARE;

   if (bgr24)
      bmp_type = RBMP_SOURCE_TYPE_BGR24;
   else if (video_driver_get_pixel_format() == RETRO_PIXEL_FORMAT_XRGB8888)
      bmp_type = RBMP_SOURCE_TYPE_XRGB888;

   ret = rbmp_save_image(filename,
         frame,
         width,
         height,
         pitch,
         bmp_type);
#endif

#ifdef HAVE_IMAGEVIEWER
   if (ret == true)
   {
      if (content_push_to_history_playlist(g_defaults.image_history, filename,  
               "imageviewer", "builtin"))
         playlist_write_file(g_defaults.image_history);
   }
#endif

   return ret;
}
コード例 #5
0
ファイル: psp1_gfx.c プロジェクト: erbridge/RetroArch
static void *psp_init(const video_info_t *video,
      const input_driver_t **input, void **input_data)
{
   /* TODO : add ASSERT() checks or use main RAM if 
    * VRAM is too low for desired video->input_scale. */
   void *pspinput = NULL;
   int pixel_format, lut_pixel_format, lut_block_count;
   unsigned int red_shift, color_mask;
   void *displayBuffer, *LUT_r, *LUT_b;
   psp1_video_t *psp        = (psp1_video_t*)calloc(1, sizeof(psp1_video_t));

   if (!psp)
      return NULL;

   sceGuInit();

   psp->vp.x                = 0;
   psp->vp.y                = 0;
   psp->vp.width            = SCEGU_SCR_WIDTH;
   psp->vp.height           = SCEGU_SCR_HEIGHT;
   psp->vp.full_width       = SCEGU_SCR_WIDTH;
   psp->vp.full_height      = SCEGU_SCR_HEIGHT;

   /* Make sure anything using uncached pointers reserves 
    * whole cachelines (memory address and size need to be a multiple of 64)
    * so it isn't overwritten by an unlucky cache writeback.
    *
    * This includes display lists since the Gu library uses 
    * uncached pointers to write to them. */

   /* Allocate more space if bigger display lists are needed. */
   psp->main_dList          = memalign(64, 256);

   psp->frame_dList         = memalign(64, 256);
   psp->menu.dList          = memalign(64, 256);
   psp->menu.frame          = memalign(16,  2 * 480 * 272);
   psp->frame_coords        = memalign(64,
         (((PSP_FRAME_SLICE_COUNT * sizeof(psp1_sprite_t)) + 63) & ~63));
   psp->menu.frame_coords   = memalign(64,
         (((PSP_FRAME_SLICE_COUNT * sizeof(psp1_sprite_t)) + 63) & ~63));

   memset(psp->frame_coords, 0,
         PSP_FRAME_SLICE_COUNT * sizeof(psp1_sprite_t));
   memset(psp->menu.frame_coords, 0,
         PSP_FRAME_SLICE_COUNT * sizeof(psp1_sprite_t));

   sceKernelDcacheWritebackInvalidateAll();
   psp->frame_coords        = TO_UNCACHED_PTR(psp->frame_coords);
   psp->menu.frame_coords   = TO_UNCACHED_PTR(psp->menu.frame_coords);

   psp->frame_coords->v0.x  = 60;
   psp->frame_coords->v0.y  = 0;
   psp->frame_coords->v0.u  = 0;
   psp->frame_coords->v0.v  = 0;

   psp->frame_coords->v1.x  = 420;
   psp->frame_coords->v1.y  = SCEGU_SCR_HEIGHT;
   psp->frame_coords->v1.u  = 256;
   psp->frame_coords->v1.v  = 240;

   psp->vsync               = video->vsync;
   psp->rgb32               = video->rgb32;

   if(psp->rgb32)
   {
      u32 i;
      uint32_t* LUT_r_local = (uint32_t*)(SCEGU_VRAM_BP32_2);
      uint32_t* LUT_b_local = (uint32_t*)(SCEGU_VRAM_BP32_2) + (1 << 8);

      red_shift             = 8 + 8;
      color_mask            = 0xFF;
      lut_block_count       = (1 << 8) / 8;

      psp->texture          = (void*)(LUT_b_local + (1 << 8));
      psp->draw_buffer      = SCEGU_VRAM_BP32_0;
      psp->bpp_log2         = 2;

      pixel_format          = GU_PSM_8888;
      lut_pixel_format      = GU_PSM_T32;

      displayBuffer         = SCEGU_VRAM_BP32_1;

      for (i = 0; i < (1 << 8); i++)
      {
         LUT_r_local[i]     = i;
         LUT_b_local[i]     = i << (8 + 8);
      }

      LUT_r                 = (void*)LUT_r_local;
      LUT_b                 = (void*)LUT_b_local;

   }
   else
   {
      u16 i;
      uint16_t* LUT_r_local = (uint16_t*)(SCEGU_VRAM_BP_2);
      uint16_t* LUT_b_local = (uint16_t*)(SCEGU_VRAM_BP_2) + (1 << 5);

      red_shift             = 6 + 5;
      color_mask            = 0x1F;
      lut_block_count       = (1 << 5) / 8;

      psp->texture          = (void*)(LUT_b_local + (1 << 5));
      psp->draw_buffer      = SCEGU_VRAM_BP_0;
      psp->bpp_log2         = 1;

      pixel_format          = 
         (video_driver_get_pixel_format() == RETRO_PIXEL_FORMAT_0RGB1555) 
         ? GU_PSM_5551 : GU_PSM_5650 ;

      lut_pixel_format      = GU_PSM_T16;

      displayBuffer         = SCEGU_VRAM_BP_1;

      for (i = 0; i < (1 << 5); i++)
      {
         LUT_r_local[i]     = i;
         LUT_b_local[i]     = i << (5 + 6);
      }

      LUT_r                 = (void*)LUT_r_local;
      LUT_b                 = (void*)LUT_b_local;

   }

   psp->tex_filter = video->smooth? GU_LINEAR : GU_NEAREST;

   /* TODO: check if necessary. */
   sceDisplayWaitVblankStart();

   sceGuDisplay(GU_FALSE);

   sceGuStart(GU_DIRECT, psp->main_dList);

   sceGuDrawBuffer(pixel_format, TO_GU_POINTER(psp->draw_buffer),
         SCEGU_VRAM_WIDTH);
   sceGuDispBuffer(SCEGU_SCR_WIDTH, SCEGU_SCR_HEIGHT,
         TO_GU_POINTER(displayBuffer), SCEGU_VRAM_WIDTH);
   sceGuClearColor(0);
   sceGuScissor(0, 0, SCEGU_SCR_WIDTH, SCEGU_SCR_HEIGHT);
   sceGuEnable(GU_SCISSOR_TEST);
   sceGuTexFilter(psp->tex_filter, psp->tex_filter);
   sceGuTexWrap (GU_CLAMP, GU_CLAMP);
   sceGuEnable(GU_TEXTURE_2D);
   sceGuDisable(GU_DEPTH_TEST);
   sceGuCallMode(GU_FALSE);

   sceGuFinish();
   sceGuSync(0, 0);
 
   /* TODO : check if necessary */
   sceDisplayWaitVblankStart();
   sceGuDisplay(GU_TRUE);

   pspDebugScreenSetColorMode(pixel_format);
   pspDebugScreenSetBase(psp->draw_buffer);

   /* fill frame_dList : */
   sceGuStart(GU_CALL, psp->frame_dList);

   sceGuTexMode(pixel_format, 0, 0, GU_FALSE);
   sceGuTexFunc(GU_TFX_REPLACE, GU_TCC_RGB);
   sceGuEnable(GU_BLEND);

   /* green only */
   sceGuBlendFunc(GU_ADD, GU_FIX, GU_FIX, 0x0000FF00, 0xFFFFFFFF);

   sceGuDrawArray(GU_SPRITES, GU_TEXTURE_32BITF | GU_VERTEX_32BITF | 
         GU_TRANSFORM_2D, PSP_FRAME_VERTEX_COUNT, NULL,
         (void*)(psp->frame_coords));
   
   /* restore */
   sceGuBlendFunc(GU_ADD, GU_FIX, GU_FIX, 0xFFFFFFFF, 0xFFFFFFFF);

   sceGuTexMode(lut_pixel_format, 0, 0, GU_FALSE);

   sceGuClutMode(pixel_format, red_shift, color_mask, 0);
   sceGuClutLoad(lut_block_count, LUT_r);

   sceGuDrawArray(GU_SPRITES, GU_TEXTURE_32BITF | GU_VERTEX_32BITF |
         GU_TRANSFORM_2D, PSP_FRAME_VERTEX_COUNT, NULL,
         (void*)(psp->frame_coords));

   sceGuClutMode(pixel_format, 0, color_mask, 0);
   sceGuClutLoad(lut_block_count, LUT_b);
   sceGuDrawArray(GU_SPRITES, GU_TEXTURE_32BITF | GU_VERTEX_32BITF | 
         GU_TRANSFORM_2D, PSP_FRAME_VERTEX_COUNT, NULL,
         (void*)(psp->frame_coords));

   sceGuFinish();

   if (input && input_data)
   {
      pspinput = input_psp.init();
      *input = pspinput ? &input_psp : NULL;
      *input_data = pspinput;
   }

   psp->vblank_not_reached = true;
   sceKernelRegisterSubIntrHandler(PSP_VBLANK_INT, 0, psp_on_vblank, psp);
   sceKernelEnableSubIntr(PSP_VBLANK_INT, 0);

   psp->keep_aspect        = true;
   psp->should_resize      = true;
   psp->hw_render          = false;

   return psp;
error:
   RARCH_ERR("PSP1 video could not be initialized.\n");
   return (void*)-1;
}
コード例 #6
0
ファイル: record_driver.c プロジェクト: neil4/RetroArch
/**
 * recording_init:
 *
 * Initializes recording.
 *
 * Returns: true (1) if successful, otherwise false (0).
 **/
bool recording_init(void)
{
   char recording_file[PATH_MAX_LENGTH] = {0};
   struct ffemu_params params           = {0};
   global_t *global                     = global_get_ptr();
   driver_t *driver                     = driver_get_ptr();
   settings_t *settings                 = config_get_ptr();
   struct retro_system_av_info *av_info = video_viewport_get_system_av_info();
   const struct retro_hw_render_callback *hw_render = 
      (const struct retro_hw_render_callback*)video_driver_callback();

   if (!global->record.enable)
      return false;

   if (global->libretro_dummy)
   {
      RARCH_WARN(RETRO_LOG_INIT_RECORDING_SKIPPED);
      return false;
   }

   if (!settings->video.gpu_record && hw_render->context_type)
   {
      RARCH_WARN("Libretro core is hardware rendered. Must use post-shaded recording as well.\n");
      return false;
   }

   RARCH_LOG("Custom timing given: FPS: %.4f, Sample rate: %.4f\n",
         (float)av_info->timing.fps,
         (float)av_info->timing.sample_rate);

   strlcpy(recording_file, global->record.path, sizeof(recording_file));

   if (global->record.use_output_dir)
      fill_pathname_join(recording_file,
            global->record.output_dir,
            global->record.path, sizeof(recording_file));

   params.out_width  = av_info->geometry.base_width;
   params.out_height = av_info->geometry.base_height;
   params.fb_width   = av_info->geometry.max_width;
   params.fb_height  = av_info->geometry.max_height;
   params.channels   = 2;
   params.filename   = recording_file;
   params.fps        = av_info->timing.fps;
   params.samplerate = av_info->timing.sample_rate;
   params.pix_fmt    = (video_driver_get_pixel_format() == RETRO_PIXEL_FORMAT_XRGB8888) ?
      FFEMU_PIX_ARGB8888 : FFEMU_PIX_RGB565;
   params.config     = NULL;
   
   if (*global->record.config)
      params.config = global->record.config;

   if (settings->video.gpu_record && driver->video->read_viewport)
   {
      struct video_viewport vp = {0};

      video_driver_viewport_info(&vp);

      if (!vp.width || !vp.height)
      {
         RARCH_ERR("Failed to get viewport information from video driver. "
               "Cannot start recording ...\n");
         return false;
      }

      params.out_width  = vp.width;
      params.out_height = vp.height;
      params.fb_width   = next_pow2(vp.width);
      params.fb_height  = next_pow2(vp.height);

      if (settings->video.force_aspect &&
            (video_driver_get_aspect_ratio() > 0.0f))
         params.aspect_ratio  = video_driver_get_aspect_ratio();
      else
         params.aspect_ratio  = (float)vp.width / vp.height;

      params.pix_fmt             = FFEMU_PIX_BGR24;
      global->record.gpu_width   = vp.width;
      global->record.gpu_height  = vp.height;

      RARCH_LOG("Detected viewport of %u x %u\n",
            vp.width, vp.height);

      global->record.gpu_buffer = (uint8_t*)malloc(vp.width * vp.height * 3);
      if (!global->record.gpu_buffer)
      {
         RARCH_ERR("Failed to allocate GPU record buffer.\n");
         return false;
      }
   }
   else
   {
      if (global->record.width || global->record.height)
      {
         params.out_width  = global->record.width;
         params.out_height = global->record.height;
      }

      if (settings->video.force_aspect &&
            (video_driver_get_aspect_ratio() > 0.0f))
         params.aspect_ratio = video_driver_get_aspect_ratio();
      else
         params.aspect_ratio = (float)params.out_width / params.out_height;

      if (settings->video.post_filter_record && video_driver_frame_filter_alive())
      {
         unsigned max_width  = 0;
         unsigned max_height = 0;

         if (video_driver_frame_filter_is_32bit())
            params.pix_fmt = FFEMU_PIX_ARGB8888;
         else
            params.pix_fmt =  FFEMU_PIX_RGB565;

         rarch_softfilter_get_max_output_size(
               video_driver_frame_filter_get_ptr(),
               &max_width, &max_height);
         params.fb_width  = next_pow2(max_width);
         params.fb_height = next_pow2(max_height);
      }
   }

   RARCH_LOG("Recording to %s @ %ux%u. (FB size: %ux%u pix_fmt: %u)\n",
         global->record.path,
         params.out_width, params.out_height,
         params.fb_width, params.fb_height,
         (unsigned)params.pix_fmt);

   if (!record_driver_init_first(&driver->recording, &driver->recording_data, &params))
   {
      RARCH_ERR(RETRO_LOG_INIT_RECORDING_FAILED);
      event_command(EVENT_CMD_GPU_RECORD_DEINIT);

      return false;
   }

   return true;
}
コード例 #7
0
ファイル: task_screenshot.c プロジェクト: Alcaro/RetroArch
/* Take frame bottom-up. */
static bool screenshot_dump(
      const char *name_base,
      const void *frame,
      unsigned width,
      unsigned height,
      int pitch, bool bgr24,
      void *userbuf, bool savestate,
      bool is_idle,
      bool is_paused)
{
   char screenshot_path[PATH_MAX_LENGTH];
   uint8_t *buf                   = NULL;
#ifdef _XBOX1
   d3d_video_t *d3d               = (d3d_video_t*)video_driver_get_ptr(true);
#endif
   settings_t *settings           = config_get_ptr();
   retro_task_t *task             = (retro_task_t*)calloc(1, sizeof(*task));
   screenshot_task_state_t *state = (screenshot_task_state_t*)
         calloc(1, sizeof(*state));
   const char *screenshot_dir     = settings->paths.directory_screenshot;

   screenshot_path[0]             = '\0';

   if (string_is_empty(screenshot_dir) || settings->bools.screenshots_in_content_dir)
   {
      fill_pathname_basedir(screenshot_path, name_base,
            sizeof(screenshot_path));
      screenshot_dir = screenshot_path;
   }

   state->is_idle             = is_idle;
   state->is_paused           = is_paused;
   state->bgr24               = bgr24;
   state->height              = height;
   state->width               = width;
   state->pitch               = pitch;
   state->frame               = frame;
   state->userbuf             = userbuf;
   state->silence             = savestate;
   state->history_list_enable = settings->bools.history_list_enable;
   state->pixel_format_type   = video_driver_get_pixel_format();

   if (savestate)
      snprintf(state->filename,
            sizeof(state->filename), "%s.png", name_base);
   else
   {
      if (settings->bools.auto_screenshot_filename)
         fill_str_dated_filename(state->shotname, path_basename(name_base),
               IMG_EXT, sizeof(state->shotname));
      else
         snprintf(state->shotname, sizeof(state->shotname),
               "%s.png", path_basename(name_base));

      fill_pathname_join(state->filename, screenshot_dir,
            state->shotname, sizeof(state->filename));
   }

#ifdef _XBOX1
   d3d->dev->GetBackBuffer(-1, D3DBACKBUFFER_TYPE_MONO, &state->surf);
#elif defined(HAVE_RPNG)
   buf = (uint8_t*)malloc(width * height * 3);
   if (!buf)
   {
      if (task)
         free(task);
      free(state);
      return false;
   }
   state->out_buffer = buf;
#endif

   task->type        = TASK_TYPE_BLOCKING;
   task->state       = state;
   task->handler     = task_screenshot_handler;

   if (!savestate)
      task->title    = strdup(msg_hash_to_str(MSG_TAKING_SCREENSHOT));

   task_queue_push(task);

   return true;
}
コード例 #8
0
ファイル: httpserver.c プロジェクト: Alcaro/RetroArch
static int httpserver_handle_basic_info(struct mg_connection* conn, void* cbdata)
{
   static const char *libretro_btn_desc[] = {
      "B (bottom)", "Y (left)", "Select", "Start",
      "D-Pad Up", "D-Pad Down", "D-Pad Left", "D-Pad Right",
      "A (right)", "X (up)",
      "L", "R", "L2", "R2", "L3", "R3",
   };

   unsigned p, q, r;
   retro_ctx_api_info_t api;
   retro_ctx_region_info_t region;
   retro_ctx_memory_info_t sram;
   retro_ctx_memory_info_t rtc;
   retro_ctx_memory_info_t sysram;
   retro_ctx_memory_info_t vram;
   char core_path[PATH_MAX_LENGTH]                 = {0};
   const char* pixel_format                        = NULL;
   const struct retro_subsystem_info* subsys       = NULL;
   const struct retro_subsystem_rom_info* rom      = NULL;
   const struct retro_subsystem_memory_info* mem   = NULL;
   const struct retro_controller_description* ctrl = NULL;
   const char* comma                               = NULL;
   const struct core_option* opts                  = NULL;
   const struct retro_system_av_info* av_info      = NULL;
   const core_option_manager_t* core_opts          = NULL;
   const struct mg_request_info              * req = mg_get_request_info(conn);
   const settings_t                     * settings = config_get_ptr();
   rarch_system_info_t *system                     = runloop_get_system_info();

   if (string_is_empty(system->info.library_name))
      return httpserver_error(conn, 500, "Core not initialized in %s", __FUNCTION__);

   if (!core_is_game_loaded())
      return httpserver_error(conn, 500, "Game not loaded in %s", __FUNCTION__);

   json_string_encode(core_path, sizeof(core_path), config_get_active_core_path());

   core_api_version(&api);
   core_get_region(&region);

   switch (video_driver_get_pixel_format())
   {
      case RETRO_PIXEL_FORMAT_0RGB1555:
         pixel_format = "RETRO_PIXEL_FORMAT_0RGB1555";
         break;
      case RETRO_PIXEL_FORMAT_XRGB8888:
         pixel_format = "RETRO_PIXEL_FORMAT_XRGB8888";
         break;
      case RETRO_PIXEL_FORMAT_RGB565:
         pixel_format = "RETRO_PIXEL_FORMAT_RGB565";
         break;
      default:
         pixel_format = "?";
         break;
   }

   sram.id = RETRO_MEMORY_SAVE_RAM;
   core_get_memory(&sram);

   rtc.id = RETRO_MEMORY_RTC;
   core_get_memory(&rtc);

   sysram.id = RETRO_MEMORY_SYSTEM_RAM;
   core_get_memory(&sysram);

   vram.id = RETRO_MEMORY_VIDEO_RAM;
   core_get_memory(&vram);

   mg_printf(conn,
         "HTTP/1.1 200 OK\r\nContent-Type: application/json\r\n\r\n"
         "{"
         "\"corePath\":\"%s\","
         "\"apiVersion\":%u,"
         "\"systemInfo\":"
         "{"
         "\"libraryName\":\"%s\","
         "\"libraryVersion\":\"%s\","
         "\"validExtensions\":\"%s\","
         "\"needsFullpath\":%s,"
         "\"blockExtract\":%s"
         "},"
         "\"region\":\"%s\","
         "\"pixelFormat\":\"%s\","
         "\"rotation\":%u,"
         "\"performaceLevel\":%u,"
         "\"supportsNoGame\":%s,"
#ifdef HAVE_CHEEVOS
         "\"frontendSupportsAchievements\":true,"
         "\"coreSupportsAchievements\":%s,"
#else
         "\"frontendSupportsAchievements\":false,"
         "\"coreSupportsAchievements\":null,"
#endif
         "\"saveRam\":{\"pointer\":\"%" PRIXPTR "\",\"size\":" STRING_REP_UINT64 "},"
         "\"rtcRam\":{\"pointer\":\"%" PRIXPTR "\",\"size\":" STRING_REP_UINT64 "},"
         "\"systemRam\":{\"pointer\":\"%" PRIXPTR "\",\"size\":" STRING_REP_UINT64 "},"
         "\"videoRam\":{\"pointer\":\"%" PRIXPTR "\",\"size\":" STRING_REP_UINT64 "},",
      core_path,
      api.version,
      system->info.library_name,
      system->info.library_version,
      system->info.valid_extensions,
      system->info.need_fullpath ? "true" : "false",
      system->info.block_extract ? "true" : "false",
      region.region ? "RETRO_REGION_PAL" : "RETRO_REGION_NTSC",
      pixel_format,
      system->rotation,
      system->performance_level,
      content_does_not_need_content() ? "true" : "false",
#ifdef HAVE_CHEEVOS
      cheevos_get_support_cheevos() ? "true" : "false",
#endif
      (uintptr_t)sram.data, sram.size,
      (uintptr_t)rtc.data, rtc.size,
      (uintptr_t)sysram.data, sysram.size,
      (uintptr_t)vram.data, vram.size
         );

   mg_printf(conn, "\"subSystems\":[");
   subsys = system->subsystem.data;

   for (p = 0; p < system->subsystem.size; p++, subsys++)
   {
      mg_printf(conn, "%s{\"id\":%u,\"description\":\"%s\",\"identifier\":\"%s\",\"roms\":[", p == 0 ? "" : ",", subsys->id, subsys->desc, subsys->ident);
      rom = subsys->roms;

      for (q = 0; q < subsys->num_roms; q++, rom++)
      {
         mg_printf(conn,
               "%s{"
               "\"description\":\"%s\","
               "\"extensions\":\"%s\","
               "\"needsFullpath\":%s,"
               "\"blockExtract\":%s,"
               "\"required\":%s,"
               "\"memory\":[",
               q == 0 ? "" : ",",
               rom->desc,
               rom->valid_extensions,
               rom->need_fullpath ? "true" : "false",
               rom->block_extract ? "true" : "false",
               rom->required ? "true" : "false"
               );

         mem = rom->memory;
         comma = "";

         for (r = 0; r < rom->num_memory; r++, mem++)
         {
            mg_printf(conn, "%s{\"extension\":\"%s\",\"type\":%u}", comma, mem->extension, mem->type);
            comma = ",";
         }

         mg_printf(conn, "]}");
      }

      mg_printf(conn, "]}");
   }

   av_info = video_viewport_get_system_av_info();

   mg_printf(conn,
         "],\"avInfo\":{"
         "\"geometry\":{"
         "\"baseWidth\":%u,"
         "\"baseHeight\":%u,"
         "\"maxWidth\":%u,"
         "\"maxHeight\":%u,"
         "\"aspectRatio\":%f"
         "},"
         "\"timing\":{"
         "\"fps\":%f,"
         "\"sampleRate\":%f"
         "}"
         "},",
         av_info->geometry.base_width,
         av_info->geometry.base_height,
         av_info->geometry.max_width,
         av_info->geometry.max_height,
         av_info->geometry.aspect_ratio,
         av_info->timing.fps,
         av_info->timing.sample_rate
            );

   mg_printf(conn, "\"ports\":[");
   comma = "";

   for (p = 0; p < system->ports.size; p++)
   {
      ctrl = system->ports.data[p].types;

      for (q = 0; q < system->ports.data[p].num_types; q++, ctrl++)
      {
         mg_printf(conn, "%s{\"id\":%u,\"description\":\"%s\"}", comma, ctrl->id, ctrl->desc);
         comma = ",";
      }
   }

   mg_printf(conn, "],\"inputDescriptors\":[");
   comma = "";

   if (core_has_set_input_descriptor())
   {
      for (p = 0; p < settings->input.max_users; p++)
      {
         for (q = 0; q < RARCH_FIRST_CUSTOM_BIND; q++)
         {
            const char* description = system->input_desc_btn[p][q];

            if (description)
            {
               mg_printf(conn,
                     "%s{\"player\":%u,\"button\":\"%s\",\"description\":\"%s\"}",
                     comma,
                     p + 1,
                     libretro_btn_desc[q],
                     description
                     );

               comma = ",";
            }
         }
      }
   }

   mg_printf(conn, "],\"coreOptions\":[");
   rarch_ctl(RARCH_CTL_CORE_OPTIONS_LIST_GET, (void*)&core_opts);
   opts = core_opts->opts;

   for (p = 0; p < core_opts->size; p++, opts++)
   {
      mg_printf(conn, "%s{\"key\":\"%s\",\"description\":\"%s\",\"values\":[", p == 0 ? "" : ",", opts->key, opts->desc);
      comma = "";

      for (q = 0; q < opts->vals->size; q++)
      {
         mg_printf(conn, "%s\"%s\"", comma, opts->vals->elems[q].data);
         comma = ",";
      }

      mg_printf(conn, "]}");
   }

   mg_printf(conn, "]}");
   return 1;
}
コード例 #9
0
ファイル: task_screenshot.c プロジェクト: DSkywalk/RetroArch
/* Take frame bottom-up. */
static bool screenshot_dump(
      const char *name_base,
      const void *frame,
      unsigned width,
      unsigned height,
      int pitch, bool bgr24,
      void *userbuf, bool savestate,
      bool is_idle,
      bool is_paused,
      bool fullpath,
      bool use_thread)
{
   char screenshot_path[PATH_MAX_LENGTH];
   uint8_t *buf                   = NULL;
   settings_t *settings           = config_get_ptr();
   retro_task_t *task;
   screenshot_task_state_t *state;
   const char *screenshot_dir     = settings->paths.directory_screenshot;
   struct retro_system_info system_info;

   screenshot_path[0]             = '\0';

   if (!core_get_system_info(&system_info))
      return false;

   task = task_init();
   state = (screenshot_task_state_t*)calloc(1, sizeof(*state));
   state->shotname[0] = '\0';

   /* If fullpath is true, name_base already contains a static path + filename to save the screenshot to. */
   if (fullpath)
      strlcpy(state->filename, name_base, sizeof(state->filename));
   else
   {
      if (string_is_empty(screenshot_dir) || settings->bools.screenshots_in_content_dir)
      {
         fill_pathname_basedir(screenshot_path, name_base,
               sizeof(screenshot_path));
         screenshot_dir = screenshot_path;
      }
   }

   state->is_idle             = is_idle;
   state->is_paused           = is_paused;
   state->bgr24               = bgr24;
   state->height              = height;
   state->width               = width;
   state->pitch               = pitch;
   state->frame               = frame;
   state->userbuf             = userbuf;
   state->silence             = savestate;
   state->history_list_enable = settings->bools.history_list_enable;
   state->pixel_format_type   = video_driver_get_pixel_format();

   if (!fullpath)
   {
      if (savestate)
         snprintf(state->filename,
               sizeof(state->filename), "%s.png", name_base);
      else
      {
         if (settings->bools.auto_screenshot_filename)
         {
            const char *screenshot_name = NULL;

            if (path_is_empty(RARCH_PATH_CONTENT))
            {
               if (string_is_empty(system_info.library_name))
                  screenshot_name = "RetroArch";
               else
                  screenshot_name = system_info.library_name;
            }
            else
               screenshot_name = path_basename(name_base);

            fill_str_dated_filename(state->shotname, screenshot_name,
                  IMG_EXT, sizeof(state->shotname));
         }
         else
            snprintf(state->shotname, sizeof(state->shotname),
                  "%s.png", path_basename(name_base));

         fill_pathname_join(state->filename, screenshot_dir,
               state->shotname, sizeof(state->filename));
      }
   }

#if defined(HAVE_RPNG)
   buf = (uint8_t*)malloc(width * height * 3);
   if (!buf)
   {
      if (task)
         free(task);
      free(state);
      return false;
   }
   state->out_buffer = buf;
#endif

   task->type        = TASK_TYPE_BLOCKING;
   task->state       = state;
   task->handler     = task_screenshot_handler;

   if (use_thread)
   {
      if (!savestate)
         task->title = strdup(msg_hash_to_str(MSG_TAKING_SCREENSHOT));

      if (!task_queue_push(task))
      {
         /* There is already a blocking task going on */
         if (task->title)
            task_free_title(task);

         free(task);

         if (state->out_buffer)
            free(state->out_buffer);

         free(state);

         return false;
      }
   }
   else
   {
      if (task)
         free(task);
      return screenshot_dump_direct(state);
   }

   return true;
}