diff --git a/plugins/GSdx/CMakeLists.txt b/plugins/GSdx/CMakeLists.txt index 3b43f6d462..dda366afa5 100644 --- a/plugins/GSdx/CMakeLists.txt +++ b/plugins/GSdx/CMakeLists.txt @@ -105,6 +105,7 @@ set(GSdxSources GSVector.cpp GSVertexTrace.cpp GSWnd.cpp + GSWndOGL.cpp GSdx.cpp stdafx.cpp ) @@ -166,6 +167,7 @@ set(GSdxHeaders GSVertexSW.h GSVertexTrace.h GSWnd.h + GSWndOGL.h GSdx.h stdafx.h xbyak/xbyak.h diff --git a/plugins/GSdx/GPURenderer.cpp b/plugins/GSdx/GPURenderer.cpp index e1e41ed585..a8efccf665 100644 --- a/plugins/GSdx/GPURenderer.cpp +++ b/plugins/GSdx/GPURenderer.cpp @@ -45,6 +45,8 @@ GPURenderer::GPURenderer(GSDevice* dev) m_hWnd = NULL; m_wndproc = NULL; + m_wnd = new GSWndDX(); + #endif } @@ -74,7 +76,7 @@ bool GPURenderer::Create(void* hWnd) SetWindowLongPtr(m_hWnd, GWLP_WNDPROC, (LONG_PTR)WndProc); - if(!m_wnd.Attach(m_hWnd)) + if(!m_wnd->Attach(m_hWnd)) { return false; } @@ -85,9 +87,9 @@ bool GPURenderer::Create(void* hWnd) #endif - m_wnd.Show(); + m_wnd->Show(); - if(!m_dev->Create(&m_wnd)) + if(!m_dev->Create(m_wnd)) { return false; } @@ -189,10 +191,10 @@ void GPURenderer::VSync() s = format("%s | %.2f mpps", s.c_str(), fps * fillrate / (1024 * 1024)); } - m_wnd.SetWindowText(s.c_str()); + m_wnd->SetWindowText(s.c_str()); } - GSVector4i r = m_wnd.GetClientRect(); + GSVector4i r = m_wnd->GetClientRect(); m_dev->Present(r.fit(m_aspectratio), 0); } diff --git a/plugins/GSdx/GPURenderer.h b/plugins/GSdx/GPURenderer.h index ffffc72091..93c23f17fd 100644 --- a/plugins/GSdx/GPURenderer.h +++ b/plugins/GSdx/GPURenderer.h @@ -24,6 +24,9 @@ #include "GPUState.h" #include "GSVertexList.h" #include "GSDevice.h" +#ifdef _WINDOWS +#include "GSWndDX.h" +#endif class GPURenderer : public GPUState { @@ -53,7 +56,7 @@ protected: #endif - GSWnd m_wnd; + GSWnd* m_wnd; public: GPURenderer(GSDevice* dev); diff --git a/plugins/GSdx/GS.cpp b/plugins/GSdx/GS.cpp index 8cd32a1fb3..d86c79e531 100644 --- a/plugins/GSdx/GS.cpp +++ b/plugins/GSdx/GS.cpp @@ -32,6 +32,7 @@ #include "GSRendererDX11.h" #include "GSDevice9.h" #include "GSDevice11.h" +#include "GSWndDX.h" #include "GSRendererCS.h" #include "GSSettingsDlg.h" @@ -41,6 +42,7 @@ static HRESULT s_hr = E_FAIL; #include "GSDeviceOGL.h" #include "GSRendererOGL.h" +#include "GSWndOGL.h" #include #include @@ -173,7 +175,7 @@ EXPORT_C GSclose() s_gs->m_dev = NULL; - s_gs->m_wnd.Detach(); + s_gs->m_wnd->Detach(); } static int _GSopen(void** dsp, char* title, int renderer, int threads = -1) @@ -265,6 +267,18 @@ static int _GSopen(void** dsp, char* title, int renderer, int threads = -1) s_renderer = renderer; } } + + if (s_gs->m_wnd == NULL) + { + switch(renderer / 3) + { + default: + #ifdef _WINDOWS + s_gs->m_wnd = new GSWndDX(); break; + #endif + case 4: s_gs->m_wnd = new GSWndOGL(); break; + } + } } catch(std::exception& ex) { @@ -296,9 +310,9 @@ static int _GSopen(void** dsp, char* title, int renderer, int threads = -1) return -1; } - s_gs->m_wnd.Show(); + s_gs->m_wnd->Show(); - *dsp = s_gs->m_wnd.GetDisplay(); + *dsp = s_gs->m_wnd->GetDisplay(); } else { @@ -306,10 +320,10 @@ static int _GSopen(void** dsp, char* title, int renderer, int threads = -1) #ifdef _LINUX // Get the Xwindow from dsp. - if( !s_gs->m_wnd.Attach((void*)((uint32*)(dsp)+1), false) ) + if( !s_gs->m_wnd->Attach((void*)((uint32*)(dsp)+1), false) ) return -1; #else - s_gs->m_wnd.Attach(*dsp, false); + s_gs->m_wnd->Attach(*dsp, false); #endif } @@ -446,13 +460,13 @@ EXPORT_C GSreadFIFO(uint8* mem) #ifdef OGL_DEBUG if (theApp.GetConfig("renderer", 0) / 3 == 4) fprintf(stderr, "Disable FIFO1 on opengl\n"); #endif - s_gs->m_wnd.AttachContext(); + s_gs->m_wnd->AttachContext(); #endif s_gs->ReadFIFO(mem, 1); #ifdef OGL_MT_HACK - s_gs->m_wnd.DetachContext(); + s_gs->m_wnd->DetachContext(); #endif } catch (GSDXRecoverableError) @@ -470,13 +484,13 @@ EXPORT_C GSreadFIFO2(uint8* mem, uint32 size) #ifdef OGL_DEBUG if (theApp.GetConfig("renderer", 0) / 3 == 4) fprintf(stderr, "Disable FIFO2(%d) on opengl\n", size); #endif - s_gs->m_wnd.AttachContext(); + s_gs->m_wnd->AttachContext(); #endif s_gs->ReadFIFO(mem, size); #ifdef OGL_MT_HACK - s_gs->m_wnd.DetachContext(); + s_gs->m_wnd->DetachContext(); #endif } catch (GSDXRecoverableError) @@ -534,7 +548,7 @@ EXPORT_C GSvsync(int field) { #ifdef _WINDOWS - if(s_gs->m_wnd.IsManaged()) + if(s_gs->m_wnd->IsManaged()) { MSG msg; @@ -550,7 +564,7 @@ EXPORT_C GSvsync(int field) #endif #ifdef OGL_MT_HACK - s_gs->m_wnd.AttachContext(); + s_gs->m_wnd->AttachContext(); #endif s_gs->VSync(field); } @@ -623,7 +637,7 @@ EXPORT_C GSconfigure() if(GSSettingsDlg(s_isgsopen2).DoModal() == IDOK) { - if(s_gs != NULL && s_gs->m_wnd.IsManaged()) + if(s_gs != NULL && s_gs->m_wnd->IsManaged()) { // Legacy apps like gsdxgui expect this... @@ -637,7 +651,7 @@ EXPORT_C GSconfigure() if (RunLinuxDialog()) { - if(s_gs != NULL && s_gs->m_wnd.IsManaged()) + if(s_gs != NULL && s_gs->m_wnd->IsManaged()) { GSshutdown(); } diff --git a/plugins/GSdx/GSDevice.cpp b/plugins/GSdx/GSDevice.cpp index 830591abb8..37f7bcdd30 100644 --- a/plugins/GSdx/GSDevice.cpp +++ b/plugins/GSdx/GSDevice.cpp @@ -393,4 +393,4 @@ GSAdapter::GSAdapter(const D3DADAPTER_IDENTIFIER9 &desc_d3d9) #endif #ifdef _LINUX // TODO -#endif \ No newline at end of file +#endif diff --git a/plugins/GSdx/GSRenderer.cpp b/plugins/GSdx/GSRenderer.cpp index 2c2d7a9b17..ee1ea5c7bb 100644 --- a/plugins/GSdx/GSRenderer.cpp +++ b/plugins/GSdx/GSRenderer.cpp @@ -23,7 +23,8 @@ #include "GSRenderer.h" GSRenderer::GSRenderer() - : m_dev(NULL) + : m_wnd(NULL) + , m_dev(NULL) , m_shader(0) , m_shift_key(false) , m_control_key(false) @@ -52,7 +53,7 @@ GSRenderer::~GSRenderer() bool GSRenderer::CreateWnd(const string& title, int w, int h) { - return m_wnd.Create(title.c_str(), w, h); + return m_wnd->Create(title.c_str(), w, h); } bool GSRenderer::CreateDevice(GSDevice* dev) @@ -60,7 +61,7 @@ bool GSRenderer::CreateDevice(GSDevice* dev) ASSERT(dev); ASSERT(!m_dev); - if(!dev->Create(&m_wnd)) + if(!dev->Create(m_wnd)) { return false; } @@ -330,7 +331,7 @@ void GSRenderer::VSync(int field) #ifdef GSTITLEINFO_API_FORCE_VERBOSE if (1)//force verbose reply #else - if (m_wnd.IsManaged()) + if (m_wnd->IsManaged()) #endif { //GSdx owns the window's title, be verbose. @@ -379,9 +380,9 @@ void GSRenderer::VSync(int field) s += " | Recording..."; } - if(m_wnd.IsManaged()) + if(m_wnd->IsManaged()) { - m_wnd.SetWindowText(s.c_str()); + m_wnd->SetWindowText(s.c_str()); } else { @@ -411,7 +412,7 @@ void GSRenderer::VSync(int field) // present - m_dev->Present(m_wnd.GetClientRect().fit(m_aspectratio), m_shader); + m_dev->Present(m_wnd->GetClientRect().fit(m_aspectratio), m_shader); // snapshot @@ -537,7 +538,7 @@ void GSRenderer::KeyEvent(GSKeyEventData* e) printf("GSdx: Set deinterlace mode to %d (%s).\n", (int)m_interlace, theApp.m_gs_interlace.at(m_interlace).name.c_str()); return; case VK_F6: - if( m_wnd.IsManaged() ) + if( m_wnd->IsManaged() ) m_aspectratio = (m_aspectratio + 3 + step) % 3; return; case VK_F7: @@ -571,7 +572,7 @@ void GSRenderer::KeyEvent(GSKeyEventData* e) fprintf(stderr, "GSdx: Set deinterlace mode to %d (%s).\n", (int)m_interlace, theApp.m_gs_interlace.at(m_interlace).name.c_str()); return; case XK_F6: - if( m_wnd.IsManaged() ) + if( m_wnd->IsManaged() ) m_aspectratio = (m_aspectratio + 3 + step) % 3; return; case XK_F7: diff --git a/plugins/GSdx/GSRenderer.h b/plugins/GSdx/GSRenderer.h index bfffd72404..394f489363 100644 --- a/plugins/GSdx/GSRenderer.h +++ b/plugins/GSdx/GSRenderer.h @@ -53,7 +53,7 @@ protected: virtual GSTexture* GetOutput(int i) = 0; public: - GSWnd m_wnd; + GSWnd* m_wnd; GSDevice* m_dev; public: @@ -80,4 +80,4 @@ public: GSCritSec m_pGSsetTitle_Crit; char m_GStitleInfoBuffer[128]; -}; \ No newline at end of file +}; diff --git a/plugins/GSdx/GSState.cpp b/plugins/GSdx/GSState.cpp index 6a58518031..c6292e116b 100644 --- a/plugins/GSdx/GSState.cpp +++ b/plugins/GSdx/GSState.cpp @@ -1261,7 +1261,7 @@ void GSState::GIFRegHandlerTRXDIR(const GIFReg* RESTRICT r) case 1: // local -> host m_tr.Init(m_env.TRXPOS.SSAX, m_env.TRXPOS.SSAY); #ifdef OGL_MT_HACK - s_gs->m_wnd.DetachContext(); + s_gs->m_wnd->DetachContext(); #endif break; case 2: // local -> local @@ -1768,7 +1768,7 @@ template void GSState::Transfer(const uint8* mem, uint32 size) { GSPerfMonAutoTimer pmat(&m_perfmon); #ifdef OGL_MT_HACK - s_gs->m_wnd.AttachContext(); + s_gs->m_wnd->AttachContext(); #endif const uint8* start = mem; diff --git a/plugins/GSdx/GSWnd.cpp b/plugins/GSdx/GSWnd.cpp index 88150e7c61..b284c39f91 100644 --- a/plugins/GSdx/GSWnd.cpp +++ b/plugins/GSdx/GSWnd.cpp @@ -18,447 +18,3 @@ * http://www.gnu.org/copyleft/gpl.html * */ - -#include "stdafx.h" -#include "GSdx.h" -#include "GSWnd.h" - -#ifdef _WINDOWS - -GSWnd::GSWnd() - : m_hWnd(NULL) - , m_managed(true) - , m_frame(true) -{ -} - -GSWnd::~GSWnd() -{ -} - -LRESULT CALLBACK GSWnd::WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) -{ - GSWnd* wnd = NULL; - - if(message == WM_NCCREATE) - { - wnd = (GSWnd*)((LPCREATESTRUCT)lParam)->lpCreateParams; - - SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR)wnd); - - wnd->m_hWnd = hWnd; - } - else - { - wnd = (GSWnd*)GetWindowLongPtr(hWnd, GWLP_USERDATA); - } - - if(wnd == NULL) - { - return DefWindowProc(hWnd, message, wParam, lParam); - } - - return wnd->OnMessage(message, wParam, lParam); -} - -LRESULT GSWnd::OnMessage(UINT message, WPARAM wParam, LPARAM lParam) -{ - switch(message) - { - case WM_CLOSE: - Hide(); - // DestroyWindow(m_hWnd); - return 0; - case WM_DESTROY: - // This kills the emulator when GS is closed, which *really* isn't desired behavior, - // especially in STGS mode (worked in MTGS mode since it only quit the thread, but even - // that wasn't needed). - //PostQuitMessage(0); - return 0; - default: - break; - } - - return DefWindowProc((HWND)m_hWnd, message, wParam, lParam); -} - -bool GSWnd::Create(const string& title, int w, int h) -{ - if(m_hWnd) return false; - - WNDCLASS wc; - - memset(&wc, 0, sizeof(wc)); - - wc.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS; - wc.lpfnWndProc = WndProc; - wc.hInstance = theApp.GetModuleHandle(); - // TODO: wc.hIcon = ; - wc.hCursor = LoadCursor(NULL, IDC_ARROW); - wc.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH); - wc.lpszClassName = "GSWnd"; - - if(!GetClassInfo(wc.hInstance, wc.lpszClassName, &wc)) - { - if(!RegisterClass(&wc)) - { - return false; - } - } - - DWORD style = WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_OVERLAPPEDWINDOW | WS_BORDER; - - GSVector4i r; - - GetWindowRect(GetDesktopWindow(), r); - - bool remote = !!GetSystemMetrics(SM_REMOTESESSION); - - if(w <= 0 || h <= 0 || remote) - { - w = r.width() / 3; - h = r.width() / 4; - - if(!remote) - { - w *= 2; - h *= 2; - } - } - - r.left = (r.left + r.right - w) / 2; - r.top = (r.top + r.bottom - h) / 2; - r.right = r.left + w; - r.bottom = r.top + h; - - AdjustWindowRect(r, style, FALSE); - - m_hWnd = CreateWindow(wc.lpszClassName, title.c_str(), style, r.left, r.top, r.width(), r.height(), NULL, NULL, wc.hInstance, (LPVOID)this); - - return m_hWnd != NULL; -} - -bool GSWnd::Attach(void* handle, bool managed) -{ - // TODO: subclass - - m_hWnd = (HWND)handle; - m_managed = managed; - - return true; -} - -void GSWnd::Detach() -{ - if(m_hWnd && m_managed) - { - // close the window, since it's under GSdx care. It's not taking messages anyway, and - // that means its big, ugly, and in the way. - - DestroyWindow(m_hWnd); - } - - m_hWnd = NULL; - m_managed = true; -} - -GSVector4i GSWnd::GetClientRect() -{ - GSVector4i r; - - ::GetClientRect(m_hWnd, r); - - return r; -} - -// Returns FALSE if the window has no title, or if th window title is under the strict -// management of the emulator. - -bool GSWnd::SetWindowText(const char* title) -{ - if(!m_managed) return false; - - ::SetWindowText(m_hWnd, title); - - return m_frame; -} - -void GSWnd::Show() -{ - if(!m_managed) return; - - SetForegroundWindow(m_hWnd); - ShowWindow(m_hWnd, SW_SHOWNORMAL); - UpdateWindow(m_hWnd); -} - -void GSWnd::Hide() -{ - if(!m_managed) return; - - ShowWindow(m_hWnd, SW_HIDE); -} - -void GSWnd::HideFrame() -{ - if(!m_managed) return; - - SetWindowLong(m_hWnd, GWL_STYLE, GetWindowLong(m_hWnd, GWL_STYLE) & ~(WS_CAPTION|WS_THICKFRAME)); - SetWindowPos(m_hWnd, NULL, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE); - SetMenu(m_hWnd, NULL); - - m_frame = false; -} - -#else - -GSWnd::GSWnd() - : m_window(NULL), m_Xwindow(0), m_XDisplay(NULL), m_ctx_attached(false), m_swapinterval(NULL) -{ -} - -GSWnd::~GSWnd() -{ - if (m_XDisplay) { - XCloseDisplay(m_XDisplay); - m_XDisplay = NULL; - } -} - -bool GSWnd::CreateContext(int major, int minor) -{ - if ( !m_XDisplay || !m_Xwindow ) - { - fprintf( stderr, "Wrong X11 display/window\n" ); - exit(1); - } - - // Get visual information - static int attrListDbl[] = - { - // GLX_X_RENDERABLE: If True is specified, then only frame buffer configurations that have associated X - // visuals (and can be used to render to Windows and/or GLX pixmaps) will be considered. The default value is GLX_DONT_CARE. - GLX_X_RENDERABLE , True, - GLX_RED_SIZE , 8, - GLX_GREEN_SIZE , 8, - GLX_BLUE_SIZE , 8, - GLX_DEPTH_SIZE , 24, - GLX_DOUBLEBUFFER , True, - None - }; - - PFNGLXCHOOSEFBCONFIGPROC glXChooseFBConfig = (PFNGLXCHOOSEFBCONFIGPROC) glXGetProcAddress((GLubyte *) "glXChooseFBConfig"); - int fbcount = 0; - GLXFBConfig *fbc = glXChooseFBConfig(m_XDisplay, DefaultScreen(m_XDisplay), attrListDbl, &fbcount); - if (!fbc || fbcount < 1) return false; - - PFNGLXCREATECONTEXTATTRIBSARBPROC glXCreateContextAttribsARB = (PFNGLXCREATECONTEXTATTRIBSARBPROC)glXGetProcAddress((const GLubyte*) "glXCreateContextAttribsARB"); - if (!glXCreateContextAttribsARB) return false; - - // Create a context - int context_attribs[] = - { - GLX_CONTEXT_MAJOR_VERSION_ARB, major, - GLX_CONTEXT_MINOR_VERSION_ARB, minor, - // FIXME : Request a debug context to ease opengl development - // Note: don't support deprecated feature (pre openg 3.1) - //GLX_CONTEXT_FLAGS_ARB, GLX_CONTEXT_DEBUG_BIT_ARB | GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB, - GLX_CONTEXT_FLAGS_ARB, GLX_CONTEXT_DEBUG_BIT_ARB, - None - }; - - m_context = glXCreateContextAttribsARB(m_XDisplay, fbc[0], 0, true, context_attribs); - if (!m_context) return false; - - XSync( m_XDisplay, false); - return true; -} - -void GSWnd::AttachContext() -{ - if (!IsContextAttached()) { - //fprintf(stderr, "Attach the context\n"); - glXMakeCurrent(m_XDisplay, m_Xwindow, m_context); - m_ctx_attached = true; - } -} - -void GSWnd::DetachContext() -{ - if (IsContextAttached()) { - //fprintf(stderr, "Detach the context\n"); - glXMakeCurrent(m_XDisplay, None, NULL); - m_ctx_attached = false; - } -} - -void GSWnd::CheckContext() -{ - int glxMajorVersion, glxMinorVersion; - glXQueryVersion(m_XDisplay, &glxMajorVersion, &glxMinorVersion); - if (glXIsDirect(m_XDisplay, m_context)) - fprintf(stderr, "glX-Version %d.%d with Direct Rendering\n", glxMajorVersion, glxMinorVersion); - else - fprintf(stderr, "glX-Version %d.%d with Indirect Rendering !!! It won't support properly opengl\n", glxMajorVersion, glxMinorVersion); -} - -bool GSWnd::Attach(void* handle, bool managed) -{ - m_Xwindow = *(Window*)handle; - m_managed = managed; - - m_renderer = theApp.GetConfig("renderer", 0) / 3; - assert(m_renderer != 2); - - m_XDisplay = XOpenDisplay(NULL); - - // Note: 4.2 crash on latest nvidia drivers! - if (!CreateContext(3, 3)) return false; - - AttachContext(); - - CheckContext(); - - PFNGLXSWAPINTERVALMESAPROC m_swapinterval = (PFNGLXSWAPINTERVALMESAPROC)glXGetProcAddress((const GLubyte*) "glXSwapIntervalMESA"); - //PFNGLXSWAPINTERVALMESAPROC m_swapinterval = (PFNGLXSWAPINTERVALMESAPROC)glXGetProcAddress((const GLubyte*) "glXSwapInterval"); - - - return true; -} - -void GSWnd::Detach() -{ - // Actually the destructor is not called when there is only a GSclose/GSshutdown - // The window still need to be closed - DetachContext(); - if (m_context) glXDestroyContext(m_XDisplay, m_context); - - if (m_XDisplay) { - XCloseDisplay(m_XDisplay); - m_XDisplay = NULL; - } -} - -bool GSWnd::Create(const string& title, int w, int h) -{ - if(m_window != NULL) return false; - - if(w <= 0 || h <= 0) { - w = theApp.GetConfig("ModeWidth", 640); - h = theApp.GetConfig("ModeHeight", 480); - } - - m_managed = true; - - // note this part must be only executed when replaying .gs debug file - m_XDisplay = XOpenDisplay(NULL); - - int attrListDbl[] = { GLX_RGBA, GLX_DOUBLEBUFFER, - GLX_RED_SIZE, 8, - GLX_GREEN_SIZE, 8, - GLX_BLUE_SIZE, 8, - GLX_DEPTH_SIZE, 24, - None - }; - XVisualInfo* vi = glXChooseVisual(m_XDisplay, DefaultScreen(m_XDisplay), attrListDbl); - - /* create a color map */ - XSetWindowAttributes attr; - attr.colormap = XCreateColormap(m_XDisplay, RootWindow(m_XDisplay, vi->screen), - vi->visual, AllocNone); - attr.border_pixel = 0; - attr.event_mask = ExposureMask | KeyPressMask | KeyReleaseMask | ButtonPressMask | - StructureNotifyMask | SubstructureRedirectMask | SubstructureNotifyMask | - EnterWindowMask | LeaveWindowMask | FocusChangeMask ; - - // Create a window at the last position/size - m_Xwindow = XCreateWindow(m_XDisplay, RootWindow(m_XDisplay, vi->screen), - 0 , 0 , w, h, 0, vi->depth, InputOutput, vi->visual, - CWBorderPixel | CWColormap | CWEventMask, &attr); - - XMapWindow (m_XDisplay, m_Xwindow); - XFree(vi); - - if (!CreateContext(3, 3)) return false; - - AttachContext(); - - return (m_Xwindow != 0); -} - -Display* GSWnd::GetDisplay() -{ - // note this part must be only executed when replaying .gs debug file - return m_XDisplay; -} - -GSVector4i GSWnd::GetClientRect() -{ - unsigned int h = 480; - unsigned int w = 640; - - unsigned int borderDummy; - unsigned int depthDummy; - Window winDummy; - int xDummy; - int yDummy; - - if (!m_XDisplay) m_XDisplay = XOpenDisplay(NULL); - XGetGeometry(m_XDisplay, m_Xwindow, &winDummy, &xDummy, &yDummy, &w, &h, &borderDummy, &depthDummy); - - return GSVector4i(0, 0, (int)w, (int)h); -} - -// Returns FALSE if the window has no title, or if th window title is under the strict -// management of the emulator. - -bool GSWnd::SetWindowText(const char* title) -{ - if (!m_managed) return true; - - XTextProperty prop; - - memset(&prop, 0, sizeof(prop)); - - char* ptitle = (char*)title; - if (XStringListToTextProperty(&ptitle, 1, &prop)) { - XSetWMName(m_XDisplay, m_Xwindow, &prop); - } - - XFree(prop.value); - XFlush(m_XDisplay); - - return true; -} - -void GSWnd::SetVSync(bool enable) -{ - // m_swapinterval uses an integer as parameter - // 0 -> disable vsync - // n -> wait n frame - if (m_swapinterval) m_swapinterval((int)enable); -} - -void GSWnd::Flip() -{ - glXSwapBuffers(m_XDisplay, m_Xwindow); -} - -void GSWnd::Show() -{ - XMapRaised(m_XDisplay, m_Xwindow); - XFlush(m_XDisplay); -} - -void GSWnd::Hide() -{ - XUnmapWindow(m_XDisplay, m_Xwindow); - XFlush(m_XDisplay); -} - -void GSWnd::HideFrame() -{ - // TODO -} - -#endif diff --git a/plugins/GSdx/GSWnd.h b/plugins/GSdx/GSWnd.h index 634bc5ce18..4b71b1a1b7 100644 --- a/plugins/GSdx/GSWnd.h +++ b/plugins/GSdx/GSWnd.h @@ -21,81 +21,37 @@ #pragma once +#include "stdafx.h" +#include "GSdx.h" #include "GSVector.h" -#ifdef _WINDOWS - class GSWnd { - HWND m_hWnd; - +protected: bool m_managed; // set true when we're attached to a 3rdparty window that's amanged by the emulator - bool m_frame; - - static LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam); - virtual LRESULT OnMessage(UINT message, WPARAM wParam, LPARAM lParam); public: - GSWnd(); - virtual ~GSWnd(); + GSWnd() : m_managed(false) {}; + virtual ~GSWnd() {}; - bool Create(const string& title, int w, int h); - bool Attach(void* handle, bool managed = true); - void Detach(); + virtual bool Create(const string& title, int w, int h) = 0; + virtual bool Attach(void* handle, bool managed = true) = 0; + virtual void Detach() = 0; bool IsManaged() const {return m_managed;} - void* GetDisplay() {return m_hWnd;} - void* GetHandle() {return m_hWnd;} - GSVector4i GetClientRect(); - bool SetWindowText(const char* title); + virtual void* GetDisplay() = 0; + virtual void* GetHandle() = 0; + virtual GSVector4i GetClientRect() = 0; + virtual bool SetWindowText(const char* title) = 0; + + virtual void AttachContext() {}; + virtual void DetachContext() {}; + + virtual void Show() = 0; + virtual void Hide() = 0; + virtual void HideFrame() = 0; + + virtual void Flip() {}; + virtual void SetVSync(bool enable) {}; - void Show(); - void Hide(); - void HideFrame(); }; - -#else - -#include - -class GSWnd -{ - void* m_window; - Window m_Xwindow; - Display* m_XDisplay; - - bool m_ctx_attached; - bool m_managed; - int m_renderer; - GLXContext m_context; - - PFNGLXSWAPINTERVALMESAPROC m_swapinterval; - -public: - GSWnd(); - virtual ~GSWnd(); - - bool Create(const string& title, int w, int h); - bool Attach(void* handle, bool managed = true); - void Detach(); - bool IsManaged() const {return m_managed;} - bool IsContextAttached() const { return m_ctx_attached; } - - Display* GetDisplay(); - void* GetHandle() {return (void*)m_Xwindow;} - GSVector4i GetClientRect(); - bool SetWindowText(const char* title); - - bool CreateContext(int major, int minor); - void AttachContext(); - void DetachContext(); - void CheckContext(); - - void Show(); - void Hide(); - void HideFrame(); - void Flip(); - void SetVSync(bool enable); -}; - -#endif diff --git a/plugins/GSdx/GSWndDX.cpp b/plugins/GSdx/GSWndDX.cpp new file mode 100644 index 0000000000..37b6c3b971 --- /dev/null +++ b/plugins/GSdx/GSWndDX.cpp @@ -0,0 +1,208 @@ +/* + * Copyright (C) 2007-2012 Gabest + * http://www.gabest.org + * + * 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 GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +#include "GSWndDX.h" + +#ifdef _WINDOWS +GSWndDX::GSWndDX() + : m_hWnd(NULL) + , m_frame(true) +{ +} + +GSWndDX::~GSWndDX() +{ +} + +LRESULT CALLBACK GSWndDX::WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) +{ + GSWnd* wnd = NULL; + + if(message == WM_NCCREATE) + { + wnd = (GSWnd*)((LPCREATESTRUCT)lParam)->lpCreateParams; + + SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR)wnd); + + wnd->m_hWnd = hWnd; + } + else + { + wnd = (GSWnd*)GetWindowLongPtr(hWnd, GWLP_USERDATA); + } + + if(wnd == NULL) + { + return DefWindowProc(hWnd, message, wParam, lParam); + } + + return wnd->OnMessage(message, wParam, lParam); +} + +LRESULT GSWndDX::OnMessage(UINT message, WPARAM wParam, LPARAM lParam) +{ + switch(message) + { + case WM_CLOSE: + Hide(); + // DestroyWindow(m_hWnd); + return 0; + case WM_DESTROY: + // This kills the emulator when GS is closed, which *really* isn't desired behavior, + // especially in STGS mode (worked in MTGS mode since it only quit the thread, but even + // that wasn't needed). + //PostQuitMessage(0); + return 0; + default: + break; + } + + return DefWindowProc((HWND)m_hWnd, message, wParam, lParam); +} + +bool GSWndDX::Create(const string& title, int w, int h) +{ + if(m_hWnd) return false; + + WNDCLASS wc; + + memset(&wc, 0, sizeof(wc)); + + wc.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS; + wc.lpfnWndProc = WndProc; + wc.hInstance = theApp.GetModuleHandle(); + // TODO: wc.hIcon = ; + wc.hCursor = LoadCursor(NULL, IDC_ARROW); + wc.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH); + wc.lpszClassName = "GSWnd"; + + if(!GetClassInfo(wc.hInstance, wc.lpszClassName, &wc)) + { + if(!RegisterClass(&wc)) + { + return false; + } + } + + DWORD style = WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_OVERLAPPEDWINDOW | WS_BORDER; + + GSVector4i r; + + GetWindowRect(GetDesktopWindow(), r); + + bool remote = !!GetSystemMetrics(SM_REMOTESESSION); + + if(w <= 0 || h <= 0 || remote) + { + w = r.width() / 3; + h = r.width() / 4; + + if(!remote) + { + w *= 2; + h *= 2; + } + } + + r.left = (r.left + r.right - w) / 2; + r.top = (r.top + r.bottom - h) / 2; + r.right = r.left + w; + r.bottom = r.top + h; + + AdjustWindowRect(r, style, FALSE); + + m_hWnd = CreateWindow(wc.lpszClassName, title.c_str(), style, r.left, r.top, r.width(), r.height(), NULL, NULL, wc.hInstance, (LPVOID)this); + + return m_hWnd != NULL; +} + +bool GSWndDX::Attach(void* handle, bool managed) +{ + // TODO: subclass + + m_hWnd = (HWND)handle; + m_managed = managed; + + return true; +} + +void GSWndDX::Detach() +{ + if(m_hWnd && m_managed) + { + // close the window, since it's under GSdx care. It's not taking messages anyway, and + // that means its big, ugly, and in the way. + + DestroyWindow(m_hWnd); + } + + m_hWnd = NULL; + m_managed = true; +} + +GSVector4i GSWndDX::GetClientRect() +{ + GSVector4i r; + + ::GetClientRect(m_hWnd, r); + + return r; +} + +// Returns FALSE if the window has no title, or if th window title is under the strict +// management of the emulator. + +bool GSWndDX::SetWindowText(const char* title) +{ + if(!m_managed) return false; + + ::SetWindowText(m_hWnd, title); + + return m_frame; +} + +void GSWndDX::Show() +{ + if(!m_managed) return; + + SetForegroundWindow(m_hWnd); + ShowWindow(m_hWnd, SW_SHOWNORMAL); + UpdateWindow(m_hWnd); +} + +void GSWndDX::Hide() +{ + if(!m_managed) return; + + ShowWindow(m_hWnd, SW_HIDE); +} + +void GSWndDX::HideFrame() +{ + if(!m_managed) return; + + SetWindowLong(m_hWnd, GWL_STYLE, GetWindowLong(m_hWnd, GWL_STYLE) & ~(WS_CAPTION|WS_THICKFRAME)); + SetWindowPos(m_hWnd, NULL, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE); + SetMenu(m_hWnd, NULL); + + m_frame = false; +} +#endif diff --git a/plugins/GSdx/GSWndDX.h b/plugins/GSdx/GSWndDX.h new file mode 100644 index 0000000000..c3085a00bb --- /dev/null +++ b/plugins/GSdx/GSWndDX.h @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2007-2012 Gabest + * http://www.gabest.org + * + * 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 GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +#include "GSWnd.h" + +#ifdef _WINDOWS +class GSWndDX : public GSWnd +{ + HWND m_hWnd; + + bool m_frame; + + static LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam); + virtual LRESULT OnMessage(UINT message, WPARAM wParam, LPARAM lParam); + +public: + GSWndDX(); + virtual ~GSWndDX(); + + bool Create(const string& title, int w, int h); + bool Attach(void* handle, bool managed = true); + void Detach(); + + void* GetDisplay() {return m_hWnd;} + void* GetHandle() {return m_hWnd;} + GSVector4i GetClientRect(); + bool SetWindowText(const char* title); + + void Show(); + void Hide(); + void HideFrame(); +}; +#endif diff --git a/plugins/GSdx/GSWndOGL.cpp b/plugins/GSdx/GSWndOGL.cpp new file mode 100644 index 0000000000..a56655e99a --- /dev/null +++ b/plugins/GSdx/GSWndOGL.cpp @@ -0,0 +1,262 @@ +/* + * Copyright (C) 2007-2012 Gabest + * http://www.gabest.org + * + * 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 GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +#include "GSWndOGL.h" + +#ifdef _LINUX +GSWndOGL::GSWndOGL() + : m_window(NULL), m_Xwindow(0), m_XDisplay(NULL), m_swapinterval(NULL) +{ +} + +bool GSWndOGL::CreateContext(int major, int minor) +{ + if ( !m_XDisplay || !m_Xwindow ) + { + fprintf( stderr, "Wrong X11 display/window\n" ); + exit(1); + } + + // Get visual information + static int attrListDbl[] = + { + // GLX_X_RENDERABLE: If True is specified, then only frame buffer configurations that have associated X + // visuals (and can be used to render to Windows and/or GLX pixmaps) will be considered. The default value is GLX_DONT_CARE. + GLX_X_RENDERABLE , True, + GLX_RED_SIZE , 8, + GLX_GREEN_SIZE , 8, + GLX_BLUE_SIZE , 8, + GLX_DEPTH_SIZE , 24, + GLX_DOUBLEBUFFER , True, + None + }; + + PFNGLXCHOOSEFBCONFIGPROC glXChooseFBConfig = (PFNGLXCHOOSEFBCONFIGPROC) glXGetProcAddress((GLubyte *) "glXChooseFBConfig"); + int fbcount = 0; + GLXFBConfig *fbc = glXChooseFBConfig(m_XDisplay, DefaultScreen(m_XDisplay), attrListDbl, &fbcount); + if (!fbc || fbcount < 1) return false; + + PFNGLXCREATECONTEXTATTRIBSARBPROC glXCreateContextAttribsARB = (PFNGLXCREATECONTEXTATTRIBSARBPROC)glXGetProcAddress((const GLubyte*) "glXCreateContextAttribsARB"); + if (!glXCreateContextAttribsARB) return false; + + // Create a context + int context_attribs[] = + { + GLX_CONTEXT_MAJOR_VERSION_ARB, major, + GLX_CONTEXT_MINOR_VERSION_ARB, minor, + // FIXME : Request a debug context to ease opengl development + // Note: don't support deprecated feature (pre openg 3.1) + //GLX_CONTEXT_FLAGS_ARB, GLX_CONTEXT_DEBUG_BIT_ARB | GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB, + GLX_CONTEXT_FLAGS_ARB, GLX_CONTEXT_DEBUG_BIT_ARB, + None + }; + + m_context = glXCreateContextAttribsARB(m_XDisplay, fbc[0], 0, true, context_attribs); + if (!m_context) return false; + + XSync( m_XDisplay, false); + return true; +} + +void GSWndOGL::AttachContext() +{ + if (!IsContextAttached()) { + //fprintf(stderr, "Attach the context\n"); + glXMakeCurrent(m_XDisplay, m_Xwindow, m_context); + m_ctx_attached = true; + } +} + +void GSWndOGL::DetachContext() +{ + if (IsContextAttached()) { + //fprintf(stderr, "Detach the context\n"); + glXMakeCurrent(m_XDisplay, None, NULL); + m_ctx_attached = false; + } +} + +void GSWndOGL::CheckContext() +{ + int glxMajorVersion, glxMinorVersion; + glXQueryVersion(m_XDisplay, &glxMajorVersion, &glxMinorVersion); + if (glXIsDirect(m_XDisplay, m_context)) + fprintf(stderr, "glX-Version %d.%d with Direct Rendering\n", glxMajorVersion, glxMinorVersion); + else + fprintf(stderr, "glX-Version %d.%d with Indirect Rendering !!! It won't support properly opengl\n", glxMajorVersion, glxMinorVersion); +} + +bool GSWndOGL::Attach(void* handle, bool managed) +{ + m_Xwindow = *(Window*)handle; + m_managed = managed; + + m_XDisplay = XOpenDisplay(NULL); + + // Note: 4.2 crash on latest nvidia drivers! + if (!CreateContext(3, 3)) return false; + + AttachContext(); + + CheckContext(); + + m_swapinterval = (PFNGLXSWAPINTERVALMESAPROC)glXGetProcAddress((const GLubyte*) "glXSwapIntervalMESA"); + //PFNGLXSWAPINTERVALMESAPROC m_swapinterval = (PFNGLXSWAPINTERVALMESAPROC)glXGetProcAddress((const GLubyte*) "glXSwapInterval"); + + + return true; +} + +void GSWndOGL::Detach() +{ + // Actually the destructor is not called when there is only a GSclose/GSshutdown + // The window still need to be closed + DetachContext(); + if (m_context) glXDestroyContext(m_XDisplay, m_context); + + if (m_XDisplay) { + XCloseDisplay(m_XDisplay); + m_XDisplay = NULL; + } +} + +bool GSWndOGL::Create(const string& title, int w, int h) +{ + if(m_window != NULL) return false; + + if(w <= 0 || h <= 0) { + w = theApp.GetConfig("ModeWidth", 640); + h = theApp.GetConfig("ModeHeight", 480); + } + + m_managed = true; + + // note this part must be only executed when replaying .gs debug file + m_XDisplay = XOpenDisplay(NULL); + + int attrListDbl[] = { GLX_RGBA, GLX_DOUBLEBUFFER, + GLX_RED_SIZE, 8, + GLX_GREEN_SIZE, 8, + GLX_BLUE_SIZE, 8, + GLX_DEPTH_SIZE, 24, + None + }; + XVisualInfo* vi = glXChooseVisual(m_XDisplay, DefaultScreen(m_XDisplay), attrListDbl); + + /* create a color map */ + XSetWindowAttributes attr; + attr.colormap = XCreateColormap(m_XDisplay, RootWindow(m_XDisplay, vi->screen), + vi->visual, AllocNone); + attr.border_pixel = 0; + attr.event_mask = ExposureMask | KeyPressMask | KeyReleaseMask | ButtonPressMask | + StructureNotifyMask | SubstructureRedirectMask | SubstructureNotifyMask | + EnterWindowMask | LeaveWindowMask | FocusChangeMask ; + + // Create a window at the last position/size + m_Xwindow = XCreateWindow(m_XDisplay, RootWindow(m_XDisplay, vi->screen), + 0 , 0 , w, h, 0, vi->depth, InputOutput, vi->visual, + CWBorderPixel | CWColormap | CWEventMask, &attr); + + XMapWindow (m_XDisplay, m_Xwindow); + XFree(vi); + + if (!CreateContext(3, 3)) return false; + + AttachContext(); + + return (m_Xwindow != 0); +} + +void* GSWndOGL::GetDisplay() +{ + // note this part must be only executed when replaying .gs debug file + return (void*)m_XDisplay; +} + +GSVector4i GSWndOGL::GetClientRect() +{ + unsigned int h = 480; + unsigned int w = 640; + + unsigned int borderDummy; + unsigned int depthDummy; + Window winDummy; + int xDummy; + int yDummy; + + if (!m_XDisplay) m_XDisplay = XOpenDisplay(NULL); + XGetGeometry(m_XDisplay, m_Xwindow, &winDummy, &xDummy, &yDummy, &w, &h, &borderDummy, &depthDummy); + + return GSVector4i(0, 0, (int)w, (int)h); +} + +// Returns FALSE if the window has no title, or if th window title is under the strict +// management of the emulator. + +bool GSWndOGL::SetWindowText(const char* title) +{ + if (!m_managed) return true; + + XTextProperty prop; + + memset(&prop, 0, sizeof(prop)); + + char* ptitle = (char*)title; + if (XStringListToTextProperty(&ptitle, 1, &prop)) { + XSetWMName(m_XDisplay, m_Xwindow, &prop); + } + + XFree(prop.value); + XFlush(m_XDisplay); + + return true; +} + +void GSWndOGL::SetVSync(bool enable) +{ + // m_swapinterval uses an integer as parameter + // 0 -> disable vsync + // n -> wait n frame + if (m_swapinterval) m_swapinterval((int)enable); +} + +void GSWndOGL::Flip() +{ + glXSwapBuffers(m_XDisplay, m_Xwindow); +} + +void GSWndOGL::Show() +{ + XMapRaised(m_XDisplay, m_Xwindow); + XFlush(m_XDisplay); +} + +void GSWndOGL::Hide() +{ + XUnmapWindow(m_XDisplay, m_Xwindow); + XFlush(m_XDisplay); +} + +void GSWndOGL::HideFrame() +{ + // TODO +} +#endif diff --git a/plugins/GSdx/GSWndOGL.h b/plugins/GSdx/GSWndOGL.h new file mode 100644 index 0000000000..c6f34f68b3 --- /dev/null +++ b/plugins/GSdx/GSWndOGL.h @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2007-2012 Gabest + * http://www.gabest.org + * + * 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 GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +#include "GSWnd.h" +#include + +#ifdef _LINUX +class GSWndOGL : public GSWnd +{ + void* m_window; + Window m_Xwindow; + Display* m_XDisplay; + GLXContext m_context; + + bool m_ctx_attached; + + PFNGLXSWAPINTERVALMESAPROC m_swapinterval; + + bool IsContextAttached() const { return m_ctx_attached; } + bool CreateContext(int major, int minor); + void CheckContext(); + +public: + GSWndOGL(); + virtual ~GSWndOGL() {}; + + bool Create(const string& title, int w, int h); + bool Attach(void* handle, bool managed = true); + void Detach(); + + void* GetDisplay(); + void* GetHandle() {return (void*)m_Xwindow;} + GSVector4i GetClientRect(); + bool SetWindowText(const char* title); + + void AttachContext(); + void DetachContext(); + + void Show(); + void Hide(); + void HideFrame(); + void Flip(); + void SetVSync(bool enable); +}; +#endif