mame/src/osd/sdl/drawsdl.c

1142 lines
30 KiB
C

//============================================================
//
// drawsdl.c - SDL software and OpenGL implementation
//
// Copyright (c) 1996-2010, Nicola Salmoria and the MAME Team.
// Visit http://mamedev.org for licensing and usage restrictions.
//
// SDLMAME by Olivier Galibert and R. Belmont
//
//============================================================
// standard C headers
#include <math.h>
#include <stdio.h>
// MAME headers
#include "emu.h"
#include "ui.h"
// standard SDL headers
#include <SDL/SDL.h>
// OSD headers
#include "osdsdl.h"
#include "window.h"
//============================================================
// DEBUGGING
//============================================================
//============================================================
// CONSTANTS
//============================================================
//============================================================
// TYPES
//============================================================
typedef struct _sdl_scale_mode sdl_scale_mode;
/* sdl_info is the information about SDL for the current screen */
typedef struct _sdl_info sdl_info;
struct _sdl_info
{
INT32 blittimer;
UINT32 extra_flags;
#if (SDL_VERSION_ATLEAST(1,3,0))
SDL_TextureID texture_id;
#else
// SDL surface
SDL_Surface *sdlsurf;
SDL_Overlay *yuvsurf;
#endif
// YUV overlay
UINT32 *yuv_lookup;
UINT16 *yuv_bitmap;
// if we leave scaling to SDL and the underlying driver, this
// is the render_target_width/height to use
int hw_scale_width;
int hw_scale_height;
int last_hofs;
int last_vofs;
int old_blitwidth;
int old_blitheight;
// shortcut to scale mode info
const sdl_scale_mode *scale_mode;
};
struct _sdl_scale_mode
{
const char *name;
int is_scale; /* Scale mode? */
int is_yuv; /* Yuv mode? */
int mult_w; /* Width multiplier */
int mult_h; /* Height multiplier */
#if (!SDL_VERSION_ATLEAST(1,3,0))
int extra_flags; /* Texture/surface flags */
#else
int sdl_scale_mode; /* sdl 1.3 scale mode */
#endif
int pixel_format; /* Pixel/Overlay format */
void (*yuv_blit)(UINT16 *bitmap, sdl_info *sdl, UINT8 *ptr, int pitch);
};
//============================================================
// INLINES
//============================================================
//============================================================
// PROTOTYPES
//============================================================
// core functions
static void drawsdl_exit(void);
static void drawsdl_attach(sdl_draw_info *info, sdl_window_info *window);
static int drawsdl_window_create(sdl_window_info *window, int width, int height);
static void drawsdl_window_resize(sdl_window_info *window, int width, int height);
static void drawsdl_window_destroy(sdl_window_info *window);
static render_primitive_list &drawsdl_window_get_primitives(sdl_window_info *window);
static int drawsdl_window_draw(sdl_window_info *window, UINT32 dc, int update);
static void drawsdl_destroy_all_textures(sdl_window_info *window);
static void drawsdl_window_clear(sdl_window_info *window);
static int drawsdl_xy_to_render_target(sdl_window_info *window, int x, int y, int *xt, int *yt);
#if (SDL_VERSION_ATLEAST(1,3,0))
static void setup_texture(sdl_window_info *window, int tempwidth, int tempheight);
#endif
// soft rendering
static void drawsdl_rgb888_draw_primitives(const render_primitive_list &primlist, void *dstdata, UINT32 width, UINT32 height, UINT32 pitch);
static void drawsdl_bgr888_draw_primitives(const render_primitive_list &primlist, void *dstdata, UINT32 width, UINT32 height, UINT32 pitch);
static void drawsdl_bgra888_draw_primitives(const render_primitive_list &primlist, void *dstdata, UINT32 width, UINT32 height, UINT32 pitch);
static void drawsdl_rgb565_draw_primitives(const render_primitive_list &primlist, void *dstdata, UINT32 width, UINT32 height, UINT32 pitch);
static void drawsdl_rgb555_draw_primitives(const render_primitive_list &primlist, void *dstdata, UINT32 width, UINT32 height, UINT32 pitch);
// YUV overlays
static void drawsdl_yuv_init(sdl_info *sdl);
static void yuv_RGB_to_YV12(UINT16 *bitmap, sdl_info *sdl, UINT8 *ptr, int pitch);
static void yuv_RGB_to_YV12X2(UINT16 *bitmap, sdl_info *sdl, UINT8 *ptr, int pitch);
static void yuv_RGB_to_YUY2(UINT16 *bitmap, sdl_info *sdl, UINT8 *ptr, int pitch);
static void yuv_RGB_to_YUY2X2(UINT16 *bitmap, sdl_info *sdl, UINT8 *ptr, int pitch);
// Static declarations
#if (!SDL_VERSION_ATLEAST(1,3,0))
static int shown_video_info = 0;
static const sdl_scale_mode scale_modes[] =
{
{ "none", 0, 0, 0, 0, SDL_DOUBLEBUF, 0, 0 },
{ "async", 0, 0, 0, 0, SDL_DOUBLEBUF | SDL_ASYNCBLIT, 0, 0 },
{ "yv12", 1, 1, 1, 1, 0, SDL_YV12_OVERLAY, yuv_RGB_to_YV12 },
{ "yv12x2", 1, 1, 2, 2, 0, SDL_YV12_OVERLAY, yuv_RGB_to_YV12X2 },
{ "yuy2", 1, 1, 1, 1, 0, SDL_YUY2_OVERLAY, yuv_RGB_to_YUY2 },
{ "yuy2x2", 1, 1, 2, 1, 0, SDL_YUY2_OVERLAY, yuv_RGB_to_YUY2X2 },
{ NULL }
};
#else
static const sdl_scale_mode scale_modes[] =
{
{ "none", 0, 0, 0, 0, SDL_TEXTURESCALEMODE_NONE, 0, 0 },
{ "hwblit", 1, 0, 1, 1, SDL_TEXTURESCALEMODE_FAST, 0, 0 },
{ "hwbest", 1, 0, 1, 1, SDL_TEXTURESCALEMODE_BEST, 0, 0 },
{ "yv12", 1, 1, 1, 1, SDL_TEXTURESCALEMODE_NONE, SDL_PIXELFORMAT_YV12, yuv_RGB_to_YV12 },
{ "yv12x2", 1, 1, 2, 2, SDL_TEXTURESCALEMODE_NONE, SDL_PIXELFORMAT_YV12, yuv_RGB_to_YV12X2 },
{ "yuy2", 1, 1, 1, 1, SDL_TEXTURESCALEMODE_NONE, SDL_PIXELFORMAT_YUY2, yuv_RGB_to_YUY2 },
{ "yuy2x2", 1, 1, 2, 1, SDL_TEXTURESCALEMODE_NONE, SDL_PIXELFORMAT_YUY2, yuv_RGB_to_YUY2X2 },
{ NULL }
};
#endif
//============================================================
// drawsdl_scale_mode
//============================================================
const char *drawsdl_scale_mode_str(int index)
{
const sdl_scale_mode *sm = scale_modes;
while (index>0)
{
if (sm->name == NULL)
return NULL;
index--;
sm++;
}
return sm->name;
};
int drawsdl_scale_mode(const char *s)
{
const sdl_scale_mode *sm = scale_modes;
int index;
index = 0;
while (sm->name != NULL)
{
if (strcmp(sm->name, s) == 0)
return index;
index++;
sm++;
}
return -1;
}
//============================================================
// drawsdl_init
//============================================================
int drawsdl_init(sdl_draw_info *callbacks)
{
// fill in the callbacks
callbacks->exit = drawsdl_exit;
callbacks->attach = drawsdl_attach;
if (SDL_VERSION_ATLEAST(1,3,0))
mame_printf_verbose("Using SDL multi-window soft driver (SDL 1.3+)\n");
else
mame_printf_verbose("Using SDL single-window soft driver (SDL 1.2)\n");
return 0;
}
//============================================================
// drawsdl_exit
//============================================================
static void drawsdl_exit(void)
{
}
//============================================================
// drawsdl_attach
//============================================================
static void drawsdl_attach(sdl_draw_info *info, sdl_window_info *window)
{
// fill in the callbacks
window->create = drawsdl_window_create;
window->resize = drawsdl_window_resize;
window->get_primitives = drawsdl_window_get_primitives;
window->draw = drawsdl_window_draw;
window->destroy = drawsdl_window_destroy;
window->destroy_all_textures = drawsdl_destroy_all_textures;
window->clear = drawsdl_window_clear;
window->xy_to_render_target = drawsdl_xy_to_render_target;
}
//============================================================
// drawsdl_destroy_all_textures
//============================================================
static void drawsdl_destroy_all_textures(sdl_window_info *window)
{
/* nothing to be done in soft mode */
}
//============================================================
// setup_texture for window
//============================================================
#if (SDL_VERSION_ATLEAST(1,3,0))
static void setup_texture(sdl_window_info *window, int tempwidth, int tempheight)
{
sdl_info *sdl = (sdl_info *) window->dxdata;
const sdl_scale_mode *sdl_sm = sdl->scale_mode;
SDL_DisplayMode mode;
UINT32 fmt;
// Determine preferred pixelformat and set up yuv if necessary
SDL_GetCurrentDisplayMode(&mode);
if (sdl->yuv_bitmap)
{
global_free(sdl->yuv_bitmap);
sdl->yuv_bitmap = NULL;
}
if (sdl_sm->is_scale)
{
window->target->compute_minimum_size(sdl->hw_scale_width, sdl->hw_scale_height);
if (video_config.prescale)
{
sdl->hw_scale_width *= video_config.prescale;
sdl->hw_scale_height *= video_config.prescale;
}
}
if (sdl_sm->is_yuv)
sdl->yuv_bitmap = global_alloc_array(UINT16, sdl->hw_scale_width * sdl->hw_scale_height);
fmt = (sdl_sm->pixel_format ? sdl_sm->pixel_format : mode.format);
if (sdl_sm->is_scale)
{
int w = sdl->hw_scale_width * sdl_sm->mult_w;
int h = sdl->hw_scale_height * sdl_sm->mult_h;
sdl->texture_id = SDL_CreateTexture(fmt, SDL_TEXTUREACCESS_STREAMING, w, h);
}
else
{
sdl->texture_id = SDL_CreateTexture(fmt, SDL_TEXTUREACCESS_STREAMING,
tempwidth, tempheight);
}
SDL_SetTextureScaleMode(sdl->texture_id, sdl_sm->sdl_scale_mode);
}
#endif
//============================================================
// yuv_overlay_init
//============================================================
#if (!SDL_VERSION_ATLEAST(1,3,0))
static void yuv_overlay_init(sdl_window_info *window)
{
sdl_info *sdl = (sdl_info *) window->dxdata;
const sdl_scale_mode *sdl_sm = sdl->scale_mode;
int minimum_width, minimum_height;
window->target->compute_minimum_size(minimum_width, minimum_height);
if (video_config.prescale)
{
minimum_width *= video_config.prescale;
minimum_height *= video_config.prescale;
}
if (sdl->yuvsurf != NULL)
{
SDL_FreeYUVOverlay(sdl->yuvsurf);
sdl->yuvsurf = NULL;
}
if (sdl->yuv_bitmap != NULL)
{
global_free(sdl->yuv_bitmap);
}
mame_printf_verbose("SDL: Creating %d x %d YUV-Overlay ...\n", minimum_width, minimum_height);
sdl->yuv_bitmap = global_alloc_array(UINT16, minimum_width*minimum_height);
sdl->yuvsurf = SDL_CreateYUVOverlay(minimum_width * sdl_sm->mult_w, minimum_height * sdl_sm->mult_h,
sdl_sm->pixel_format, sdl->sdlsurf);
if ( sdl->yuvsurf == NULL ) {
mame_printf_error("SDL: Couldn't create SDL_yuv_overlay: %s\n", SDL_GetError());
//return 1;
}
sdl->hw_scale_width = minimum_width;
sdl->hw_scale_height = minimum_height;
if (!shown_video_info)
{
mame_printf_verbose("YUV Mode : %s\n", sdl_sm->name);
mame_printf_verbose("YUV Overlay Size : %d x %d\n", minimum_width, minimum_height);
mame_printf_verbose("YUV Acceleration : %s\n", sdl->yuvsurf->hw_overlay ? "Hardware" : "Software");
shown_video_info = 1;
}
}
#endif
//============================================================
// drawsdl_show_info
//============================================================
#if (SDL_VERSION_ATLEAST(1,3,0))
static void drawsdl_show_info(sdl_window_info *window, struct SDL_RendererInfo *render_info)
{
#define RF_ENTRY(x) {x, #x }
static struct {
int flag;
const char *name;
} rflist[] =
{
RF_ENTRY(SDL_RENDERER_SINGLEBUFFER),
RF_ENTRY(SDL_RENDERER_PRESENTCOPY),
RF_ENTRY(SDL_RENDERER_PRESENTFLIP2),
RF_ENTRY(SDL_RENDERER_PRESENTFLIP3),
RF_ENTRY(SDL_RENDERER_PRESENTDISCARD),
RF_ENTRY(SDL_RENDERER_PRESENTVSYNC),
RF_ENTRY(SDL_RENDERER_ACCELERATED),
{-1, NULL}
};
int i;
mame_printf_verbose("window: using renderer %s\n", render_info->name ? render_info->name : "<unknown>");
for (i = 0; rflist[i].name != NULL; i++)
if (render_info->flags & rflist[i].flag)
mame_printf_verbose("renderer: flag %s\n", rflist[i].name);
}
#endif
//============================================================
// drawsdl_window_create
//============================================================
static int drawsdl_window_create(sdl_window_info *window, int width, int height)
{
sdl_info *sdl;
// allocate memory for our structures
sdl = (sdl_info *) osd_malloc(sizeof(sdl_info));
memset(sdl, 0, sizeof(sdl_info));
window->dxdata = sdl;
sdl->scale_mode = &scale_modes[window->scale_mode];
#if (SDL_VERSION_ATLEAST(1,3,0))
sdl->extra_flags = (window->fullscreen ?
SDL_WINDOW_BORDERLESS | SDL_WINDOW_INPUT_FOCUS | SDL_WINDOW_MOUSE_FOCUS
| SDL_WINDOW_INPUT_GRABBED : SDL_WINDOW_RESIZABLE);
SDL_SelectVideoDisplay(window->monitor->handle);
if (window->fullscreen && video_config.switchres)
{
SDL_DisplayMode mode;
SDL_GetCurrentDisplayMode(&mode);
mode.w = width;
mode.h = height;
if (window->refresh)
mode.refresh_rate = window->refresh;
SDL_SetWindowDisplayMode(window->sdl_window, &mode); // Try to set mode
}
else
SDL_SetWindowDisplayMode(window->sdl_window, NULL); // Use desktop
window->sdl_window = SDL_CreateWindow(window->title, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
width, height, sdl->extra_flags);
SDL_ShowWindow(window->sdl_window);
SDL_SetWindowFullscreen(window->sdl_window, window->fullscreen);
SDL_GetWindowSize(window->sdl_window, &window->width, &window->height);
SDL_RaiseWindow(window->sdl_window);
/* FIXME: Bug in SDL 1.3 */
if (window->fullscreen)
SDL_SetWindowGrab(window->sdl_window, 1);
// create a texture
if (video_config.waitvsync)
SDL_CreateRenderer(window->sdl_window, -1, SDL_RENDERER_PRESENTFLIP2 | SDL_RENDERER_PRESENTDISCARD | SDL_RENDERER_PRESENTVSYNC);
else
SDL_CreateRenderer(window->sdl_window, -1, SDL_RENDERER_PRESENTFLIP2 | SDL_RENDERER_PRESENTDISCARD);
SDL_SelectRenderer(window->sdl_window);
{
struct SDL_RendererInfo render_info;
SDL_GetRendererInfo(&render_info);
drawsdl_show_info(window, &render_info);
// Check scale mode
if (sdl->scale_mode->pixel_format)
{
int i;
int found = 0;
for (i=0; i < render_info.num_texture_formats; i++)
if (sdl->scale_mode->pixel_format == render_info.texture_formats[i])
found = 1;
if (!found)
{
mame_printf_verbose("window: Scale mode %s not supported! Using default.\n", sdl->scale_mode->name);
ui_popup_time(3, "Scale mode %s not supported! Using default.", sdl->scale_mode->name);
sdl->scale_mode = &scale_modes[0];
}
}
}
setup_texture(window, width, height);
#else
sdl->extra_flags = (window->fullscreen ? SDL_FULLSCREEN : SDL_RESIZABLE);
sdl->extra_flags |= sdl->scale_mode->extra_flags;
sdl->sdlsurf = SDL_SetVideoMode(width, height,
0, SDL_SWSURFACE | SDL_ANYFORMAT | sdl->extra_flags);
if (!sdl->sdlsurf)
return 1;
window->width = sdl->sdlsurf->w;
window->height = sdl->sdlsurf->h;
if (sdl->scale_mode->is_yuv)
yuv_overlay_init(window);
// set the window title
SDL_WM_SetCaption(window->title, "SDLMAME");
#endif
sdl->yuv_lookup = NULL;
sdl->blittimer = 0;
drawsdl_yuv_init(sdl);
return 0;
}
//============================================================
// drawsdl_window_resize
//============================================================
static void drawsdl_window_resize(sdl_window_info *window, int width, int height)
{
#if (SDL_VERSION_ATLEAST(1,3,0))
SDL_SetWindowSize(window->sdl_window, width, height);
SDL_GetWindowSize(window->sdl_window, &window->width, &window->height);
#else
sdl_info *sdl = (sdl_info *) window->dxdata;
if (sdl->yuvsurf != NULL)
{
SDL_FreeYUVOverlay(sdl->yuvsurf);
sdl->yuvsurf = NULL;
}
SDL_FreeSurface(sdl->sdlsurf);
//printf("SetVideoMode %d %d\n", wp->resize_new_width, wp->resize_new_height);
sdl->sdlsurf = SDL_SetVideoMode(width, height, 0,
SDL_SWSURFACE | SDL_ANYFORMAT | sdl->extra_flags);
window->width = sdl->sdlsurf->w;
window->height = sdl->sdlsurf->h;
if (sdl->scale_mode->is_yuv)
{
yuv_overlay_init(window);
}
#endif
}
//============================================================
// drawsdl_window_destroy
//============================================================
static void drawsdl_window_destroy(sdl_window_info *window)
{
sdl_info *sdl = (sdl_info *) window->dxdata;
// skip if nothing
if (sdl == NULL)
return;
#if (SDL_VERSION_ATLEAST(1,3,0))
SDL_SelectRenderer(window->sdl_window);
SDL_DestroyTexture(sdl->texture_id);
//SDL_DestroyRenderer(window->sdl_window);
SDL_DestroyWindow(window->sdl_window);
#else
if (sdl->yuvsurf != NULL)
{
SDL_FreeYUVOverlay(sdl->yuvsurf);
sdl->yuvsurf = NULL;
}
if (sdl->sdlsurf)
{
SDL_FreeSurface(sdl->sdlsurf);
sdl->sdlsurf = NULL;
}
#endif
// free the memory in the window
if (sdl->yuv_lookup != NULL)
{
global_free(sdl->yuv_lookup);
sdl->yuv_lookup = NULL;
}
if (sdl->yuv_bitmap != NULL)
{
global_free(sdl->yuv_bitmap);
sdl->yuv_bitmap = NULL;
}
osd_free(sdl);
window->dxdata = NULL;
}
//============================================================
// drawsdl_window_clear
//============================================================
static void drawsdl_window_clear(sdl_window_info *window)
{
sdl_info *sdl = (sdl_info *) window->dxdata;
sdl->blittimer = 3;
}
//============================================================
// drawsdl_xy_to_render_target
//============================================================
static int drawsdl_xy_to_render_target(sdl_window_info *window, int x, int y, int *xt, int *yt)
{
sdl_info *sdl = (sdl_info *) window->dxdata;
*xt = x - sdl->last_hofs;
*yt = y - sdl->last_vofs;
if (*xt<0 || *xt >= window->blitwidth)
return 0;
if (*yt<0 || *xt >= window->blitheight)
return 0;
if (!sdl->scale_mode->is_scale)
{
return 1;
}
/* Rescale */
*xt = (*xt * sdl->hw_scale_width) / window->blitwidth;
*yt = (*yt * sdl->hw_scale_height) / window->blitheight;
return 1;
}
//============================================================
// drawsdl_window_get_primitives
//============================================================
static render_primitive_list &drawsdl_window_get_primitives(sdl_window_info *window)
{
sdl_info *sdl = (sdl_info *) window->dxdata;
if ((!window->fullscreen) || (video_config.switchres))
{
sdlwindow_blit_surface_size(window, window->width, window->height);
}
else
{
sdlwindow_blit_surface_size(window, window->monitor->center_width, window->monitor->center_height);
}
if (!sdl->scale_mode->is_scale)
window->target->set_bounds(window->blitwidth, window->blitheight, sdlvideo_monitor_get_aspect(window->monitor));
else
window->target->set_bounds(sdl->hw_scale_width, sdl->hw_scale_height);
return window->target->get_primitives();
}
//============================================================
// drawsdl_window_draw
//============================================================
static int drawsdl_window_draw(sdl_window_info *window, UINT32 dc, int update)
{
sdl_info *sdl = (sdl_info *) window->dxdata;
UINT8 *surfptr;
INT32 pitch;
int bpp;
Uint32 rmask, gmask, bmask, amask;
INT32 vofs, hofs, blitwidth, blitheight, ch, cw;
if (video_config.novideo)
{
return 0;
}
// if we haven't been created, just punt
if (sdl == NULL)
return 1;
// lock it if we need it
#if (!SDL_VERSION_ATLEAST(1,3,0))
pitch = sdl->sdlsurf->pitch;
bpp = sdl->sdlsurf->format->BytesPerPixel;
rmask = sdl->sdlsurf->format->Rmask;
gmask = sdl->sdlsurf->format->Gmask;
bmask = sdl->sdlsurf->format->Bmask;
amask = sdl->sdlsurf->format->Amask;
if (window->blitwidth != sdl->old_blitwidth || window->blitheight != sdl->old_blitheight)
{
if (sdl->scale_mode->is_yuv)
yuv_overlay_init(window);
sdl->old_blitwidth = window->blitwidth;
sdl->old_blitheight = window->blitheight;
sdl->blittimer = 3;
}
if (SDL_MUSTLOCK(sdl->sdlsurf)) SDL_LockSurface(sdl->sdlsurf);
// Clear if necessary
if (sdl->blittimer > 0)
{
memset(sdl->sdlsurf->pixels, 0, window->height * sdl->sdlsurf->pitch);
sdl->blittimer--;
}
if (sdl->scale_mode->is_yuv)
{
SDL_LockYUVOverlay(sdl->yuvsurf);
surfptr = sdl->yuvsurf->pixels[0]; // (UINT8 *) sdl->yuv_bitmap;
pitch = sdl->yuvsurf->pitches[0]; // (UINT8 *) sdl->yuv_bitmap;
}
else
surfptr = (UINT8 *)sdl->sdlsurf->pixels;
#else
SDL_SelectRenderer(window->sdl_window);
if (window->blitwidth != sdl->old_blitwidth || window->blitheight != sdl->old_blitheight)
{
SDL_DestroyTexture(sdl->texture_id);
setup_texture(window, window->blitwidth, window->blitheight);
sdl->old_blitwidth = window->blitwidth;
sdl->old_blitheight = window->blitheight;
sdl->blittimer = 3;
}
{
Uint32 format;
int access, w, h;
SDL_QueryTexture(sdl->texture_id, &format, &access, &w, &h);
SDL_PixelFormatEnumToMasks(format, &bpp, &rmask, &gmask, &bmask, &amask);
bpp = bpp / 8; /* convert to bytes per pixels */
}
// Clear if necessary
if (sdl->blittimer > 0)
{
/* SDL Underlays need alpha = 0 ! */
SDL_SetRenderDrawColor(0,0,0,0);
SDL_RenderFillRect(NULL);
//SDL_RenderFill(0,0,0,0 /*255*/,NULL);
sdl->blittimer--;
}
SDL_LockTexture(sdl->texture_id, NULL, 1, (void **) &surfptr, &pitch);
#endif
// get ready to center the image
vofs = hofs = 0;
blitwidth = window->blitwidth;
blitheight = window->blitheight;
// figure out what coordinate system to use for centering - in window mode it's always the
// SDL surface size. in fullscreen the surface covers all monitors, so center according to
// the first one only
if ((window->fullscreen) && (!video_config.switchres))
{
ch = window->monitor->center_height;
cw = window->monitor->center_width;
}
else
{
ch = window->height;
cw = window->width;
}
// do not crash if the window's smaller than the blit area
if (blitheight > ch)
{
blitheight = ch;
}
else if (video_config.centerv)
{
vofs = (ch - window->blitheight) / 2;
}
if (blitwidth > cw)
{
blitwidth = cw;
}
else if (video_config.centerh)
{
hofs = (cw - window->blitwidth) / 2;
}
sdl->last_hofs = hofs;
sdl->last_vofs = vofs;
window->primlist->acquire_lock();
// render to it
if (!sdl->scale_mode->is_yuv)
{
int mamewidth, mameheight;
if (!sdl->scale_mode->is_scale)
{
mamewidth = blitwidth;
mameheight = blitheight;
#if !SDL_VERSION_ATLEAST(1,3,0)
surfptr += ((vofs * pitch) + (hofs * bpp));
#endif
}
else
{
mamewidth = sdl->hw_scale_width;
mameheight = sdl->hw_scale_height;
}
switch (rmask)
{
case 0x0000ff00:
drawsdl_bgra888_draw_primitives(*window->primlist, surfptr, mamewidth, mameheight, pitch / 4);
break;
case 0x00ff0000:
drawsdl_rgb888_draw_primitives(*window->primlist, surfptr, mamewidth, mameheight, pitch / 4);
break;
case 0x000000ff:
drawsdl_bgr888_draw_primitives(*window->primlist, surfptr, mamewidth, mameheight, pitch / 4);
break;
case 0xf800:
drawsdl_rgb565_draw_primitives(*window->primlist, surfptr, mamewidth, mameheight, pitch / 2);
break;
case 0x7c00:
drawsdl_rgb555_draw_primitives(*window->primlist, surfptr, mamewidth, mameheight, pitch / 2);
break;
default:
mame_printf_error("SDL: ERROR! Unknown video mode: R=%08X G=%08X B=%08X\n", rmask, gmask, bmask);
break;
}
}
else
{
assert (sdl->yuv_bitmap != NULL);
assert (surfptr != NULL);
drawsdl_rgb555_draw_primitives(*window->primlist, sdl->yuv_bitmap, sdl->hw_scale_width, sdl->hw_scale_height, sdl->hw_scale_width);
sdl->scale_mode->yuv_blit((UINT16 *)sdl->yuv_bitmap, sdl, surfptr, pitch);
}
window->primlist->release_lock();
// unlock and flip
#if (!SDL_VERSION_ATLEAST(1,3,0))
if (SDL_MUSTLOCK(sdl->sdlsurf)) SDL_UnlockSurface(sdl->sdlsurf);
if (!sdl->scale_mode->is_yuv)
{
SDL_Flip(sdl->sdlsurf);
}
else
{
SDL_Rect r;
SDL_UnlockYUVOverlay(sdl->yuvsurf);
r.x=hofs;
r.y=vofs;
r.w=blitwidth;
r.h=blitheight;
SDL_DisplayYUVOverlay(sdl->yuvsurf, &r);
}
#else
SDL_UnlockTexture(sdl->texture_id);
{
SDL_Rect r;
r.x=hofs;
r.y=vofs;
r.w=blitwidth;
r.h=blitheight;
//printf("blitwidth %d %d - %d %d\n", blitwidth, blitheight, window->width, window->height);
//SDL_UpdateTexture(sdl->sdltex, NULL, sdl->sdlsurf->pixels, pitch);
SDL_RenderCopy(sdl->texture_id, NULL, &r);
SDL_RenderPresent();
}
#endif
return 0;
}
//============================================================
// SOFTWARE RENDERING
//============================================================
#define FUNC_PREFIX(x) drawsdl_rgb888_##x
#define PIXEL_TYPE UINT32
#define SRCSHIFT_R 0
#define SRCSHIFT_G 0
#define SRCSHIFT_B 0
#define DSTSHIFT_R 16
#define DSTSHIFT_G 8
#define DSTSHIFT_B 0
#include "rendersw.c"
#define FUNC_PREFIX(x) drawsdl_bgr888_##x
#define PIXEL_TYPE UINT32
#define SRCSHIFT_R 0
#define SRCSHIFT_G 0
#define SRCSHIFT_B 0
#define DSTSHIFT_R 0
#define DSTSHIFT_G 8
#define DSTSHIFT_B 16
#include "rendersw.c"
#define FUNC_PREFIX(x) drawsdl_bgra888_##x
#define PIXEL_TYPE UINT32
#define SRCSHIFT_R 0
#define SRCSHIFT_G 0
#define SRCSHIFT_B 0
#define DSTSHIFT_R 8
#define DSTSHIFT_G 16
#define DSTSHIFT_B 24
#include "rendersw.c"
#define FUNC_PREFIX(x) drawsdl_rgb565_##x
#define PIXEL_TYPE UINT16
#define SRCSHIFT_R 3
#define SRCSHIFT_G 2
#define SRCSHIFT_B 3
#define DSTSHIFT_R 11
#define DSTSHIFT_G 5
#define DSTSHIFT_B 0
#include "rendersw.c"
#define FUNC_PREFIX(x) drawsdl_rgb555_##x
#define PIXEL_TYPE UINT16
#define SRCSHIFT_R 3
#define SRCSHIFT_G 3
#define SRCSHIFT_B 3
#define DSTSHIFT_R 10
#define DSTSHIFT_G 5
#define DSTSHIFT_B 0
#include "rendersw.c"
//============================================================
// YUV Blitting
//============================================================
#define CU_CLAMP(v, a, b) ((v < a)? a: ((v > b)? b: v))
#define RGB2YUV_F(r,g,b,y,u,v) \
(y) = (0.299*(r) + 0.587*(g) + 0.114*(b) ); \
(u) = (-0.169*(r) - 0.331*(g) + 0.5*(b) + 128); \
(v) = (0.5*(r) - 0.419*(g) - 0.081*(b) + 128); \
(y) = CU_CLAMP(y,0,255); \
(u) = CU_CLAMP(u,0,255); \
(v) = CU_CLAMP(v,0,255)
#define RGB2YUV(r,g,b,y,u,v) \
(y) = (( 8453*(r) + 16594*(g) + 3223*(b) + 524288) >> 15); \
(u) = (( -4878*(r) - 9578*(g) + 14456*(b) + 4210688) >> 15); \
(v) = (( 14456*(r) - 12105*(g) - 2351*(b) + 4210688) >> 15)
#ifdef LSB_FIRST
#define Y1MASK 0x000000FF
#define UMASK 0x0000FF00
#define Y2MASK 0x00FF0000
#define VMASK 0xFF000000
#define Y1SHIFT 0
#define USHIFT 8
#define Y2SHIFT 16
#define VSHIFT 24
#else
#define Y1MASK 0xFF000000
#define UMASK 0x00FF0000
#define Y2MASK 0x0000FF00
#define VMASK 0x000000FF
#define Y1SHIFT 24
#define USHIFT 16
#define Y2SHIFT 8
#define VSHIFT 0
#endif
#define YMASK (Y1MASK|Y2MASK)
#define UVMASK (UMASK|VMASK)
static void yuv_lookup_set(sdl_info *sdl, unsigned int pen, unsigned char red,
unsigned char green, unsigned char blue)
{
UINT32 y,u,v;
RGB2YUV(red,green,blue,y,u,v);
/* Storing this data in YUYV order simplifies using the data for
YUY2, both with and without smoothing... */
sdl->yuv_lookup[pen]=(y<<Y1SHIFT)|(u<<USHIFT)|(y<<Y2SHIFT)|(v<<VSHIFT);
}
static void drawsdl_yuv_init(sdl_info *sdl)
{
unsigned char r,g,b;
if (sdl->yuv_lookup == NULL)
sdl->yuv_lookup = global_alloc_array(UINT32, 65536);
for (r = 0; r < 32; r++)
for (g = 0; g < 32; g++)
for (b = 0; b < 32; b++)
{
int idx = (r << 10) | (g << 5) | b;
yuv_lookup_set(sdl, idx,
(r << 3) | (r >> 2),
(g << 3) | (g >> 2),
(b << 3) | (b >> 2));
}
}
static void yuv_RGB_to_YV12(UINT16 *bitmap, sdl_info *sdl, UINT8 *ptr, int pitch)
{
int x, y;
UINT8 *dest_y;
UINT8 *dest_u;
UINT8 *dest_v;
UINT16 *src;
UINT16 *src2;
UINT32 *lookup = sdl->yuv_lookup;
UINT8 *pixels[3];
int u1,v1,y1,u2,v2,y2,u3,v3,y3,u4,v4,y4; /* 12 */
pixels[0] = ptr;
pixels[1] = ptr + pitch * sdl->hw_scale_height;
pixels[2] = pixels[1] + pitch * sdl->hw_scale_height / 4;
for(y=0;y<sdl->hw_scale_height;y+=2)
{
src=bitmap + (y * sdl->hw_scale_width) ;
src2=src + sdl->hw_scale_width;
dest_y = pixels[0] + y * pitch;
dest_v = pixels[1] + (y>>1) * pitch / 2;
dest_u = pixels[2] + (y>>1) * pitch / 2;
for(x=0;x<sdl->hw_scale_width;x+=2)
{
v1 = lookup[src[x]];
y1 = (v1>>Y1SHIFT) & 0xff;
u1 = (v1>>USHIFT) & 0xff;
v1 = (v1>>VSHIFT) & 0xff;
v2 = lookup[src[x+1]];
y2 = (v2>>Y1SHIFT) & 0xff;
u2 = (v2>>USHIFT) & 0xff;
v2 = (v2>>VSHIFT) & 0xff;
v3 = lookup[src2[x]];
y3 = (v3>>Y1SHIFT) & 0xff;
u3 = (v3>>USHIFT) & 0xff;
v3 = (v3>>VSHIFT) & 0xff;
v4 = lookup[src2[x+1]];
y4 = (v4>>Y1SHIFT) & 0xff;
u4 = (v4>>USHIFT) & 0xff;
v4 = (v4>>VSHIFT) & 0xff;
dest_y[x] = y1;
dest_y[x+pitch] = y3;
dest_y[x+1] = y2;
dest_y[x+pitch+1] = y4;
dest_u[x>>1] = (u1+u2+u3+u4)/4;
dest_v[x>>1] = (v1+v2+v3+v4)/4;
}
}
}
static void yuv_RGB_to_YV12X2(UINT16 *bitmap, sdl_info *sdl, UINT8 *ptr, int pitch)
{
/* this one is used when scale==2 */
unsigned int x,y;
UINT16 *dest_y;
UINT8 *dest_u;
UINT8 *dest_v;
UINT16 *src;
int u1,v1,y1;
UINT8 *pixels[3];
pixels[0] = ptr;
pixels[1] = ptr + pitch * sdl->hw_scale_height * 2;
pixels[2] = pixels[1] + pitch * sdl->hw_scale_height / 2;
for(y=0;y<sdl->hw_scale_height;y++)
{
src = bitmap + (y * sdl->hw_scale_width) ;
dest_y = (UINT16 *)(pixels[0] + 2 * y * pitch);
dest_v = pixels[1] + y * pitch / 2;
dest_u = pixels[2] + y * pitch / 2;
for(x=0;x<sdl->hw_scale_width;x++)
{
v1 = sdl->yuv_lookup[src[x]];
y1 = (v1 >> Y1SHIFT) & 0xff;
u1 = (v1 >> USHIFT) & 0xff;
v1 = (v1 >> VSHIFT) & 0xff;
dest_y[x + pitch/2] = y1 << 8 | y1;
dest_y[x] = y1 << 8 | y1;
dest_u[x] = u1;
dest_v[x] = v1;
}
}
}
static void yuv_RGB_to_YUY2(UINT16 *bitmap, sdl_info *sdl, UINT8 *ptr, int pitch)
{
/* this one is used when scale==2 */
unsigned int y;
UINT32 *dest;
UINT16 *src;
UINT16 *end;
UINT32 p1,p2,uv;
UINT32 *lookup = sdl->yuv_lookup;
int yuv_pitch = pitch/4;
for(y=0;y<sdl->hw_scale_height;y++)
{
src=bitmap + (y * sdl->hw_scale_width) ;
end=src+sdl->hw_scale_width;
dest = (UINT32 *) ptr;
dest += y * yuv_pitch;
for(; src<end; src+=2)
{
p1 = lookup[src[0]];
p2 = lookup[src[1]];
uv = (p1&UVMASK)>>1;
uv += (p2&UVMASK)>>1;
*dest++ = (p1&Y1MASK)|(p2&Y2MASK)|(uv&UVMASK);
}
}
}
static void yuv_RGB_to_YUY2X2(UINT16 *bitmap, sdl_info *sdl, UINT8 *ptr, int pitch)
{
/* this one is used when scale==2 */
unsigned int y;
UINT32 *dest;
UINT16 *src;
UINT16 *end;
UINT32 *lookup = sdl->yuv_lookup;
int yuv_pitch = pitch / 4;
for(y=0;y<sdl->hw_scale_height;y++)
{
src=bitmap + (y * sdl->hw_scale_width) ;
end=src+sdl->hw_scale_width;
dest = (UINT32 *) ptr;
dest += (y * yuv_pitch);
for(; src<end; src++)
{
dest[0] = lookup[src[0]];
dest++;
}
}
}