From bd07f02a0db0545d00c6c1dd1d1535cadd48f682 Mon Sep 17 00:00:00 2001 From: bgk Date: Tue, 22 Apr 2008 10:39:23 +0000 Subject: [PATCH] GTK GUI : Added a Xvideo renderer to get hardware accelerated scaling and filtering. It is about 10x faster than the GTK+ renderer. No filters yet. git-svn-id: https://svn.code.sf.net/p/vbam/code/trunk@490 a31d4220-a93d-0410-bf67-fe4944624d44 --- CMakeLists.txt | 7 +- src/gtk/screenarea-xvideo.cpp | 226 ++++++++++++++++++++++++++++++++++ src/gtk/screenarea-xvideo.h | 64 ++++++++++ src/gtk/screenarea.h | 1 - src/gtk/window.cpp | 42 +++++-- src/gtk/window.h | 5 +- 6 files changed, 333 insertions(+), 12 deletions(-) create mode 100644 src/gtk/screenarea-xvideo.cpp create mode 100644 src/gtk/screenarea-xvideo.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 916def64..4d0a6341 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -15,14 +15,15 @@ PKG_CHECK_MODULES ( GLIBMM glibmm-2.4 ) PKG_CHECK_MODULES ( GLADEMM libglademm-2.4 ) PKG_CHECK_MODULES ( PORTAUDIO portaudio-2.0 ) PKG_CHECK_MODULES ( SDL sdl ) +PKG_CHECK_MODULES ( XV xv ) IF( SDL_FOUND ) SET( CAN_BUILD_VBAM 1 ) ENDIF( SDL_FOUND ) -IF( GLIBMM_FOUND AND GTKMM_FOUND AND GLADEMM_FOUND AND PORTAUDIO_FOUND ) +IF( GLIBMM_FOUND AND GTKMM_FOUND AND GLADEMM_FOUND AND PORTAUDIO_FOUND AND XV_FOUND ) SET( CAN_BUILD_GVBAM 1 ) -ENDIF( GLIBMM_FOUND AND GTKMM_FOUND AND GLADEMM_FOUND AND PORTAUDIO_FOUND ) +ENDIF( GLIBMM_FOUND AND GTKMM_FOUND AND GLADEMM_FOUND AND PORTAUDIO_FOUND AND XV_FOUND ) IF( NOT DATA_INSTALL_DIR ) SET( DATA_INSTALL_DIR "src/gtk" ) @@ -141,6 +142,7 @@ SET(SRC_GTK src/gtk/joypadconfig.cpp src/gtk/screenarea.cpp src/gtk/screenarea-gtk.cpp + src/gtk/screenarea-xvideo.cpp src/gtk/tools.cpp src/gtk/window.cpp src/gtk/sndPortAudio.cpp @@ -207,6 +209,7 @@ IF( CAN_BUILD_GVBAM ) ${PNG_LIBRARY} ${GLADEMM_LIBRARIES} ${PORTAUDIO_LIBRARIES} + ${XV_LIBRARIES} ) INSTALL(PROGRAMS gvbam DESTINATION bin) diff --git a/src/gtk/screenarea-xvideo.cpp b/src/gtk/screenarea-xvideo.cpp new file mode 100644 index 00000000..c382a6d2 --- /dev/null +++ b/src/gtk/screenarea-xvideo.cpp @@ -0,0 +1,226 @@ +// VisualBoyAdvance - Nintendo Gameboy/GameboyAdvance (TM) emulator. +// Copyright (C) 1999-2003 Forgotten +// Copyright (C) 2004 Forgotten and the VBA development team + +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2, or(at your option) +// any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, +// Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#include "screenarea-xvideo.h" + +#include +#include +#include +#include +#include + +#include + +#define FOURCC_YUY2 0x32595559 + +namespace VBA +{ + +ScreenAreaXv::ScreenAreaXv(int _iWidth, int _iHeight, int _iScale) : + ScreenArea(_iWidth, _iHeight, _iScale) +{ + XvAdaptorInfo *pAdaptors; + unsigned int iNumAdaptors; + XvImageFormatValues *pFormats; + int iNumFormats; + GdkWindow *pRoot; + + memset(&m_oShm, 0, sizeof(m_oShm)); + + // Ugly bit of GTK+ to get the X display + Glib::RefPtr poWindow = get_root_window(); + GdkWindow *pWindow = poWindow->gobj(); + + m_pDisplay = gdk_x11_drawable_get_xdisplay(GDK_DRAWABLE(pWindow)); + + Glib::RefPtr poScreen = get_screen(); + Glib::RefPtr poRoot = poScreen->get_root_window(); + pRoot = poRoot->gobj(); + + m_iXvPortId = -1; + XvQueryAdaptors(m_pDisplay, + GDK_WINDOW_XWINDOW(pRoot), + &iNumAdaptors, + &pAdaptors); + + for (unsigned int i = 0; i < iNumAdaptors; i++) + { + if (pAdaptors[i].type & XvInputMask && + pAdaptors[i].type & XvImageMask) + { + m_iXvPortId = pAdaptors[i].base_id; + } + } + + XvFreeAdaptorInfo(pAdaptors); + + if (m_iXvPortId < 0) + { + fprintf (stderr, "Could not open Xv output port.\n"); + throw std::exception(); + } + + /* Try to find an RGB format */ + pFormats = XvListImageFormats(m_pDisplay, m_iXvPortId, &iNumFormats); + + m_iFormat = FOURCC_YUY2; + + for (int i = 0; i < iNumFormats; i++) + { + if (pFormats[i].id == 0x3 || pFormats[i].type == XvRGB) + { + /* Try to find a 32-bit mode */ + if (pFormats[i].bits_per_pixel == 32) + { + m_iFormat = pFormats[i].id; + } + } + } + + Atom oAtom = XInternAtom(m_pDisplay, "XV_AUTOPAINT_COLORKEY", True); + if (oAtom != None) + XvSetPortAttribute (m_pDisplay, m_iXvPortId, oAtom, 1); + + vUpdateSize(); +} + +ScreenAreaXv::~ScreenAreaXv() +{ + XShmDetach(m_pDisplay, &m_oShm); +} + +void ScreenAreaXv::vDrawPixels(u8 * _puiData) +{ + GtkWidget *pDrawingArea = GTK_WIDGET(this->gobj()); + GdkGC *gc = pDrawingArea->style->bg_gc[GTK_WIDGET_STATE (pDrawingArea)]; + + const int iSrcPitch = (m_iWidth + 4) * sizeof(u16); + const int iDstPitch = m_iWidth * sizeof(u32) + 4; + + vRGB32toYUY2((unsigned char*)m_pXvImage->data, m_iWidth, m_iHeight, iSrcPitch, + _puiData + iDstPitch, m_iWidth + 4, m_iHeight + 4, iDstPitch); + + gdk_display_sync(gtk_widget_get_display(pDrawingArea)); + + XvShmPutImage(m_pDisplay, + m_iXvPortId, + GDK_WINDOW_XWINDOW (pDrawingArea->window), + GDK_GC_XGC (gc), + m_pXvImage, + 0, 0, + m_iWidth, m_iHeight, + 0, 0, + m_iAreaWidth, m_iAreaHeight, + True); + + gdk_display_sync(gtk_widget_get_display(pDrawingArea)); +} + +void ScreenAreaXv::vDrawColor(u32 _uiColor) +{ +} + +void ScreenAreaXv::vUpdateSize() +{ + + if (m_oShm.shmid) + { + XShmDetach(m_pDisplay, &m_oShm); + } + + m_iAreaWidth = m_iScale * m_iWidth; + m_iAreaHeight = m_iScale * m_iHeight; + + m_pXvImage = XvShmCreateImage(m_pDisplay, + m_iXvPortId, + m_iFormat, + 0, + m_iWidth + 4, + m_iHeight + 4, + &m_oShm); + + m_oShm.shmid = shmget(IPC_PRIVATE, m_pXvImage->data_size, IPC_CREAT | 0777); + m_oShm.shmaddr = (char *) shmat(m_oShm.shmid, 0, 0); + m_oShm.readOnly = FALSE; + + m_pXvImage->data = m_oShm.shmaddr; + + XShmAttach(m_pDisplay, &m_oShm); + + set_size_request(m_iAreaWidth, m_iAreaHeight); +} + +void ScreenAreaXv::vRGB32toYUY2 (unsigned char* dest_ptr, + int dest_width, + int dest_height, + int dest_pitch, + unsigned char* src_ptr, + int src_width, + int src_height, + int src_pitch) +{ + unsigned char* pSrc = NULL; + unsigned char* pDst = NULL; + int iR = 0; + int iG = 0; + int iB = 0; + int iY = 0; + int iU = 0; + int iV = 0; + + + /* Run through each row */ + for (int y = 0; y < src_height; y++) + { + /* Get the src and dst row pointers */ + pSrc = src_ptr + y * src_pitch; + pDst = dest_ptr + y * dest_pitch; + /* Loop along each row */ + for (int x = 0; x < src_width; x++) + { + /* Convert RGB to YUV, using the following fixed-point formula: + * + * Y = (r * 2104 + g * 4130 + b * 802 + 4096 + 131072) >> 13 + * U = (r * -1214 + g * -2384 + b * 3598 + 4096 + 1048576) >> 13 + * V = (r * 3598 + g * -3013 + b * -585 + 4096 + 1048576) >> 13 + */ +#if defined(_WINDOWS) + iR = pSrc[2]; + iG = pSrc[1]; + iB = pSrc[0]; +#else + iR = pSrc[0]; + iG = pSrc[1]; + iB = pSrc[2]; +#endif + iY = (iR * 2104 + iG * 4130 + iB * 802 + 4096 + 131072) >> 13; + iU = (iR * -1214 - iG * 2384 + iB * 3598 + 4096 + 1048576) >> 13; + iV = (iR * 3598 - iG * 3013 - iB * 585 + 4096 + 1048576) >> 13; + /* Write out the Y */ + pDst[0] = (unsigned char) iY; + /* If we are even, write out U. If odd, write V */ + pDst[1] = (unsigned char) ((x & 1) ? iV : iU); + /* Advance the src pointer */ + pSrc += 4; + /* Advance the dst pointer */ + pDst += 2; + } + } +} + +} // namespace VBA diff --git a/src/gtk/screenarea-xvideo.h b/src/gtk/screenarea-xvideo.h new file mode 100644 index 00000000..2c33a53c --- /dev/null +++ b/src/gtk/screenarea-xvideo.h @@ -0,0 +1,64 @@ +// -*- C++ -*- +// VisualBoyAdvance - Nintendo Gameboy/GameboyAdvance (TM) emulator. +// Copyright (C) 1999-2003 Forgotten +// Copyright (C) 2004 Forgotten and the VBA development team + +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2, or(at your option) +// any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, +// Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#ifndef __VBA_SCREENAREA_XVIDEO_H__ +#define __VBA_SCREENAREA_XVIDEO_H__ + +#include "screenarea.h" + +#include +#include +#include +#include +#include + +namespace VBA +{ + +class ScreenAreaXv : public ScreenArea +{ +public: + ScreenAreaXv(int _iWidth, int _iHeight, int _iScale = 1); + virtual ~ScreenAreaXv(); + void vDrawPixels(u8 * _puiData); + void vDrawColor(u32 _uiColor); // 0xRRGGBB + +private: + Display *m_pDisplay; + XvImage *m_pXvImage; + int m_iXvPortId; + int m_iFormat; + u16* m_paYUY; + XShmSegmentInfo m_oShm; + + void vUpdateSize(); + void vRGB32toYUY2 (unsigned char* dest_ptr, + int dest_width, + int dest_height, + int dest_pitch, + unsigned char* src_ptr, + int src_width, + int src_height, + int src_pitch); +}; + +} // namespace VBA + + +#endif // __VBA_SCREENAREA_XVIDEO_H__ diff --git a/src/gtk/screenarea.h b/src/gtk/screenarea.h index 315b4969..b835cd2c 100644 --- a/src/gtk/screenarea.h +++ b/src/gtk/screenarea.h @@ -42,7 +42,6 @@ public: virtual void vDrawColor(u32 _uiColor) = 0; // 0xRRGGBB protected: - virtual bool on_expose_event(GdkEventExpose * _pstEvent) = 0; virtual bool on_motion_notify_event(GdkEventMotion * _pstEvent); virtual bool on_enter_notify_event(GdkEventCrossing * _pstEvent); virtual bool on_leave_notify_event(GdkEventCrossing * _pstEvent); diff --git a/src/gtk/window.cpp b/src/gtk/window.cpp index a485dc3b..4bec3e29 100644 --- a/src/gtk/window.cpp +++ b/src/gtk/window.cpp @@ -33,6 +33,8 @@ #include "menuitem.h" #include "tools.h" #include "intl.h" +#include "screenarea-gtk.h" +#include "screenarea-xvideo.h" extern int systemRenderedFrames; extern int systemFPS; @@ -95,13 +97,6 @@ Window::Window(GtkWindow * _pstWindow, const Glib::RefPtr & _poXml) : vSetDefaultTitle(); - Gtk::Container * poC; - poC = dynamic_cast(_poXml->get_widget("ScreenContainer")); - m_poScreenArea = Gtk::manage(new ScreenAreaGtk(m_iScreenWidth, m_iScreenHeight)); - poC->add(*m_poScreenArea); - vDrawDefaultScreen(); - m_poScreenArea->show(); - // Get config // vInitConfig(); @@ -123,6 +118,8 @@ Window::Window(GtkWindow * _pstWindow, const Glib::RefPtr & _poXml) : vSaveConfig(m_sConfigFile); } + vInitScreenArea(); + vCreateFileOpenDialog(); vLoadHistoryFromConfig(); vLoadJoypadsFromConfig(); @@ -857,6 +854,36 @@ Window::~Window() m_poInstance = NULL; } +void Window::vInitScreenArea() +{ + Gtk::Container * poC; + bool bUseXv; + + poC = dynamic_cast(m_poXml->get_widget("ScreenContainer")); + bUseXv = m_poDisplayConfig->oGetKey("use_Xv"); + + if (bUseXv) + { + try + { + m_poScreenArea = Gtk::manage(new ScreenAreaXv(m_iScreenWidth, m_iScreenHeight)); + } + catch (std::exception e) + { + fprintf(stderr, "Unable to initialise Xv output, falling back to GTK+\n"); + m_poScreenArea = Gtk::manage(new ScreenAreaGtk(m_iScreenWidth, m_iScreenHeight)); + } + } + else + { + m_poScreenArea = Gtk::manage(new ScreenAreaGtk(m_iScreenWidth, m_iScreenHeight)); + } + + poC->add(*m_poScreenArea); + vDrawDefaultScreen(); + m_poScreenArea->show(); +} + void Window::vInitSystem() { #if G_BYTE_ORDER == G_LITTLE_ENDIAN @@ -963,6 +990,7 @@ void Window::vInitConfig() m_poDisplayConfig->vSetKey("pause_when_inactive", true ); m_poDisplayConfig->vSetKey("filter2x", FilterNone ); m_poDisplayConfig->vSetKey("filterIB", FilterIBNone ); + m_poDisplayConfig->vSetKey("use_Xv", false ); // Sound section // diff --git a/src/gtk/window.h b/src/gtk/window.h index f6db831d..0ae87fef 100644 --- a/src/gtk/window.h +++ b/src/gtk/window.h @@ -33,7 +33,7 @@ #include "../System.h" #include "configfile.h" -#include "screenarea-gtk.h" +#include "screenarea.h" #include "filters.h" #include "input.h" #include "joypadconfig.h" @@ -232,7 +232,7 @@ private: Gtk::FileChooserDialog * m_poFileOpenDialog; - ScreenAreaGtk * m_poScreenArea; + ScreenArea * m_poScreenArea; Gtk::Menu * m_poRecentMenu; Gtk::MenuItem * m_poRecentResetItem; Gtk::CheckMenuItem * m_poFilePauseItem; @@ -281,6 +281,7 @@ private: void vInitSystem(); void vInitConfig(); void vCheckConfig(); + void vInitScreenArea(); void vLoadConfig(const std::string & _rsFile); void vSaveConfig(const std::string & _rsFile); void vLoadHistoryFromConfig();