Merge pull request #176 from SuuperW/refactor

Refactor+Bugfixes
This commit is contained in:
zeromus 2018-08-28 13:50:27 -05:00 committed by GitHub
commit b3a352a409
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 1556 additions and 1310 deletions

View File

@ -284,6 +284,8 @@
<ClCompile Include="colorctrl.cpp" />
<ClCompile Include="console.cpp" />
<ClCompile Include="CWindow.cpp" />
<ClCompile Include="ddraw.cpp" />
<ClCompile Include="display.cpp" />
<ClCompile Include="FEX_Interface.cpp" />
<ClCompile Include="File_Extractor\7z_C\7zAlloc.c" />
<ClCompile Include="File_Extractor\7z_C\7zBuf.c" />
@ -371,6 +373,7 @@
<ClCompile Include="main.cpp" />
<ClCompile Include="mic-win.cpp" />
<ClCompile Include="ogl.cpp" />
<ClCompile Include="ogl_display.cpp" />
<ClCompile Include="OpenArchive.cpp" />
<ClCompile Include="pathsettings.cpp" />
<ClCompile Include="recentroms.cpp" />
@ -582,6 +585,8 @@
<ClInclude Include="colorctrl.h" />
<ClInclude Include="console.h" />
<ClInclude Include="CWindow.h" />
<ClInclude Include="ddraw.h" />
<ClInclude Include="display.h" />
<ClInclude Include="FEX_Interface.h" />
<ClInclude Include="File_Extractor\7z_C\7z.h" />
<ClInclude Include="File_Extractor\7z_C\7zAlloc.h" />
@ -657,6 +662,7 @@
<ClInclude Include="importSave.h" />
<ClInclude Include="inputdx.h" />
<ClInclude Include="main.h" />
<ClInclude Include="ogl_display.h" />
<ClInclude Include="OpenArchive.h" />
<ClInclude Include="pathsettings.h" />
<ClInclude Include="recentroms.h" />

View File

@ -921,6 +921,15 @@
<ClCompile Include="..\..\utils\colorspacehandler\colorspacehandler_AltiVec.cpp">
<Filter>utils\colorspacehandler</Filter>
</ClCompile>
<ClCompile Include="ddraw.cpp">
<Filter>frontend\Windows</Filter>
</ClCompile>
<ClCompile Include="ogl_display.cpp">
<Filter>frontend\Windows</Filter>
</ClCompile>
<ClCompile Include="display.cpp">
<Filter>frontend\Windows</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\utils\guid.h">
@ -1610,6 +1619,15 @@
<ClInclude Include="..\..\utils\colorspacehandler\colorspacehandler_SSE2.h">
<Filter>utils\colorspacehandler</Filter>
</ClInclude>
<ClInclude Include="ddraw.h">
<Filter>frontend\Windows</Filter>
</ClInclude>
<ClInclude Include="ogl_display.h">
<Filter>frontend\Windows</Filter>
</ClInclude>
<ClInclude Include="display.h">
<Filter>frontend\Windows</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<None Include="bitmap1.bmp">

View File

@ -0,0 +1,185 @@
/*
Copyright (C) 2018 DeSmuME team
This file 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 of the License, or
(at your option) any later version.
This file 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 the this software. If not, see <http://www.gnu.org/licenses/>.
*/
#include "ddraw.h"
#include "directx/ddraw.h"
#include "GPU.h"
#include "types.h"
const char *DDerrors[] = {
"no errors",
"Unable to initialize DirectDraw",
"Unable to set DirectDraw Cooperative Level",
"Unable to create DirectDraw primary surface",
"Unable to set DirectDraw clipper" };
DDRAW::DDRAW() :
handle(NULL), clip(NULL)
{
surface.primary = NULL;
surface.back = NULL;
memset(&surfDesc, 0, sizeof(surfDesc));
memset(&surfDescBack, 0, sizeof(surfDescBack));
}
u32 DDRAW::create(HWND hwnd)
{
if (handle) return 0;
if (FAILED(DirectDrawCreateEx(NULL, (LPVOID*)&handle, IID_IDirectDraw7, NULL)))
return 1;
if (FAILED(handle->SetCooperativeLevel(hwnd, DDSCL_NORMAL)))
return 2;
createSurfaces(hwnd);
return 0;
}
bool DDRAW::release()
{
if (!handle) return true;
if (clip != NULL) clip->Release();
if (surface.back != NULL) surface.back->Release();
if (surface.primary != NULL) surface.primary->Release();
if (FAILED(handle->Release())) return false;
return true;
}
bool DDRAW::createBackSurface(int width, int height)
{
if (surface.back) { surface.back->Release(); surface.back = NULL; }
memset(&surfDescBack, 0, sizeof(surfDescBack));
surfDescBack.dwSize = sizeof(surfDescBack);
surfDescBack.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH;
surfDescBack.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
if (systemMemory)
surfDescBack.ddsCaps.dwCaps |= DDSCAPS_SYSTEMMEMORY;
else
surfDescBack.ddsCaps.dwCaps |= DDSCAPS_VIDEOMEMORY;
surfDescBack.dwWidth = width;
surfDescBack.dwHeight = height;
if (FAILED(handle->CreateSurface(&surfDescBack, &surface.back, NULL))) return false;
return true;
}
bool DDRAW::createSurfaces(HWND hwnd)
{
if (!handle) return true;
if (clip) { clip->Release(); clip = NULL; }
if (surface.primary) { surface.primary->Release(); surface.primary = NULL; }
// primary
memset(&surfDesc, 0, sizeof(surfDesc));
surfDesc.dwSize = sizeof(surfDesc);
surfDesc.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
surfDesc.dwFlags = DDSD_CAPS;
if (FAILED(handle->CreateSurface(&surfDesc, &surface.primary, NULL)))
return false;
//default doesnt matter much, itll get adjusted later
if (!createBackSurface(GPU_FRAMEBUFFER_NATIVE_WIDTH, GPU_FRAMEBUFFER_NATIVE_HEIGHT * 2))
return false;
if (FAILED(handle->CreateClipper(0, &clip, NULL))) return false;
if (FAILED(clip->SetHWnd(0, hwnd))) return false;
if (FAILED(surface.primary->SetClipper(clip))) return false;
return true;
}
bool DDRAW::lock()
{
if (!handle) return true;
if (!surface.back) return false;
memset(&surfDescBack, 0, sizeof(surfDescBack));
surfDescBack.dwSize = sizeof(surfDescBack);
surfDescBack.dwFlags = DDSD_ALL;
HRESULT res = surface.back->Lock(NULL, &surfDescBack, DDLOCK_WAIT | DDLOCK_WRITEONLY, NULL);
if (FAILED(res))
{
//INFO("DDraw failed: Lock %i\n", res);
if (res == DDERR_SURFACELOST)
{
res = surface.back->Restore();
if (FAILED(res)) return false;
}
}
return true;
}
bool DDRAW::unlock()
{
if (!handle) return true;
if (!surface.back) return false;
if (FAILED(surface.back->Unlock((LPRECT)surfDescBack.lpSurface))) return false;
return true;
}
bool DDRAW::OK()
{
if (!handle) return false;
if (!surface.primary) return false;
if (!surface.back) return false;
return true;
}
bool DDRAW::blt(LPRECT dst, LPRECT src)
{
if (!handle) return true;
if (!surface.primary) return false;
if (!surface.back) return false;
if (vSync)
{
//this seems to block the whole process. this destroys the display thread and will easily block the emulator to 30fps.
//IDirectDraw7_WaitForVerticalBlank(handle,DDWAITVB_BLOCKBEGIN,0);
for (;;)
{
BOOL vblank;
IDirectDraw7_GetVerticalBlankStatus(handle, &vblank);
if (vblank) break;
//must be a greedy loop since vblank is small relative to 1msec minimum Sleep() resolution.
}
}
HRESULT res = surface.primary->Blt(dst, surface.back, src, DDBLT_WAIT, 0);
if (FAILED(res))
{
//INFO("DDraw failed: Blt %i\n", res);
if (res == DDERR_SURFACELOST)
{
res = surface.primary->Restore();
if (FAILED(res)) return false;
}
}
return true;
}

View File

@ -0,0 +1,54 @@
/*
Copyright (C) 2018 DeSmuME team
This file 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 of the License, or
(at your option) any later version.
This file 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 the this software. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _DDRAW_H_
#define _DDRAW_H_
#include "types.h"
#include "directx/ddraw.h"
extern const char *DDerrors[];
struct DDRAW
{
DDRAW();
u32 create(HWND hwnd);
bool release();
bool createSurfaces(HWND hwnd);
bool createBackSurface(int width, int height);
bool lock();
bool unlock();
bool blt(LPRECT dst, LPRECT src);
bool OK();
LPDIRECTDRAW7 handle;
struct
{
LPDIRECTDRAWSURFACE7 primary;
LPDIRECTDRAWSURFACE7 back;
} surface;
DDSURFACEDESC2 surfDesc;
DDSURFACEDESC2 surfDescBack;
LPDIRECTDRAWCLIPPER clip;
bool systemMemory = false;
bool vSync = false;
};
#endif

View File

@ -0,0 +1,961 @@
/*
Copyright (C) 2018 DeSmuME team
This file 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 of the License, or
(at your option) any later version.
This file 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 the this software. If not, see <http://www.gnu.org/licenses/>.
*/
#include "display.h"
#include <MMSystem.h>
#include <WindowsX.h>
#include "main.h"
#include "windriver.h"
#include "winutil.h"
DDRAW ddraw;
GLDISPLAY gldisplay;
u32 displayMethod;
VideoInfo video;
int gpu_bpp = 18;
int frameskiprate = 0;
int lastskiprate = 0;
int emu_paused = 0;
bool frameAdvance = false;
bool SeparationBorderDrag = true;
int ScreenGapColor = 0xFFFFFF;
/*const u32 gapColors[16] = {
Color::Gray,
Color::Brown,
Color::Red,
Color::Pink,
Color::Orange,
Color::Yellow,
Color::LightGreen,
Color::Lime,
Color::Green,
Color::SeaGreen,
Color::SkyBlue,
Color::Blue,
Color::DarkBlue,
Color::DarkViolet,
Color::Purple,
Color::Fuchsia
};*/
RECT FullScreenRect, MainScreenRect, SubScreenRect, GapRect;
RECT MainScreenSrcRect, SubScreenSrcRect;
bool ForceRatio = true;
bool PadToInteger = false;
float screenSizeRatio = 1.0f;
bool vCenterResizedScr = true;
//triple buffering logic
struct DisplayBuffer
{
DisplayBuffer()
: buffer(NULL)
, size(0)
{
}
u32* buffer;
size_t size; //[256*192*4];
} displayBuffers[3];
volatile int currDisplayBuffer = -1;
volatile int newestDisplayBuffer = -2;
slock_t *display_mutex = NULL;
sthread_t *display_thread = NULL;
volatile bool display_die = false;
HANDLE display_wakeup_event = INVALID_HANDLE_VALUE;
HANDLE display_done_event = INVALID_HANDLE_VALUE;
DWORD display_done_timeout = 500;
int displayPostponeType = 0;
DWORD displayPostponeUntil = ~0;
bool displayNoPostponeNext = false;
DWORD display_invoke_argument = 0;
void(*display_invoke_function)(DWORD) = NULL;
HANDLE display_invoke_ready_event = INVALID_HANDLE_VALUE;
HANDLE display_invoke_done_event = INVALID_HANDLE_VALUE;
DWORD display_invoke_timeout = 500;
CRITICAL_SECTION display_invoke_handler_cs;
static void InvokeOnMainThread(void(*function)(DWORD), DWORD argument);
int scanline_filter_a = 0;
int scanline_filter_b = 2;
int scanline_filter_c = 2;
int scanline_filter_d = 4;
#pragma pack(push,1)
struct pix24
{
u8 b, g, r;
FORCEINLINE pix24(u32 s) : b(s & 0xFF), g((s & 0xFF00) >> 8), r((s & 0xFF0000) >> 16) {}
};
struct pix16
{
u16 c;
FORCEINLINE pix16(u32 s) : c(((s & 0xF8) >> 3) | ((s & 0xFC00) >> 5) | ((s & 0xF80000) >> 8)) {}
};
struct pix15
{
u16 c;
FORCEINLINE pix15(u32 s) : c(((s & 0xF8) >> 3) | ((s & 0xF800) >> 6) | ((s & 0xF80000) >> 9)) {}
};
#pragma pack(pop)
void GetNdsScreenRect(RECT* r)
{
RECT zero;
SetRect(&zero, 0, 0, 0, 0);
if (zero == MainScreenRect) *r = SubScreenRect;
else if (zero == SubScreenRect || video.layout == 2) *r = MainScreenRect;
else
{
RECT* dstRects[2] = { &MainScreenRect, &SubScreenRect };
int left = min(dstRects[0]->left, dstRects[1]->left);
int top = min(dstRects[0]->top, dstRects[1]->top);
int right = max(dstRects[0]->right, dstRects[1]->right);
int bottom = max(dstRects[0]->bottom, dstRects[1]->bottom);
SetRect(r, left, top, right, bottom);
}
}
struct DisplayLayoutInfo
{
int vx, vy, vw, vh;
float widthScale, heightScale;
int bufferWidth, bufferHeight;
};
//performs aspect ratio letterboxing correction and integer clamping
DisplayLayoutInfo CalculateDisplayLayout(RECT rcClient, bool maintainAspect, bool maintainInteger, int targetWidth, int targetHeight)
{
DisplayLayoutInfo ret;
//do maths on the viewport and the native resolution and the user settings to get a display rectangle
SIZE sz = { rcClient.right - rcClient.left, rcClient.bottom - rcClient.top };
float widthScale = (float)sz.cx / targetWidth;
float heightScale = (float)sz.cy / targetHeight;
if (maintainAspect)
{
if (widthScale > heightScale) widthScale = heightScale;
if (heightScale > widthScale) heightScale = widthScale;
}
if (maintainInteger)
{
widthScale = floorf(widthScale);
heightScale = floorf(heightScale);
}
ret.vw = (int)(widthScale * targetWidth);
ret.vh = (int)(heightScale * targetHeight);
ret.vx = (sz.cx - ret.vw) / 2;
ret.vy = (sz.cy - ret.vh) / 2;
ret.widthScale = widthScale;
ret.heightScale = heightScale;
ret.bufferWidth = sz.cx;
ret.bufferHeight = sz.cy;
return ret;
}
//reformulates CalculateDisplayLayout() into a format more convenient for this purpose
RECT CalculateDisplayLayoutWrapper(RECT rcClient, int targetWidth, int targetHeight, int tbHeight, bool maximized)
{
bool maintainInteger = !!PadToInteger;
bool maintainAspect = !!ForceRatio;
if (maintainInteger) maintainAspect = true;
//nothing to do here if maintain aspect isnt chosen
if (!maintainAspect) return rcClient;
RECT rc = { rcClient.left, rcClient.top + tbHeight, rcClient.right, rcClient.bottom };
DisplayLayoutInfo dli = CalculateDisplayLayout(rc, maintainAspect, maintainInteger, targetWidth, targetHeight);
rc.left = rcClient.left + dli.vx;
rc.top = rcClient.top + dli.vy;
rc.right = rc.left + dli.vw;
rc.bottom = rc.top + dli.vh + tbHeight;
return rc;
}
template<typename T> static void doRotate(void* dst)
{
u8* buffer = (u8*)dst;
int size = video.size();
u32* src = (u32*)video.finalBuffer();
int width = video.width;
int height = video.height;
int pitch = ddraw.surfDescBack.lPitch;
switch (video.rotation)
{
case 0:
case 180:
{
if (pitch == 1024)
{
if (video.rotation == 0)
if (sizeof(T) == sizeof(u32))
memcpy(buffer, src, size * sizeof(u32));
else
for (int i = 0; i < size; i++)
((T*)buffer)[i] = src[i];
else // if(video.rotation==180)
for (int i = 0, j = size - 1; j >= 0; i++, j--)
((T*)buffer)[i] = src[j];
}
else
{
if (video.rotation == 0)
if (sizeof(T) != sizeof(u32))
for (int y = 0; y < height; y++)
{
for (int x = 0; x < width; x++)
((T*)buffer)[x] = src[(y * width) + x];
buffer += pitch;
}
else
for (int y = 0; y < height; y++)
{
memcpy(buffer, &src[y * width], width * sizeof(u32));
buffer += pitch;
}
else // if(video.rotation==180)
for (int y = 0; y < height; y++)
{
for (int x = 0; x < width; x++)
((T*)buffer)[x] = src[height*width - (y * width) - x - 1];
buffer += pitch;
}
}
}
break;
case 90:
case 270:
{
if (video.rotation == 90)
for (int y = 0; y < width; y++)
{
for (int x = 0; x < height; x++)
((T*)buffer)[x] = src[(((height - 1) - x) * width) + y];
buffer += pitch;
}
else
for (int y = 0; y < width; y++)
{
for (int x = 0; x < height; x++)
((T*)buffer)[x] = src[((x)* width) + (width - 1) - y];
buffer += pitch;
}
}
break;
}
}
static void DD_FillRect(LPDIRECTDRAWSURFACE7 surf, int left, int top, int right, int bottom, DWORD color)
{
RECT r;
SetRect(&r, left, top, right, bottom);
DDBLTFX fx;
memset(&fx, 0, sizeof(DDBLTFX));
fx.dwSize = sizeof(DDBLTFX);
//fx.dwFillColor = color;
fx.dwFillColor = 0; //color is just for debug
surf->Blt(&r, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &fx);
}
static void OGL_DrawTexture(RECT* srcRects, RECT* dstRects)
{
//don't change the original rects
RECT sRects[2];
sRects[0] = RECT(srcRects[0]);
sRects[1] = RECT(srcRects[1]);
//use clear+scissor for gap
if (video.screengap > 0)
{
//adjust client rect into scissor rect (0,0 at bottomleft)
glScissor(dstRects[2].left, dstRects[2].bottom, dstRects[2].right - dstRects[2].left, dstRects[2].top - dstRects[2].bottom);
u32 color_rev = (u32)ScreenGapColor;
int r = (color_rev >> 0) & 0xFF;
int g = (color_rev >> 8) & 0xFF;
int b = (color_rev >> 16) & 0xFF;
glClearColor(r / 255.0f, g / 255.0f, b / 255.0f, 1.0f);
glEnable(GL_SCISSOR_TEST);
glClear(GL_COLOR_BUFFER_BIT);
glDisable(GL_SCISSOR_TEST);
}
//draw two screens
glBegin(GL_QUADS);
for (int i = 0; i<2; i++)
{
//none of this makes any goddamn sense. dont even try.
int idx = i;
int ofs = 0;
switch (video.rotation)
{
case 0:
break;
case 90:
ofs = 3;
idx = 1 - i;
std::swap(sRects[idx].right, sRects[idx].bottom);
std::swap(sRects[idx].left, sRects[idx].top);
break;
case 180:
idx = 1 - i;
ofs = 2;
break;
case 270:
std::swap(sRects[idx].right, sRects[idx].bottom);
std::swap(sRects[idx].left, sRects[idx].top);
ofs = 1;
break;
}
float u1 = sRects[idx].left / (float)video.width;
float u2 = sRects[idx].right / (float)video.width;
float v1 = sRects[idx].top / (float)video.height;
float v2 = sRects[idx].bottom / (float)video.height;
float u[] = { u1,u2,u2,u1 };
float v[] = { v1,v1,v2,v2 };
glTexCoord2f(u[(ofs + 0) % 4], v[(ofs + 0) % 4]);
glVertex2i(dstRects[i].left, dstRects[i].top);
glTexCoord2f(u[(ofs + 1) % 4], v[(ofs + 1) % 4]);
glVertex2i(dstRects[i].right, dstRects[i].top);
glTexCoord2f(u[(ofs + 2) % 4], v[(ofs + 2) % 4]);
glVertex2i(dstRects[i].right, dstRects[i].bottom);
glTexCoord2f(u[(ofs + 3) % 4], v[(ofs + 3) % 4]);
glVertex2i(dstRects[i].left, dstRects[i].bottom);
}
glEnd();
}
static void OGL_DoDisplay()
{
if (!gldisplay.begin(MainWindow->getHWnd())) return;
//the ds screen fills the texture entirely, so we dont have garbage at edge to worry about,
//but we need to make sure this is clamped for when filtering is selected
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
if (gldisplay.filter)
{
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
}
else
{
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
}
RECT rc;
HWND hwnd = MainWindow->getHWnd();
GetClientRect(hwnd, &rc);
int width = rc.right - rc.left;
int height = rc.bottom - rc.top;
glViewport(0, 0, width, height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0.0f, (float)width, (float)height, 0.0f, -100.0f, 100.0f);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
//clear entire area, for cases where the screen is maximized
glClearColor(0, 0, 0, 0);
glClear(GL_COLOR_BUFFER_BIT);
// get dest and src rects
RECT dr[] = { MainScreenRect, SubScreenRect, GapRect };
for (int i = 0; i<2; i++) //dont change gap rect, for some reason
{
ScreenToClient(hwnd, (LPPOINT)&dr[i].left);
ScreenToClient(hwnd, (LPPOINT)&dr[i].right);
}
dr[2].bottom = height - dr[2].bottom;
dr[2].top = height - dr[2].top;
RECT srcRects[2];
const bool isMainGPUFirst = (GPU->GetDisplayInfo().engineID[NDSDisplayID_Main] == GPUEngineID_Main);
if (video.swap == 0)
{
srcRects[0] = MainScreenSrcRect;
srcRects[1] = SubScreenSrcRect;
if (osd) osd->swapScreens = false;
}
else if (video.swap == 1)
{
srcRects[0] = SubScreenSrcRect;
srcRects[1] = MainScreenSrcRect;
if (osd) osd->swapScreens = true;
}
else if (video.swap == 2)
{
srcRects[0] = (!isMainGPUFirst) ? SubScreenSrcRect : MainScreenSrcRect;
srcRects[1] = (!isMainGPUFirst) ? MainScreenSrcRect : SubScreenSrcRect;
if (osd) osd->swapScreens = !isMainGPUFirst;
}
else if (video.swap == 3)
{
srcRects[0] = (!isMainGPUFirst) ? MainScreenSrcRect : SubScreenSrcRect;
srcRects[1] = (!isMainGPUFirst) ? SubScreenSrcRect : MainScreenSrcRect;
if (osd) osd->swapScreens = isMainGPUFirst;
}
//printf("%d,%d %dx%d -- %d,%d %dx%d\n",
// srcRects[0].left,srcRects[0].top, srcRects[0].right-srcRects[0].left, srcRects[0].bottom-srcRects[0].top,
// srcRects[1].left,srcRects[1].top, srcRects[1].right-srcRects[1].left, srcRects[1].bottom-srcRects[1].top
// );
glEnable(GL_TEXTURE_2D);
// draw DS display
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, video.width, video.height, 0, GL_BGRA, GL_UNSIGNED_BYTE, video.finalBuffer());
OGL_DrawTexture(srcRects, dr);
// draw HUD
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_BLEND);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, GPU_FRAMEBUFFER_NATIVE_WIDTH, GPU_FRAMEBUFFER_NATIVE_HEIGHT * 2, 0, GL_BGRA, GL_UNSIGNED_BYTE, aggDraw.hud->buf().buf());
OGL_DrawTexture(srcRects, dr);
glDisable(GL_BLEND);
gldisplay.showPage();
gldisplay.end();
}
static void DD_DoDisplay()
{
if (ddraw.surfDescBack.dwWidth != video.rotatedwidth() || ddraw.surfDescBack.dwHeight != video.rotatedheight())
ddraw.createBackSurface(video.rotatedwidth(), video.rotatedheight());
if (!ddraw.lock()) return;
char* buffer = (char*)ddraw.surfDescBack.lpSurface;
switch (ddraw.surfDescBack.ddpfPixelFormat.dwRGBBitCount)
{
case 32:
doRotate<u32>(ddraw.surfDescBack.lpSurface);
break;
case 24:
doRotate<pix24>(ddraw.surfDescBack.lpSurface);
break;
case 16:
if (ddraw.surfDescBack.ddpfPixelFormat.dwGBitMask != 0x3E0)
doRotate<pix16>(ddraw.surfDescBack.lpSurface);
else
doRotate<pix15>(ddraw.surfDescBack.lpSurface);
break;
case 0:
break;
default:
INFO("Unsupported color depth: %i bpp\n", ddraw.surfDescBack.ddpfPixelFormat.dwRGBBitCount);
//emu_halt();
break;
}
if (!ddraw.unlock()) return;
RECT* dstRects[2] = { &MainScreenRect, &SubScreenRect };
RECT* srcRects[2];
const bool isMainGPUFirst = (GPU->GetDisplayInfo().engineID[NDSDisplayID_Main] == GPUEngineID_Main);
if (video.swap == 0)
{
srcRects[0] = &MainScreenSrcRect;
srcRects[1] = &SubScreenSrcRect;
if (osd) osd->swapScreens = false;
}
else if (video.swap == 1)
{
srcRects[0] = &SubScreenSrcRect;
srcRects[1] = &MainScreenSrcRect;
if (osd) osd->swapScreens = true;
}
else if (video.swap == 2)
{
srcRects[0] = (!isMainGPUFirst) ? &SubScreenSrcRect : &MainScreenSrcRect;
srcRects[1] = (!isMainGPUFirst) ? &MainScreenSrcRect : &SubScreenSrcRect;
if (osd) osd->swapScreens = !isMainGPUFirst;
}
else if (video.swap == 3)
{
srcRects[0] = (!isMainGPUFirst) ? &MainScreenSrcRect : &SubScreenSrcRect;
srcRects[1] = (!isMainGPUFirst) ? &SubScreenSrcRect : &MainScreenSrcRect;
if (osd) osd->swapScreens = isMainGPUFirst;
}
//this code fills in all the undrawn areas
//it is probably a waste of time to keep black-filling all this, but we need to do it to be safe.
{
RECT wr;
GetWindowRect(MainWindow->getHWnd(), &wr);
RECT r;
GetNdsScreenRect(&r);
int left = r.left;
int top = r.top;
int right = r.right;
int bottom = r.bottom;
//printf("%d %d %d %d / %d %d %d %d\n",fullScreen.left,fullScreen.top,fullScreen.right,fullScreen.bottom,left,top,right,bottom);
//printf("%d %d %d %d / %d %d %d %d\n",MainScreenRect.left,MainScreenRect.top,MainScreenRect.right,MainScreenRect.bottom,SubScreenRect.left,SubScreenRect.top,SubScreenRect.right,SubScreenRect.bottom);
if (ddraw.OK())
{
DD_FillRect(ddraw.surface.primary, 0, 0, left, top, RGB(255, 0, 0)); //topleft
DD_FillRect(ddraw.surface.primary, left, 0, right, top, RGB(128, 0, 0)); //topcenter
DD_FillRect(ddraw.surface.primary, right, 0, wr.right, top, RGB(0, 255, 0)); //topright
DD_FillRect(ddraw.surface.primary, 0, top, left, bottom, RGB(0, 128, 0)); //left
DD_FillRect(ddraw.surface.primary, right, top, wr.right, bottom, RGB(0, 0, 255)); //right
DD_FillRect(ddraw.surface.primary, 0, bottom, left, wr.bottom, RGB(0, 0, 128)); //bottomleft
DD_FillRect(ddraw.surface.primary, left, bottom, right, wr.bottom, RGB(255, 0, 255)); //bottomcenter
DD_FillRect(ddraw.surface.primary, right, bottom, wr.right, wr.bottom, RGB(0, 255, 255)); //bottomright
if (video.layout == 1)
{
DD_FillRect(ddraw.surface.primary, SubScreenRect.left, wr.top, wr.right, SubScreenRect.top, RGB(0, 0, 0)); //Top gap left when centering the resized screen
DD_FillRect(ddraw.surface.primary, SubScreenRect.left, SubScreenRect.bottom, wr.right, wr.bottom, RGB(0, 0, 0)); //Bottom gap left when centering the resized screen
}
}
}
for (int i = 0; i < 2; i++)
{
if (i && video.layout == 2)
break;
if (!ddraw.blt(dstRects[i], srcRects[i])) return;
}
if (video.layout == 1) return;
if (video.layout == 2) return;
// Gap
if (video.screengap > 0)
{
//u32 color = gapColors[win_fw_config.fav_colour];
//u32 color_rev = (((color & 0xFF) << 16) | (color & 0xFF00) | ((color & 0xFF0000) >> 16));
u32 color_rev = (u32)ScreenGapColor;
HDC dc;
HBRUSH brush;
dc = GetDC(MainWindow->getHWnd());
brush = CreateSolidBrush(color_rev);
FillRect(dc, &GapRect, brush);
DeleteObject((HGDIOBJ)brush);
ReleaseDC(MainWindow->getHWnd(), dc);
}
}
void displayProc()
{
slock_lock(display_mutex);
//find a buffer to display
int todo = newestDisplayBuffer;
bool alreadyDisplayed = (todo == currDisplayBuffer);
slock_unlock(display_mutex);
//something new to display:
if (!alreadyDisplayed) {
//start displaying a new buffer
currDisplayBuffer = todo;
video.srcBuffer = (u8*)displayBuffers[currDisplayBuffer].buffer;
video.srcBufferSize = displayBuffers[currDisplayBuffer].size;
}
DoDisplay();
}
void displayThread(void *arg)
{
do
{
if ((MainWindow == NULL) || IsMinimized(MainWindow->getHWnd()))
{
WaitForSingleObject(display_wakeup_event, INFINITE);
}
else if ((emu_paused || !execute || !romloaded) && (!HudEditorMode && !CommonSettings.hud.ShowInputDisplay && !CommonSettings.hud.ShowGraphicalInputDisplay))
{
WaitForSingleObject(display_wakeup_event, 250);
}
else
{
WaitForSingleObject(display_wakeup_event, 10);
}
if (display_die)
{
break;
}
displayProc();
SetEvent(display_done_event);
} while (!display_die);
}
static void DoDisplay_DrawHud()
{
osd->update();
DrawHUD();
osd->clear();
}
void Display()
{
const NDSDisplayInfo &dispInfo = GPU->GetDisplayInfo();
if (CommonSettings.single_core())
{
video.srcBuffer = (u8*)dispInfo.masterCustomBuffer;
video.srcBufferSize = dispInfo.customWidth * dispInfo.customHeight * dispInfo.pixelBytes * 2;
DoDisplay();
}
else
{
if (display_thread == NULL)
{
display_mutex = slock_new();
display_thread = sthread_create(&displayThread, nullptr);
}
slock_lock(display_mutex);
if (int diff = (currDisplayBuffer + 1) % 3 - newestDisplayBuffer)
newestDisplayBuffer += diff;
else newestDisplayBuffer = (currDisplayBuffer + 2) % 3;
DisplayBuffer& db = displayBuffers[newestDisplayBuffer];
size_t targetSize = dispInfo.customWidth * dispInfo.customHeight * dispInfo.pixelBytes * 2;
if (db.size != targetSize)
{
free_aligned(db.buffer);
db.buffer = (u32*)malloc_alignedPage(targetSize);
db.size = targetSize;
}
memcpy(db.buffer, dispInfo.masterCustomBuffer, targetSize);
slock_unlock(display_mutex);
SetEvent(display_wakeup_event);
}
}
//does a single display work unit. only to be used from the display thread
void DoDisplay()
{
Lock lock(win_backbuffer_sync);
if (displayPostponeType && !displayNoPostponeNext && (displayPostponeType < 0 || timeGetTime() < displayPostponeUntil))
return;
displayNoPostponeNext = false;
//we have to do a copy here because we're about to draw the OSD onto it. bummer.
if (gpu_bpp == 15)
ColorspaceConvertBuffer555To8888Opaque<true, false>((u16 *)video.srcBuffer, video.buffer, video.srcBufferSize / 2);
else
ColorspaceConvertBuffer888XTo8888Opaque<true, false>((u32*)video.srcBuffer, video.buffer, video.srcBufferSize / 4);
//some games use the backlight for fading effects
const size_t pixCount = video.prefilterWidth * video.prefilterHeight / 2;
const NDSDisplayInfo &displayInfo = GPU->GetDisplayInfo();
ColorspaceApplyIntensityToBuffer32<false, false>(video.buffer, pixCount, displayInfo.backlightIntensity[NDSDisplayID_Main]);
ColorspaceApplyIntensityToBuffer32<false, false>(video.buffer + pixCount, pixCount, displayInfo.backlightIntensity[NDSDisplayID_Touch]);
// Lua draws to the HUD buffer, so clear it here instead of right before redrawing the HUD.
aggDraw.hud->clear();
if (AnyLuaActive())
{
if (sthread_isself(display_thread))
{
InvokeOnMainThread((void(*)(DWORD))
CallRegisteredLuaFunctions, LUACALL_AFTEREMULATIONGUI);
}
else
{
CallRegisteredLuaFunctions(LUACALL_AFTEREMULATIONGUI);
}
}
// draw hud
DoDisplay_DrawHud();
if (displayMethod == DISPMETHOD_DDRAW_HW || displayMethod == DISPMETHOD_DDRAW_SW)
{
// DirectDraw doesn't support alpha blending, so we must scale and overlay the HUD ourselves.
T_AGG_RGBA target((u8*)video.buffer, video.prefilterWidth, video.prefilterHeight, video.prefilterWidth * 4);
target.transformImage(aggDraw.hud->image<T_AGG_PF_RGBA>(), 0, 0, video.prefilterWidth, video.prefilterHeight);
}
//apply user's filter
video.filter();
if (displayMethod == DISPMETHOD_DDRAW_HW || displayMethod == DISPMETHOD_DDRAW_SW)
{
gldisplay.kill();
DD_DoDisplay();
}
else
{
OGL_DoDisplay();
}
}
void KillDisplay()
{
display_die = true;
SetEvent(display_wakeup_event);
if (display_thread)
sthread_join(display_thread);
}
void UpdateWndRects(HWND hwnd, RECT* newClientRect)
{
POINT ptClient;
RECT rc;
GapRect = {0,0,0,0};
bool maximized = IsZoomed(hwnd) != FALSE;
int wndWidth, wndHeight;
int defHeight = video.height;
if (video.layout == 0)
defHeight += video.scaledscreengap();
float ratio;
int oneScreenHeight, gapHeight;
int tbheight;
//if we're in the middle of resizing the window, GetClientRect will return the old rect
if (newClientRect)
rc = RECT(*newClientRect);
else
GetClientRect(hwnd, &rc);
if (maximized)
rc = FullScreenRect;
tbheight = MainWindowToolbar->GetHeight();
if (video.layout == 1) //horizontal
{
rc = CalculateDisplayLayoutWrapper(rc, (int)((float)GPU_FRAMEBUFFER_NATIVE_WIDTH * 2 / screenSizeRatio), GPU_FRAMEBUFFER_NATIVE_HEIGHT, tbheight, maximized);
wndWidth = (rc.bottom - rc.top) - tbheight;
wndHeight = (rc.right - rc.left);
ratio = ((float)wndHeight / (float)512);
oneScreenHeight = (int)((float)GPU_FRAMEBUFFER_NATIVE_WIDTH * ratio);
int oneScreenWidth = (int)((float)GPU_FRAMEBUFFER_NATIVE_HEIGHT * ratio);
int vResizedScrOffset = 0;
// Main screen
ptClient.x = rc.left;
ptClient.y = rc.top;
ClientToScreen(hwnd, &ptClient);
MainScreenRect.left = ptClient.x;
MainScreenRect.top = ptClient.y;
ptClient.x = (rc.left + oneScreenHeight * screenSizeRatio);
ptClient.y = (rc.top + wndWidth);
ClientToScreen(hwnd, &ptClient);
MainScreenRect.right = ptClient.x;
MainScreenRect.bottom = ptClient.y;
// Sub screen
ptClient.x = (rc.left + oneScreenHeight * screenSizeRatio);
if (vCenterResizedScr && ForceRatio)
vResizedScrOffset = (wndWidth - oneScreenWidth * (2 - screenSizeRatio)) / 2;
ptClient.y = rc.top + vResizedScrOffset;
ClientToScreen(hwnd, &ptClient);
SubScreenRect.left = ptClient.x;
SubScreenRect.top = ptClient.y;
ptClient.x = (rc.left + oneScreenHeight * 2);
if (ForceRatio)
ptClient.y = (rc.top + vResizedScrOffset + oneScreenWidth * (2 - screenSizeRatio));
else
ptClient.y = (rc.top + wndWidth);
ClientToScreen(hwnd, &ptClient);
SubScreenRect.right = ptClient.x;
SubScreenRect.bottom = ptClient.y;
}
else
if (video.layout == 2) //one screen
{
rc = CalculateDisplayLayoutWrapper(rc, GPU_FRAMEBUFFER_NATIVE_WIDTH, GPU_FRAMEBUFFER_NATIVE_HEIGHT, tbheight, maximized);
wndWidth = (rc.bottom - rc.top) - tbheight;
wndHeight = (rc.right - rc.left);
ratio = ((float)wndHeight / (float)defHeight);
oneScreenHeight = (int)((video.height) * ratio);
// Main screen
ptClient.x = rc.left;
ptClient.y = rc.top;
ClientToScreen(hwnd, &ptClient);
MainScreenRect.left = ptClient.x;
MainScreenRect.top = ptClient.y;
ptClient.x = (rc.left + oneScreenHeight);
ptClient.y = (rc.top + wndWidth);
ClientToScreen(hwnd, &ptClient);
MainScreenRect.right = ptClient.x;
MainScreenRect.bottom = ptClient.y;
SetRectEmpty(&SubScreenRect);
}
else
if (video.layout == 0) //vertical
{
//apply logic to correct things if forced integer is selected
if ((video.rotation == 90) || (video.rotation == 270))
{
rc = CalculateDisplayLayoutWrapper(rc, (GPU_FRAMEBUFFER_NATIVE_HEIGHT * 2) + video.screengap, GPU_FRAMEBUFFER_NATIVE_WIDTH, tbheight, maximized);
}
else
{
rc = CalculateDisplayLayoutWrapper(rc, GPU_FRAMEBUFFER_NATIVE_WIDTH, (GPU_FRAMEBUFFER_NATIVE_HEIGHT * 2) + video.screengap, tbheight, maximized);
}
if ((video.rotation == 90) || (video.rotation == 270))
{
wndWidth = (rc.bottom - rc.top) - tbheight;
wndHeight = (rc.right - rc.left);
}
else
{
wndWidth = (rc.right - rc.left);
wndHeight = (rc.bottom - rc.top) - tbheight;
}
ratio = ((float)wndHeight / (float)defHeight);
oneScreenHeight = (int)((video.height / 2) * ratio);
gapHeight = (wndHeight - (oneScreenHeight * 2));
if ((video.rotation == 90) || (video.rotation == 270))
{
// Main screen
ptClient.x = rc.left;
ptClient.y = rc.top;
ClientToScreen(hwnd, &ptClient);
MainScreenRect.left = ptClient.x;
MainScreenRect.top = ptClient.y;
ptClient.x = (rc.left + oneScreenHeight);
ptClient.y = (rc.top + wndWidth);
ClientToScreen(hwnd, &ptClient);
MainScreenRect.right = ptClient.x;
MainScreenRect.bottom = ptClient.y;
//if there was no specified screen gap, extend the top screen to cover the extra column
if (video.screengap == 0) MainScreenRect.right += gapHeight;
// Sub screen
ptClient.x = (rc.left + oneScreenHeight + gapHeight);
ptClient.y = rc.top;
ClientToScreen(hwnd, &ptClient);
SubScreenRect.left = ptClient.x;
SubScreenRect.top = ptClient.y;
ptClient.x = (rc.left + oneScreenHeight + gapHeight + oneScreenHeight);
ptClient.y = (rc.top + wndWidth);
ClientToScreen(hwnd, &ptClient);
SubScreenRect.right = ptClient.x;
SubScreenRect.bottom = ptClient.y;
// Gap
GapRect.left = (rc.left + oneScreenHeight);
GapRect.top = rc.top;
GapRect.right = (rc.left + oneScreenHeight + gapHeight);
GapRect.bottom = (rc.top + wndWidth);
}
else
{
// Main screen
ptClient.x = rc.left;
ptClient.y = rc.top;
ClientToScreen(hwnd, &ptClient);
MainScreenRect.left = ptClient.x;
MainScreenRect.top = ptClient.y;
ptClient.x = (rc.left + wndWidth);
ptClient.y = (rc.top + oneScreenHeight);
ClientToScreen(hwnd, &ptClient);
MainScreenRect.right = ptClient.x;
MainScreenRect.bottom = ptClient.y;
//if there was no specified screen gap, extend the top screen to cover the extra row
if (video.screengap == 0) MainScreenRect.bottom += gapHeight;
// Sub screen
ptClient.x = rc.left;
ptClient.y = (rc.top + oneScreenHeight + gapHeight);
ClientToScreen(hwnd, &ptClient);
SubScreenRect.left = ptClient.x;
SubScreenRect.top = ptClient.y;
ptClient.x = (rc.left + wndWidth);
ptClient.y = (rc.top + oneScreenHeight + gapHeight + oneScreenHeight);
ClientToScreen(hwnd, &ptClient);
SubScreenRect.right = ptClient.x;
SubScreenRect.bottom = ptClient.y;
// Gap
GapRect.left = rc.left;
GapRect.top = (rc.top + oneScreenHeight);
GapRect.right = (rc.left + wndWidth);
GapRect.bottom = (rc.top + oneScreenHeight + gapHeight);
}
}
MainScreenRect.top += tbheight;
MainScreenRect.bottom += tbheight;
SubScreenRect.top += tbheight;
SubScreenRect.bottom += tbheight;
GapRect.top += tbheight;
GapRect.bottom += tbheight;
}
static void InvokeOnMainThread(void(*function)(DWORD), DWORD argument)
{
ResetEvent(display_invoke_ready_event);
display_invoke_argument = argument;
display_invoke_function = function;
PostMessage(MainWindow->getHWnd(), WM_CUSTINVOKE, 0, 0); // in case a modal dialog or menu is open
SignalObjectAndWait(display_invoke_ready_event, display_invoke_done_event, display_invoke_timeout, FALSE);
display_invoke_function = NULL;
}
void _ServiceDisplayThreadInvocation()
{
Lock lock(display_invoke_handler_cs);
DWORD res = WaitForSingleObject(display_invoke_ready_event, display_invoke_timeout);
if (res != WAIT_ABANDONED && display_invoke_function)
display_invoke_function(display_invoke_argument);
display_invoke_function = NULL;
SetEvent(display_invoke_done_event);
}

View File

@ -0,0 +1,108 @@
/*
Copyright (C) 2018 DeSmuME team
This file 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 of the License, or
(at your option) any later version.
This file 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 the this software. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _DISPLAY_H_
#define _DISPLAY_H_
#include "main.h"
#include "NDSSystem.h"
#include "debug.h"
#include "GPU.h"
#include "resource.h"
#include "lua-engine.h"
#include "video.h"
#include "frontend/modules/osd/agg/agg_osd.h"
#include "rthreads/rthreads.h"
#include "ddraw.h"
#include "ogl_display.h"
extern DDRAW ddraw;
extern GLDISPLAY gldisplay;
extern u32 displayMethod;
const u32 DISPMETHOD_DDRAW_HW = 1;
const u32 DISPMETHOD_DDRAW_SW = 2;
const u32 DISPMETHOD_OPENGL = 3;
extern int gpu_bpp;
extern int emu_paused;
extern bool frameAdvance;
extern int frameskiprate;
extern int lastskiprate;
extern VideoInfo video;
extern RECT FullScreenRect, MainScreenRect, SubScreenRect, GapRect;
extern RECT MainScreenSrcRect, SubScreenSrcRect;
const int kGapNone = 0;
const int kGapBorder = 5;
const int kGapNDS = 64; // extremely tilted (but some games seem to use this value)
const int kGapNDS2 = 90; // more normal viewing angle
const int kScale1point5x = 65535;
const int kScale2point5x = 65534;
extern bool ForceRatio;
extern bool PadToInteger;
extern float screenSizeRatio;
extern bool vCenterResizedScr;
extern bool SeparationBorderDrag;
extern int ScreenGapColor;
extern slock_t *display_mutex;
extern HANDLE display_wakeup_event;
extern HANDLE display_done_event;
extern DWORD display_done_timeout;
extern int displayPostponeType;
extern DWORD displayPostponeUntil;
extern bool displayNoPostponeNext;
extern void(*display_invoke_function)(DWORD);
extern HANDLE display_invoke_ready_event;
extern HANDLE display_invoke_done_event;
extern DWORD display_invoke_timeout;
extern CRITICAL_SECTION display_invoke_handler_cs;
// Scanline filter parameters. The first set is from commandline.cpp, the second
// set is externed to scanline.cpp.
// TODO: When videofilter.cpp becomes Windows-friendly, remove the second set of
// variables, as they will no longer be necessary at that point.
extern int _scanline_filter_a;
extern int _scanline_filter_b;
extern int _scanline_filter_c;
extern int _scanline_filter_d;
extern int scanline_filter_a;
extern int scanline_filter_b;
extern int scanline_filter_c;
extern int scanline_filter_d;
void Display();
void DoDisplay();
void KillDisplay();
void GetNdsScreenRect(RECT* r);
void _ServiceDisplayThreadInvocation();
FORCEINLINE void ServiceDisplayThreadInvocations()
{
if (display_invoke_function)
_ServiceDisplayThreadInvocation();
}
void UpdateWndRects(HWND hwnd, RECT* newClientRect = NULL);
#endif

File diff suppressed because it is too large Load Diff

View File

@ -28,6 +28,7 @@ extern WINCLASS *MainWindow;
extern HINSTANCE hAppInst;
extern HMENU mainMenu; //Holds handle to the main DeSmuME menu
extern CToolBar* MainWindowToolbar;
extern CRITICAL_SECTION win_backbuffer_sync;
extern volatile bool execute, paused;
extern bool romloaded;
@ -98,4 +99,6 @@ void WIN_InstallGBACartridge();
#define IDT_VIEW_LIGHTS 50011
#define IDM_EXEC 50112
#define WM_CUSTINVOKE WM_USER+52
#endif

View File

@ -0,0 +1,142 @@
/*
Copyright (C) 2018 DeSmuME team
This file 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 of the License, or
(at your option) any later version.
This file 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 the this software. If not, see <http://www.gnu.org/licenses/>.
*/
#include "ogl_display.h"
bool GLDISPLAY::initialize(HWND hwnd)
{
//do we need to use another HDC?
if (hwnd == this->hwnd) return true;
else if (this->hwnd) return false;
if (initContext(hwnd, &privateContext))
{
this->hwnd = hwnd;
return true;
}
else
return false;
}
//http://stackoverflow.com/questions/589064/how-to-enable-vertical-sync-in-opengl
bool GLDISPLAY::WGLExtensionSupported(const char *extension_name)
{
// this is pointer to function which returns pointer to string with list of all wgl extensions
PFNWGLGETEXTENSIONSSTRINGEXTPROC _wglGetExtensionsStringEXT = NULL;
// determine pointer to wglGetExtensionsStringEXT function
_wglGetExtensionsStringEXT = (PFNWGLGETEXTENSIONSSTRINGEXTPROC)wglGetProcAddress("wglGetExtensionsStringEXT");
if (strstr(_wglGetExtensionsStringEXT(), extension_name) == NULL)
{
// string was not found
return false;
}
// extension is supported
return true;
}
void GLDISPLAY::_setvsync()
{
//even if it doesn't work, we'll track it
haveVsync = wantVsync;
if (!WGLExtensionSupported("WGL_EXT_swap_control")) return;
//http://stackoverflow.com/questions/589064/how-to-enable-vertical-sync-in-opengl
PFNWGLSWAPINTERVALEXTPROC wglSwapIntervalEXT = NULL;
PFNWGLGETSWAPINTERVALEXTPROC wglGetSwapIntervalEXT = NULL;
{
// Extension is supported, init pointers.
wglSwapIntervalEXT = (PFNWGLSWAPINTERVALEXTPROC)wglGetProcAddress("wglSwapIntervalEXT");
// this is another function from WGL_EXT_swap_control extension
wglGetSwapIntervalEXT = (PFNWGLGETSWAPINTERVALEXTPROC)wglGetProcAddress("wglGetSwapIntervalEXT");
}
wglSwapIntervalEXT(wantVsync ? 1 : 0);
}
GLDISPLAY::GLDISPLAY()
: active(false)
, wantVsync(false)
, haveVsync(false)
{
}
void GLDISPLAY::kill()
{
if (!hwnd) return;
wglDeleteContext(privateContext);
privateContext = NULL;
hwnd = NULL;
haveVsync = false;
}
bool GLDISPLAY::begin(HWND hwnd)
{
DWORD myThread = GetCurrentThreadId();
//always use another context for display logic
//1. if this is a single threaded process (3d rendering and display in the main thread) then alternating contexts is benign
//2. if this is a multi threaded process (3d rendernig and display in other threads) then the display needs some context
if (!this->hwnd)
{
if (!initialize(hwnd)) return false;
}
privateDC = GetDC(hwnd);
wglMakeCurrent(privateDC, privateContext);
//go ahead and sync the vsync setting while we have the context
if (wantVsync != haveVsync)
_setvsync();
if (filter)
{
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
}
else
{
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
}
return active = true;
}
void GLDISPLAY::end()
{
wglMakeCurrent(NULL, privateContext);
ReleaseDC(hwnd, privateDC);
privateDC = NULL;
active = false;
}
void GLDISPLAY::setvsync(bool vsync)
{
wantVsync = vsync;
}
void GLDISPLAY::showPage()
{
SwapBuffers(privateDC);
}

View File

@ -0,0 +1,52 @@
/*
Copyright (C) 2018 DeSmuME team
This file 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 of the License, or
(at your option) any later version.
This file 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 the this software. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _OGL_DISPLAY_H_
#define _OGL_DISPLAY_H_
#include "types.h"
#include "ogl.h"
#include <GL/gl.h>
#include <GL/glext.h>
#include <GL/wglext.h>
struct GLDISPLAY
{
private:
HGLRC privateContext;
HDC privateDC;
HWND hwnd;
bool initialize(HWND hwnd);
bool WGLExtensionSupported(const char *extension_name);
void _setvsync();
public:
bool active;
bool wantVsync, haveVsync;
bool filter;
GLDISPLAY();
void kill();
bool begin(HWND hwnd);
void end();
void setvsync(bool vsync);
void showPage();
};
#endif

View File

@ -15,6 +15,9 @@ You should have received a copy of the GNU General Public License
along with the this software. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _VIDEO_H_
#define _VIDEO_H_
#include "filter/filter.h"
#include "common.h"
@ -349,3 +352,5 @@ public:
return screengap * height / 384;
}
};
#endif