summaryrefslogtreecommitdiffstatshomepage
path: root/src/osd/modules/render/drawsdl.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/osd/modules/render/drawsdl.cpp')
-rw-r--r--src/osd/modules/render/drawsdl.cpp1021
1 files changed, 1021 insertions, 0 deletions
diff --git a/src/osd/modules/render/drawsdl.cpp b/src/osd/modules/render/drawsdl.cpp
new file mode 100644
index 00000000000..afd2057e0c5
--- /dev/null
+++ b/src/osd/modules/render/drawsdl.cpp
@@ -0,0 +1,1021 @@
+// license:BSD-3-Clause
+// copyright-holders:Couriersud, Olivier Galibert, R. Belmont
+//============================================================
+//
+// drawsdl.c - SDL software and OpenGL implementation
+//
+// SDLMAME by Olivier Galibert and R. Belmont
+//
+// yuvmodes by Couriersud
+//
+//============================================================
+
+// standard C headers
+#include <math.h>
+#include <stdio.h>
+
+// MAME headers
+#include "emu.h"
+#include "ui/ui.h"
+#include "rendersw.inc"
+
+// standard SDL headers
+#include "sdlinc.h"
+
+// OSD headers
+#include "osdsdl.h"
+#include "window.h"
+
+//============================================================
+// DEBUGGING
+//============================================================
+
+//============================================================
+// CONSTANTS
+//============================================================
+
+//============================================================
+// TYPES
+//============================================================
+
+struct sdl_scale_mode;
+
+#if (SDLMAME_SDL2)
+#define DRAW2_SCALEMODE_NEAREST "0"
+#define DRAW2_SCALEMODE_LINEAR "1"
+#define DRAW2_SCALEMODE_BEST "2"
+#endif
+
+/* sdl_info is the information about SDL for the current screen */
+class sdl_info : public osd_renderer
+{
+public:
+
+ sdl_info(osd_window *w, int extra_flags)
+ : osd_renderer(w, extra_flags),
+ #if (SDLMAME_SDL2)
+ m_sdl_renderer(NULL),
+ m_texture_id(NULL),
+ #else
+ m_yuvsurf(NULL),
+ #endif
+ m_yuv_lookup(NULL),
+ m_yuv_bitmap(NULL),
+ //m_hw_scale_width(0),
+ //m_hw_scale_height(0),
+ m_last_hofs(0),
+ m_last_vofs(0),
+ m_blit_dim(0, 0),
+ m_last_dim(0, 0)
+ { }
+
+ /* virtual */ int create();
+ /* virtual */ int draw(const int update);
+ /* virtual */ int xy_to_render_target(const int x, const int y, int *xt, int *yt);
+ /* virtual */ void destroy();
+ /* virtual */ render_primitive_list *get_primitives()
+ {
+ osd_dim nd = window().blit_surface_size();
+ if (nd != m_blit_dim)
+ {
+ m_blit_dim = nd;
+ notify_changed();
+ }
+ window().target()->set_bounds(m_blit_dim.width(), m_blit_dim.height(), window().aspect());
+ return &window().target()->get_primitives();
+ }
+
+private:
+ void destroy_all_textures();
+ void yuv_init();
+#if (SDLMAME_SDL2)
+ void setup_texture(const osd_dim &size);
+#endif
+ void yuv_lookup_set(unsigned int pen, unsigned char red,
+ unsigned char green, unsigned char blue);
+
+#if (!SDLMAME_SDL2)
+ void yuv_overlay_init();
+#endif
+
+ INT32 m_blittimer;
+
+#if (SDLMAME_SDL2)
+ SDL_Renderer *m_sdl_renderer;
+ SDL_Texture *m_texture_id;
+#else
+ SDL_Overlay *m_yuvsurf;
+#endif
+
+ // YUV overlay
+ UINT32 *m_yuv_lookup;
+ UINT16 *m_yuv_bitmap;
+
+ // if we leave scaling to SDL and the underlying driver, this
+ // is the render_target_width/height to use
+
+ int m_last_hofs;
+ int m_last_vofs;
+ osd_dim m_blit_dim;
+ osd_dim m_last_dim;
+};
+
+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 (!SDLMAME_SDL2)
+ int m_extra_flags; /* Texture/surface flags */
+#else
+ const char *sdl_scale_mode_hint; /* what to use as a hint ? */
+#endif
+ int pixel_format; /* Pixel/Overlay format */
+ void (*yuv_blit)(const UINT16 *bitmap, UINT8 *ptr, const int pitch, const UINT32 *lookup, const int width, const int height);
+};
+
+//============================================================
+// INLINES
+//============================================================
+
+//============================================================
+// PROTOTYPES
+//============================================================
+
+// core functions
+static void drawsdl_exit(void);
+
+// YUV overlays
+
+static void yuv_RGB_to_YV12(const UINT16 *bitmap, UINT8 *ptr, const int pitch, \
+ const UINT32 *lookup, const int width, const int height);
+static void yuv_RGB_to_YV12X2(const UINT16 *bitmap, UINT8 *ptr, const int pitch, \
+ const UINT32 *lookup, const int width, const int height);
+static void yuv_RGB_to_YUY2(const UINT16 *bitmap, UINT8 *ptr, const int pitch, \
+ const UINT32 *lookup, const int width, const int height);
+static void yuv_RGB_to_YUY2X2(const UINT16 *bitmap, UINT8 *ptr, const int pitch, \
+ const UINT32 *lookup, const int width, const int height);
+
+// Static declarations
+
+#if (!SDLMAME_SDL2)
+static int shown_video_info = 0;
+
+static const sdl_scale_mode scale_modes[] =
+{
+ { "none", 0, 0, 1, 1, osd_renderer::FLAG_NEEDS_DOUBLEBUF, 0, 0 },
+ { "async", 0, 0, 1, 1, osd_renderer::FLAG_NEEDS_DOUBLEBUF | osd_renderer::FLAG_NEEDS_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, 1, 1, DRAW2_SCALEMODE_NEAREST, 0, 0 },
+ { "hwblit", 1, 0, 1, 1, DRAW2_SCALEMODE_LINEAR, 0, 0 },
+ { "hwbest", 1, 0, 1, 1, DRAW2_SCALEMODE_BEST, 0, 0 },
+ /* SDL1.2 uses interpolation as well */
+ { "yv12", 1, 1, 1, 1, DRAW2_SCALEMODE_BEST, SDL_PIXELFORMAT_YV12, yuv_RGB_to_YV12 },
+ { "yv12x2", 1, 1, 2, 2, DRAW2_SCALEMODE_BEST, SDL_PIXELFORMAT_YV12, yuv_RGB_to_YV12X2 },
+ { "yuy2", 1, 1, 1, 1, DRAW2_SCALEMODE_BEST, SDL_PIXELFORMAT_YUY2, yuv_RGB_to_YUY2 },
+ { "yuy2x2", 1, 1, 2, 1, DRAW2_SCALEMODE_BEST, 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;
+}
+
+
+static osd_renderer *drawsdl_create(osd_window *window)
+{
+ // FIXME: QUALITY HINTS
+#if (SDLMAME_SDL2)
+ return global_alloc(sdl_info(window, osd_renderer::FLAG_NONE));
+#else
+ const sdl_scale_mode *sm = &scale_modes[video_config.scale_mode];
+ return global_alloc(sdl_info(window, sm->m_extra_flags));
+#endif
+}
+
+//============================================================
+// drawsdl_init
+//============================================================
+
+int drawsdl_init(osd_draw_callbacks *callbacks)
+{
+ // fill in the callbacks
+ callbacks->create = drawsdl_create;
+ callbacks->exit = drawsdl_exit;
+
+ if (SDLMAME_SDL2)
+ osd_printf_verbose("Using SDL multi-window soft driver (SDL 2.0+)\n");
+ else
+ osd_printf_verbose("Using SDL single-window soft driver (SDL 1.2)\n");
+
+ return 0;
+}
+
+//============================================================
+// drawsdl_exit
+//============================================================
+
+static void drawsdl_exit(void)
+{
+}
+
+//============================================================
+// setup_texture for window
+//============================================================
+
+#if (SDLMAME_SDL2)
+void sdl_info::setup_texture(const osd_dim &size)
+{
+ const sdl_scale_mode *sdl_sm = &scale_modes[video_config.scale_mode];
+ SDL_DisplayMode mode;
+ UINT32 fmt;
+
+ // Determine preferred pixelformat and set up yuv if necessary
+ SDL_GetCurrentDisplayMode(*((UINT64 *)window().monitor()->oshandle()), &mode);
+
+ if (m_yuv_bitmap)
+ {
+ global_free_array(m_yuv_bitmap);
+ m_yuv_bitmap = NULL;
+ }
+
+ fmt = (sdl_sm->pixel_format ? sdl_sm->pixel_format : mode.format);
+
+ if (sdl_sm->is_scale)
+ {
+ int m_hw_scale_width = 0;
+ int m_hw_scale_height = 0;
+
+ window().target()->compute_minimum_size(m_hw_scale_width, m_hw_scale_height);
+ if (window().prescale())
+ {
+ m_hw_scale_width *= window().prescale();
+ m_hw_scale_height *= window().prescale();
+
+ /* This must be a multiple of 2 */
+ m_hw_scale_width = (m_hw_scale_width + 1) & ~1;
+ }
+ if (sdl_sm->is_yuv)
+ m_yuv_bitmap = global_alloc_array(UINT16, m_hw_scale_width * m_hw_scale_height);
+
+ int w = m_hw_scale_width * sdl_sm->mult_w;
+ int h = m_hw_scale_height * sdl_sm->mult_h;
+
+ m_texture_id = SDL_CreateTexture(m_sdl_renderer, fmt, SDL_TEXTUREACCESS_STREAMING, w, h);
+
+ }
+ else
+ {
+ m_texture_id = SDL_CreateTexture(m_sdl_renderer,fmt, SDL_TEXTUREACCESS_STREAMING,
+ size.width(), size.height());
+ }
+}
+#endif
+
+//============================================================
+// yuv_overlay_init
+//============================================================
+
+#if (!SDLMAME_SDL2)
+void sdl_info::yuv_overlay_init()
+{
+ const sdl_scale_mode *sdl_sm = &scale_modes[video_config.scale_mode];
+ int minimum_width, minimum_height;
+
+ window().target()->compute_minimum_size(minimum_width, minimum_height);
+
+ if (window().prescale())
+ {
+ minimum_width *= window().prescale();
+ minimum_height *= window().prescale();
+ }
+
+ if (m_yuvsurf != NULL)
+ {
+ SDL_FreeYUVOverlay(m_yuvsurf);
+ m_yuvsurf = NULL;
+ }
+
+ if (m_yuv_bitmap != NULL)
+ {
+ global_free_array(m_yuv_bitmap);
+ }
+
+ osd_printf_verbose("SDL: Creating %d x %d YUV-Overlay ...\n", minimum_width, minimum_height);
+
+ m_yuv_bitmap = global_alloc_array(UINT16, minimum_width*minimum_height);
+
+ m_yuvsurf = SDL_CreateYUVOverlay(minimum_width * sdl_sm->mult_w, minimum_height * sdl_sm->mult_h,
+ sdl_sm->pixel_format, window().sdl_surface());
+
+ if ( m_yuvsurf == NULL ) {
+ osd_printf_error("SDL: Couldn't create SDL_yuv_overlay: %s\n", SDL_GetError());
+ //return 1;
+ }
+
+ if (!shown_video_info)
+ {
+ osd_printf_verbose("YUV Mode : %s\n", sdl_sm->name);
+ osd_printf_verbose("YUV Overlay Size : %d x %d\n", minimum_width, minimum_height);
+ osd_printf_verbose("YUV Acceleration : %s\n", m_yuvsurf->hw_overlay ? "Hardware" : "Software");
+ shown_video_info = 1;
+ }
+}
+#endif
+
+//============================================================
+// drawsdl_show_info
+//============================================================
+
+#if (SDLMAME_SDL2)
+static void drawsdl_show_info(struct SDL_RendererInfo *render_info)
+{
+#define RF_ENTRY(x) {x, #x }
+ static struct {
+ int flag;
+ const char *name;
+ } rflist[] =
+ {
+#if 0
+ 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),
+#endif
+ RF_ENTRY(SDL_RENDERER_PRESENTVSYNC),
+ RF_ENTRY(SDL_RENDERER_ACCELERATED),
+ {-1, NULL}
+ };
+ int i;
+
+ osd_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)
+ osd_printf_verbose("renderer: flag %s\n", rflist[i].name);
+}
+#endif
+
+//============================================================
+// sdl_info::create
+// a
+// a
+// a
+// a
+// a
+// a
+// a
+// a
+// a
+// a
+// a
+// a
+// a
+// a
+// a
+// a
+// a
+// a
+// a
+// a
+// a
+// a
+// a
+// a
+// a
+// a
+//============================================================
+
+
+int sdl_info::create()
+{
+#if (SDLMAME_SDL2)
+ const sdl_scale_mode *sm = &scale_modes[video_config.scale_mode];
+
+ // create renderer
+
+ /* set hints ... */
+ SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, sm->sdl_scale_mode_hint);
+
+
+ if (video_config.waitvsync)
+ m_sdl_renderer = SDL_CreateRenderer(window().sdl_window(), -1, SDL_RENDERER_PRESENTVSYNC | SDL_RENDERER_ACCELERATED);
+ else
+ m_sdl_renderer = SDL_CreateRenderer(window().sdl_window(), -1, SDL_RENDERER_ACCELERATED);
+
+ if (!m_sdl_renderer)
+ {
+ fatalerror("Error on creating renderer: %s\n", SDL_GetError());
+ }
+
+ {
+ struct SDL_RendererInfo render_info;
+
+ SDL_GetRendererInfo(m_sdl_renderer, &render_info);
+ drawsdl_show_info(&render_info);
+
+ // Check scale mode
+
+ if (sm->pixel_format)
+ {
+ int i;
+ int found = 0;
+
+ for (i=0; i < render_info.num_texture_formats; i++)
+ if (sm->pixel_format == render_info.texture_formats[i])
+ found = 1;
+
+ if (!found)
+ {
+ fatalerror("window: Scale mode %s not supported!", sm->name);
+ }
+ }
+ }
+
+#if 0
+ int w = 0, h = 0;
+ window().get_size(w, h);
+ setup_texture(w, h);
+#endif
+#else
+#endif
+
+ m_yuv_lookup = NULL;
+ m_blittimer = 0;
+
+ yuv_init();
+ osd_printf_verbose("Leave sdl_info::create\n");
+ return 0;
+}
+
+//============================================================
+// sdl_info::destroy
+//============================================================
+
+void sdl_info::destroy()
+{
+ // free the memory in the window
+
+ destroy_all_textures();
+
+ if (m_yuv_lookup != NULL)
+ {
+ global_free_array(m_yuv_lookup);
+ m_yuv_lookup = NULL;
+ }
+ if (m_yuv_bitmap != NULL)
+ {
+ global_free_array(m_yuv_bitmap);
+ m_yuv_bitmap = NULL;
+ }
+#if (SDLMAME_SDL2)
+ SDL_DestroyRenderer(m_sdl_renderer);
+#endif
+}
+
+//============================================================
+// drawsdl_xy_to_render_target
+//============================================================
+
+int sdl_info::xy_to_render_target(int x, int y, int *xt, int *yt)
+{
+ *xt = x - m_last_hofs;
+ *yt = y - m_last_vofs;
+ if (*xt<0 || *xt >= m_blit_dim.width())
+ return 0;
+ if (*yt<0 || *yt >= m_blit_dim.height())
+ return 0;
+ return 1;
+}
+
+//============================================================
+// drawsdl_destroy_all_textures
+//============================================================
+
+void sdl_info::destroy_all_textures()
+{
+#if (SDLMAME_SDL2)
+ SDL_DestroyTexture(m_texture_id);
+ m_texture_id = NULL;
+#else
+ if (m_yuvsurf != NULL)
+ {
+ SDL_FreeYUVOverlay(m_yuvsurf);
+ m_yuvsurf = NULL;
+ }
+#endif
+}
+
+
+//============================================================
+// sdl_info::draw
+//============================================================
+
+int sdl_info::draw(int update)
+{
+ const sdl_scale_mode *sm = &scale_modes[video_config.scale_mode];
+ UINT8 *surfptr;
+ INT32 pitch;
+ Uint32 rmask, gmask, bmask;
+#if (SDLMAME_SDL2)
+ Uint32 amask;
+#endif
+ INT32 vofs, hofs, blitwidth, blitheight, ch, cw;
+ int bpp;
+
+ if (video_config.novideo)
+ {
+ return 0;
+ }
+
+ osd_dim wdim = window().get_size();
+ if (has_flags(FI_CHANGED) || (wdim != m_last_dim))
+ {
+ destroy_all_textures();
+ clear_flags(FI_CHANGED);
+ m_blittimer = 3;
+ m_last_dim = wdim;
+#if (SDLMAME_SDL2)
+ SDL_RenderSetViewport(m_sdl_renderer, NULL);
+ if (m_texture_id != NULL)
+ SDL_DestroyTexture(m_texture_id);
+ setup_texture(m_blit_dim);
+ m_blittimer = 3;
+#else
+ const sdl_scale_mode *sdl_sm = &scale_modes[video_config.scale_mode];
+ if (sdl_sm->is_yuv)
+ {
+ yuv_overlay_init();
+ }
+#endif
+ }
+
+ // lock it if we need it
+#if (!SDLMAME_SDL2)
+
+ pitch = window().sdl_surface()->pitch;
+ bpp = window().sdl_surface()->format->BytesPerPixel;
+ rmask = window().sdl_surface()->format->Rmask;
+ gmask = window().sdl_surface()->format->Gmask;
+ bmask = window().sdl_surface()->format->Bmask;
+// amask = sdlsurf->format->Amask;
+#if 0
+ if (window().blitwidth() != m_old_blitwidth || window().blitheight() != m_old_blitheight)
+ {
+ if (sm->is_yuv)
+ yuv_overlay_init();
+ m_old_blitwidth = window().blitwidth();
+ m_old_blitheight = window().blitheight();
+ m_blittimer = 3;
+ }
+#endif
+ if (SDL_MUSTLOCK(window().sdl_surface()))
+ SDL_LockSurface(window().sdl_surface());
+
+ // Clear if necessary
+ if (m_blittimer > 0)
+ {
+ memset(window().sdl_surface()->pixels, 0, wdim.height() * window().sdl_surface()->pitch);
+ m_blittimer--;
+ }
+
+
+ if (sm->is_yuv)
+ {
+ SDL_LockYUVOverlay(m_yuvsurf);
+ surfptr = m_yuvsurf->pixels[0]; // (UINT8 *) m_yuv_bitmap;
+ pitch = m_yuvsurf->pitches[0]; // (UINT8 *) m_yuv_bitmap;
+#if 0
+ printf("abcd %d\n", m_yuvsurf->h);
+ printf("abcd %d %d %d\n", m_yuvsurf->pitches[0], m_yuvsurf->pitches[1], m_yuvsurf->pitches[2]);
+ printf("abcd %p %p %p\n", m_yuvsurf->pixels[0], m_yuvsurf->pixels[1], m_yuvsurf->pixels[2]);
+ printf("abcd %ld %ld\n", m_yuvsurf->pixels[1] - m_yuvsurf->pixels[0], m_yuvsurf->pixels[2] - m_yuvsurf->pixels[1]);
+#endif
+ }
+ else
+ surfptr = (UINT8 *)window().sdl_surface()->pixels;
+#else
+ //SDL_SelectRenderer(window().sdl_window);
+
+
+ {
+ Uint32 format;
+ int access, w, h;
+
+ SDL_QueryTexture(m_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 (m_blittimer > 0)
+ {
+ /* SDL Underlays need alpha = 0 ! */
+ SDL_SetRenderDrawColor(m_sdl_renderer,0,0,0,0);
+ SDL_RenderFillRect(m_sdl_renderer,NULL);
+ //SDL_RenderFill(0,0,0,0 /*255*/,NULL);
+ m_blittimer--;
+ }
+
+ SDL_LockTexture(m_texture_id, NULL, (void **) &surfptr, &pitch);
+
+#endif
+ // get ready to center the image
+ vofs = hofs = 0;
+ blitwidth = m_blit_dim.width();
+ blitheight = m_blit_dim.height();
+
+ ch = wdim.height();
+ cw = wdim.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 - m_blit_dim.height()) / 2;
+ }
+
+ if (blitwidth > cw)
+ {
+ blitwidth = cw;
+ }
+ else if (video_config.centerh)
+ {
+ hofs = (cw - m_blit_dim.width()) / 2;
+ }
+
+ m_last_hofs = hofs;
+ m_last_vofs = vofs;
+
+ window().m_primlist->acquire_lock();
+
+ int mamewidth, mameheight;
+
+#if !SDLMAME_SDL2
+ if (!sm->is_yuv)
+ {
+ surfptr += ((vofs * pitch) + (hofs * bpp));
+ mamewidth = blitwidth; //sdl_surface()->w;
+ mameheight = blitheight; //sdl_surface()->h;
+ }
+ else
+ {
+ mamewidth = m_yuvsurf->w / sm->mult_w;
+ mameheight = m_yuvsurf->h / sm->mult_h;
+ }
+#else
+ Uint32 fmt = 0;
+ int access = 0;
+ SDL_QueryTexture(m_texture_id, &fmt, &access, &mamewidth, &mameheight);
+ mamewidth /= sm->mult_w;
+ mameheight /= sm->mult_h;
+#endif
+ //printf("w h %d %d %d %d\n", mamewidth, mameheight, blitwidth, blitheight);
+
+ // rescale bounds
+ float fw = (float) mamewidth / (float) blitwidth;
+ float fh = (float) mameheight / (float) blitheight;
+
+ // FIXME: this could be a lot easier if we get the primlist here!
+ // Bounds would be set fit for purpose and done!
+
+ for (render_primitive *prim = window().m_primlist->first(); prim != NULL; prim = prim->next())
+ {
+ prim->bounds.x0 = floor(fw * prim->bounds.x0 + 0.5f);
+ prim->bounds.x1 = floor(fw * prim->bounds.x1 + 0.5f);
+ prim->bounds.y0 = floor(fh * prim->bounds.y0 + 0.5f);
+ prim->bounds.y1 = floor(fh * prim->bounds.y1 + 0.5f);
+ }
+
+ // render to it
+ if (!sm->is_yuv)
+ {
+ switch (rmask)
+ {
+ case 0x0000ff00:
+ software_renderer<UINT32, 0,0,0, 8,16,24>::draw_primitives(*window().m_primlist, surfptr, mamewidth, mameheight, pitch / 4);
+ break;
+
+ case 0x00ff0000:
+ software_renderer<UINT32, 0,0,0, 16,8,0>::draw_primitives(*window().m_primlist, surfptr, mamewidth, mameheight, pitch / 4);
+ break;
+
+ case 0x000000ff:
+ software_renderer<UINT32, 0,0,0, 0,8,16>::draw_primitives(*window().m_primlist, surfptr, mamewidth, mameheight, pitch / 4);
+ break;
+
+ case 0xf800:
+ software_renderer<UINT16, 3,2,3, 11,5,0>::draw_primitives(*window().m_primlist, surfptr, mamewidth, mameheight, pitch / 2);
+ break;
+
+ case 0x7c00:
+ software_renderer<UINT16, 3,3,3, 10,5,0>::draw_primitives(*window().m_primlist, surfptr, mamewidth, mameheight, pitch / 2);
+ break;
+
+ default:
+ osd_printf_error("SDL: ERROR! Unknown video mode: R=%08X G=%08X B=%08X\n", rmask, gmask, bmask);
+ break;
+ }
+ }
+ else
+ {
+ assert (m_yuv_bitmap != NULL);
+ assert (surfptr != NULL);
+ software_renderer<UINT16, 3,3,3, 10,5,0>::draw_primitives(*window().m_primlist, m_yuv_bitmap, mamewidth, mameheight, mamewidth);
+ sm->yuv_blit((UINT16 *)m_yuv_bitmap, surfptr, pitch, m_yuv_lookup, mamewidth, mameheight);
+ }
+
+ window().m_primlist->release_lock();
+
+ // unlock and flip
+#if (!SDLMAME_SDL2)
+ if (SDL_MUSTLOCK(window().sdl_surface())) SDL_UnlockSurface(window().sdl_surface());
+ if (!sm->is_yuv)
+ {
+ SDL_Flip(window().sdl_surface());
+ }
+ else
+ {
+ SDL_Rect r;
+
+ SDL_UnlockYUVOverlay(m_yuvsurf);
+ r.x = hofs;
+ r.y = vofs;
+ r.w = blitwidth;
+ r.h = blitheight;
+ SDL_DisplayYUVOverlay(m_yuvsurf, &r);
+ }
+#else
+ SDL_UnlockTexture(m_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(sdltex, NULL, sdlsurf->pixels, pitch);
+ SDL_RenderCopy(m_sdl_renderer,m_texture_id, NULL, &r);
+ SDL_RenderPresent(m_sdl_renderer);
+ }
+#endif
+ return 0;
+}
+//============================================================
+// 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)
+
+void sdl_info::yuv_lookup_set(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... */
+ m_yuv_lookup[pen]=(y<<Y1SHIFT)|(u<<USHIFT)|(y<<Y2SHIFT)|(v<<VSHIFT);
+}
+
+void sdl_info::yuv_init()
+{
+ unsigned char r,g,b;
+ if (m_yuv_lookup == NULL)
+ m_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(idx,
+ (r << 3) | (r >> 2),
+ (g << 3) | (g >> 2),
+ (b << 3) | (b >> 2));
+ }
+}
+
+//UINT32 *lookup = sdl->m_yuv_lookup;
+
+static void yuv_RGB_to_YV12(const UINT16 *bitmap, UINT8 *ptr, const int pitch, \
+ const UINT32 *lookup, const int width, const int height)
+{
+ int x, y;
+ UINT8 *pixels[3];
+ int u1,v1,y1,u2,v2,y2,u3,v3,y3,u4,v4,y4; /* 12 */
+
+ pixels[0] = ptr;
+ pixels[1] = ptr + pitch * height;
+ pixels[2] = pixels[1] + pitch * height / 4;
+
+ for(y=0;y<height;y+=2)
+ {
+ const UINT16 *src=bitmap + (y * width) ;
+ const UINT16 *src2=src + width;
+
+ UINT8 *dest_y = pixels[0] + y * pitch;
+ UINT8 *dest_v = pixels[1] + (y>>1) * pitch / 2;
+ UINT8 *dest_u = pixels[2] + (y>>1) * pitch / 2;
+
+ for(x=0;x<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(const UINT16 *bitmap, UINT8 *ptr, const int pitch, \
+ const UINT32 *lookup, const int width, const int height)
+{
+ /* this one is used when scale==2 */
+ unsigned int x,y;
+ int u1,v1,y1;
+ UINT8 *pixels[3];
+
+ pixels[0] = ptr;
+ pixels[1] = ptr + pitch * height * 2;
+#if (SDLMAME_SDL2)
+ int p2 = (pitch >> 1);
+#else
+ int p2 = (pitch + 7) & ~ 7;;
+ p2 = (p2 >> 1);
+#endif
+ pixels[2] = pixels[1] + p2 * height;
+
+ for(y=0;y<height;y++)
+ {
+ const UINT16 *src = bitmap + (y * width) ;
+
+ UINT16 *dest_y = (UINT16 *)(pixels[0] + 2 * y * pitch);
+ UINT8 *dest_v = pixels[1] + y * p2;
+ UINT8 *dest_u = pixels[2] + y * p2;
+ for(x=0;x<width;x++)
+ {
+ v1 = 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(const UINT16 *bitmap, UINT8 *ptr, const int pitch, \
+ const UINT32 *lookup, const int width, const int height)
+{
+ /* this one is used when scale==2 */
+ unsigned int y;
+ UINT32 p1,p2,uv;
+ const int yuv_pitch = pitch/4;
+
+ for(y=0;y<height;y++)
+ {
+ const UINT16 *src=bitmap + (y * width) ;
+ const UINT16 *end=src+width;
+
+ UINT32 *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(const UINT16 *bitmap, UINT8 *ptr, const int pitch, \
+ const UINT32 *lookup, const int width, const int height)
+{
+ /* this one is used when scale==2 */
+ unsigned int y;
+ int yuv_pitch = pitch / 4;
+
+ for(y=0;y<height;y++)
+ {
+ const UINT16 *src=bitmap + (y * width) ;
+ const UINT16 *end=src+width;
+
+ UINT32 *dest = (UINT32 *) ptr;
+ dest += (y * yuv_pitch);
+ for(; src<end; src++)
+ {
+ dest[0] = lookup[src[0]];
+ dest++;
+ }
+ }
+}