Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
Please login to access the resource
home:ahmedmoselhi2:branches:Emulators
melonds
melonds_hires-software-renderer.patch
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File melonds_hires-software-renderer.patch of Package melonds
From fdfbfce11bb0be6d45bf23538c6d33a7ec0c622c Mon Sep 17 00:00:00 2001 From: v-fox <virtuousfox@gmail.com> Date: Mon, 18 Sep 2023 00:28:52 +0500 Subject: [PATCH] rebase of "Hi-res software rendering" PR from https://github.com/melonDS-emu/melonDS/pull/1009 --- src/GPU.cpp | 26 +- src/GPU.h | 3 +- src/GPU2D.cpp | 38 +-- src/GPU2D.h | 7 +- src/GPU2D_Soft.cpp | 269 +++++++++++++------- src/GPU2D_Soft.h | 20 +- src/GPU3D.cpp | 197 +++++++------- src/GPU3D.h | 5 + src/GPU3D_OpenGL.cpp | 43 ++-- src/GPU3D_OpenGL.h | 2 +- src/GPU3D_Soft.cpp | 126 ++++++--- src/GPU3D_Soft.h | 23 +- src/GPU_OpenGL.cpp | 2 +- src/Savestate.h | 2 +- src/frontend/FrontendUtil.h | 1 + src/frontend/Util_Video.cpp | 25 +- src/frontend/qt_sdl/VideoSettingsDialog.cpp | 23 +- src/frontend/qt_sdl/VideoSettingsDialog.h | 2 +- src/frontend/qt_sdl/VideoSettingsDialog.ui | 44 +++- src/frontend/qt_sdl/main.cpp | 176 +++++++------ src/frontend/qt_sdl/main.h | 9 +- 21 files changed, 630 insertions(+), 413 deletions(-) diff --git a/src/GPU.cpp b/src/GPU.cpp index f51748b..16eabd1 100644 --- a/src/GPU.cpp +++ b/src/GPU.cpp @@ -87,6 +87,7 @@ u8* VRAMPtr_BOBJ[0x8]; int FrontBuffer; u32* Framebuffer[2][2]; int Renderer = 0; +int ScaleFactor; GPU2D::Unit GPU2D_A(0); GPU2D::Unit GPU2D_B(1); @@ -253,9 +254,9 @@ void Reset() size_t fbsize; if (GPU3D::CurrentRenderer->Accelerated) - fbsize = (256*3 + 1) * 192; + fbsize = (NATIVE_WIDTH*3 + 1) * NATIVE_HEIGHT; else - fbsize = 256 * 192; + fbsize = NATIVE_WIDTH * ScaleFactor * NATIVE_HEIGHT * ScaleFactor; for (size_t i = 0; i < fbsize; i++) { @@ -287,9 +288,9 @@ void Stop() { int fbsize; if (GPU3D::CurrentRenderer->Accelerated) - fbsize = (256*3 + 1) * 192; + fbsize = (NATIVE_WIDTH*3 + 1) * NATIVE_HEIGHT; else - fbsize = 256 * 192; + fbsize = NATIVE_WIDTH * ScaleFactor * NATIVE_HEIGHT * ScaleFactor; memset(Framebuffer[0][0], 0, fbsize*4); memset(Framebuffer[0][1], 0, fbsize*4); @@ -451,11 +452,12 @@ void SetRenderSettings(int renderer, RenderSettings& settings) InitRenderer(renderer); } + ScaleFactor = settings.ScaleFactor; int fbsize; if (GPU3D::CurrentRenderer->Accelerated) - fbsize = (256*3 + 1) * 192; + fbsize = (NATIVE_WIDTH*3 + 1) * NATIVE_HEIGHT; else - fbsize = 256 * 192; + fbsize = NATIVE_WIDTH * ScaleFactor * NATIVE_HEIGHT * ScaleFactor; if (Framebuffer[0][0]) { delete[] Framebuffer[0][0]; Framebuffer[0][0] = nullptr; } if (Framebuffer[1][0]) { delete[] Framebuffer[1][0]; Framebuffer[1][0] = nullptr; } @@ -474,6 +476,8 @@ void SetRenderSettings(int renderer, RenderSettings& settings) AssignFramebuffers(); + GPU2D_Renderer->SetRenderSettings(ScaleFactor); + if (Renderer == 0) { GPU3D::CurrentRenderer->SetRenderSettings(settings); @@ -1012,7 +1016,7 @@ void DisplayFIFO(u32 x) GPU2D_A.SampleFIFO(x-11, 8); } - if (x < 256) + if (x < NATIVE_WIDTH) { // transfer the next 8 pixels NDS::CheckDMAs(0, 0x04); @@ -1038,18 +1042,18 @@ void StartHBlank(u32 line) DispStat[0] |= (1<<1); DispStat[1] |= (1<<1); - if (VCount < 192) + if (VCount < NATIVE_HEIGHT) { // draw // note: this should start 48 cycles after the scanline start - if (line < 192) + if (line < NATIVE_HEIGHT) { GPU2D_Renderer->DrawScanline(line, &GPU2D_A); GPU2D_Renderer->DrawScanline(line, &GPU2D_B); } // sprites are pre-rendered one scanline in advance - if (line < 191) + if (line < NATIVE_HEIGHT - 1) { GPU2D_Renderer->DrawSprites(line+1, &GPU2D_A); GPU2D_Renderer->DrawSprites(line+1, &GPU2D_B); @@ -1130,7 +1134,7 @@ void StartScanline(u32 line) else if (VCount == 194) NDS::StopDMAs(0, 0x03); - if (line < 192) + if (line < NATIVE_HEIGHT) { if (line == 0) { diff --git a/src/GPU.h b/src/GPU.h index 9686704..e09a436 100644 --- a/src/GPU.h +++ b/src/GPU.h @@ -79,6 +79,7 @@ extern GPU2D::Unit GPU2D_A; extern GPU2D::Unit GPU2D_B; extern int Renderer; +extern int ScaleFactor; const u32 VRAMDirtyGranularity = 512; @@ -158,7 +159,7 @@ struct RenderSettings { bool Soft_Threaded; - int GL_ScaleFactor; + int ScaleFactor; bool GL_BetterPolygons; }; diff --git a/src/GPU2D.cpp b/src/GPU2D.cpp index d5df992..5549263 100644 --- a/src/GPU2D.cpp +++ b/src/GPU2D.cpp @@ -132,7 +132,7 @@ void Unit::Reset() DispFIFOReadPtr = 0; DispFIFOWritePtr = 0; - memset(DispFIFOBuffer, 0, 256*2); + memset(DispFIFOBuffer, 0, sizeof(DispFIFOBuffer)); CaptureCnt = 0; CaptureLatch = false; @@ -182,7 +182,7 @@ void Unit::DoSavestate(Savestate* file) file->Var32(&DispFIFOReadPtr); file->Var32(&DispFIFOWritePtr); - file->VarArray(DispFIFOBuffer, 256*2); + file->VarArray(DispFIFOBuffer, sizeof(DispFIFOBuffer)); file->Var32(&CaptureCnt); } @@ -422,21 +422,21 @@ void Unit::Write16(u32 addr, u16 val) case 0x026: BGRotD[0] = val; return; case 0x028: BGXRef[0] = (BGXRef[0] & 0xFFFF0000) | val; - if (GPU::VCount < 192) BGXRefInternal[0] = BGXRef[0]; + if (GPU::VCount < NATIVE_HEIGHT) BGXRefInternal[0] = BGXRef[0]; return; case 0x02A: if (val & 0x0800) val |= 0xF000; BGXRef[0] = (BGXRef[0] & 0xFFFF) | (val << 16); - if (GPU::VCount < 192) BGXRefInternal[0] = BGXRef[0]; + if (GPU::VCount < NATIVE_HEIGHT) BGXRefInternal[0] = BGXRef[0]; return; case 0x02C: BGYRef[0] = (BGYRef[0] & 0xFFFF0000) | val; - if (GPU::VCount < 192) BGYRefInternal[0] = BGYRef[0]; + if (GPU::VCount < NATIVE_HEIGHT) BGYRefInternal[0] = BGYRef[0]; return; case 0x02E: if (val & 0x0800) val |= 0xF000; BGYRef[0] = (BGYRef[0] & 0xFFFF) | (val << 16); - if (GPU::VCount < 192) BGYRefInternal[0] = BGYRef[0]; + if (GPU::VCount < NATIVE_HEIGHT) BGYRefInternal[0] = BGYRef[0]; return; case 0x030: BGRotA[1] = val; return; @@ -445,21 +445,21 @@ void Unit::Write16(u32 addr, u16 val) case 0x036: BGRotD[1] = val; return; case 0x038: BGXRef[1] = (BGXRef[1] & 0xFFFF0000) | val; - if (GPU::VCount < 192) BGXRefInternal[1] = BGXRef[1]; + if (GPU::VCount < NATIVE_HEIGHT) BGXRefInternal[1] = BGXRef[1]; return; case 0x03A: if (val & 0x0800) val |= 0xF000; BGXRef[1] = (BGXRef[1] & 0xFFFF) | (val << 16); - if (GPU::VCount < 192) BGXRefInternal[1] = BGXRef[1]; + if (GPU::VCount < NATIVE_HEIGHT) BGXRefInternal[1] = BGXRef[1]; return; case 0x03C: BGYRef[1] = (BGYRef[1] & 0xFFFF0000) | val; - if (GPU::VCount < 192) BGYRefInternal[1] = BGYRef[1]; + if (GPU::VCount < NATIVE_HEIGHT) BGYRefInternal[1] = BGYRef[1]; return; case 0x03E: if (val & 0x0800) val |= 0xF000; BGYRef[1] = (BGYRef[1] & 0xFFFF) | (val << 16); - if (GPU::VCount < 192) BGYRefInternal[1] = BGYRef[1]; + if (GPU::VCount < NATIVE_HEIGHT) BGYRefInternal[1] = BGYRef[1]; return; case 0x040: @@ -541,23 +541,23 @@ void Unit::Write32(u32 addr, u32 val) case 0x028: if (val & 0x08000000) val |= 0xF0000000; BGXRef[0] = val; - if (GPU::VCount < 192) BGXRefInternal[0] = BGXRef[0]; + if (GPU::VCount < NATIVE_HEIGHT) BGXRefInternal[0] = BGXRef[0]; return; case 0x02C: if (val & 0x08000000) val |= 0xF0000000; BGYRef[0] = val; - if (GPU::VCount < 192) BGYRefInternal[0] = BGYRef[0]; + if (GPU::VCount < NATIVE_HEIGHT) BGYRefInternal[0] = BGYRef[0]; return; case 0x038: if (val & 0x08000000) val |= 0xF0000000; BGXRef[1] = val; - if (GPU::VCount < 192) BGXRefInternal[1] = BGXRef[1]; + if (GPU::VCount < NATIVE_HEIGHT) BGXRefInternal[1] = BGXRef[1]; return; case 0x03C: if (val & 0x08000000) val |= 0xF0000000; BGYRef[1] = val; - if (GPU::VCount < 192) BGYRefInternal[1] = BGYRef[1]; + if (GPU::VCount < NATIVE_HEIGHT) BGYRefInternal[1] = BGYRef[1]; return; } } @@ -625,7 +625,7 @@ void Unit::SampleFIFO(u32 offset, u32 num) u16* Unit::GetBGExtPal(u32 slot, u32 pal) { - const u32 PaletteSize = 256 * 2; + const u32 PaletteSize = NATIVE_WIDTH * 2; const u32 SlotSize = PaletteSize * 16; return (u16*)&(Num == 0 ? GPU::VRAMFlat_ABGExtPal @@ -650,13 +650,13 @@ void Unit::CheckWindows(u32 line) void Unit::CalculateWindowMask(u32 line, u8* windowMask, u8* objWindow) { - for (u32 i = 0; i < 256; i++) + for (u32 i = 0; i < NATIVE_WIDTH; i++) windowMask[i] = WinCnt[2]; // window outside if (DispCnt & (1<<15)) { // OBJ window - for (int i = 0; i < 256; i++) + for (int i = 0; i < NATIVE_WIDTH; i++) { if (objWindow[i]) windowMask[i] = WinCnt[3]; @@ -669,7 +669,7 @@ void Unit::CalculateWindowMask(u32 line, u8* windowMask, u8* objWindow) u8 x1 = Win1Coords[0]; u8 x2 = Win1Coords[1]; - for (int i = 0; i < 256; i++) + for (int i = 0; i < NATIVE_WIDTH; i++) { if (i == x2) Win1Active &= ~0x2; else if (i == x1) Win1Active |= 0x2; @@ -684,7 +684,7 @@ void Unit::CalculateWindowMask(u32 line, u8* windowMask, u8* objWindow) u8 x1 = Win0Coords[0]; u8 x2 = Win0Coords[1]; - for (int i = 0; i < 256; i++) + for (int i = 0; i < NATIVE_WIDTH; i++) { if (i == x2) Win0Active &= ~0x2; else if (i == x1) Win0Active |= 0x2; diff --git a/src/GPU2D.h b/src/GPU2D.h index 5edc0a2..bf64fb5 100644 --- a/src/GPU2D.h +++ b/src/GPU2D.h @@ -19,6 +19,9 @@ #ifndef GPU2D_H #define GPU2D_H +#define NATIVE_WIDTH 256 +#define NATIVE_HEIGHT 192 + #include "types.h" #include "Savestate.h" @@ -79,7 +82,7 @@ public: u32 DispFIFOReadPtr; u32 DispFIFOWritePtr; - u16 DispFIFOBuffer[256]; + u16 DispFIFOBuffer[NATIVE_WIDTH]; u32 DispCnt; u16 BGCnt[4]; @@ -133,6 +136,8 @@ public: Framebuffer[0] = unitA; Framebuffer[1] = unitB; } + + virtual void SetRenderSettings(int scale) {} protected: u32* Framebuffer[2]; diff --git a/src/GPU2D_Soft.cpp b/src/GPU2D_Soft.cpp index 070079a..ef6d0f4 100644 --- a/src/GPU2D_Soft.cpp +++ b/src/GPU2D_Soft.cpp @@ -28,12 +28,27 @@ SoftRenderer::SoftRenderer() // initialize mosaic table for (int m = 0; m < 16; m++) { - for (int x = 0; x < 256; x++) + for (int x = 0; x < NATIVE_WIDTH; x++) { int offset = x % (m+1); MosaicTable[m][x] = offset; } } + + BGOBJLine = NULL; +} + +SoftRenderer::~SoftRenderer() +{ + if (BGOBJLine) operator delete[](BGOBJLine, std::align_val_t(8)); + BGOBJLine = NULL; +} + +void SoftRenderer::SetRenderSettings(int scale) +{ + if (BGOBJLine) operator delete[](BGOBJLine, std::align_val_t(8)); + int len = GPU3D::CurrentRenderer->Accelerated ? NATIVE_WIDTH * 3 : NATIVE_WIDTH * scale * scale * 2; + BGOBJLine = new(std::align_val_t(8)) u32[len]; } u32 SoftRenderer::ColorBlend4(u32 val1, u32 val2, u32 eva, u32 evb) @@ -165,10 +180,12 @@ void SoftRenderer::DrawScanline(u32 line, Unit* unit) { CurUnit = unit; - int stride = GPU3D::CurrentRenderer->Accelerated ? (256*3 + 1) : 256; + // multiply by ScaleFactor twice, because we want to multiply line number and width + int pixelCount = GPU3D::CurrentRenderer->Accelerated ? NATIVE_WIDTH : NATIVE_WIDTH * GPU::ScaleFactor * GPU::ScaleFactor; + int stride = GPU3D::CurrentRenderer->Accelerated ? pixelCount*3 + 1 : pixelCount; u32* dst = &Framebuffer[CurUnit->Num][stride * line]; - int n3dline = line; + int n3dline = GPU3D::CurrentRenderer->Accelerated ? line : line * GPU::ScaleFactor; line = GPU::VCount; if (CurUnit->Num == 0) @@ -194,7 +211,7 @@ void SoftRenderer::DrawScanline(u32 line, Unit* unit) // scanlines that end up outside of the GPU drawing range // (as a result of writing to VCount) are filled white - if (line > 192) forceblank = true; + if (line > NATIVE_HEIGHT) forceblank = true; // GPU B can be completely disabled by POWCNT1 // oddly that's not the case for GPU A @@ -216,12 +233,12 @@ void SoftRenderer::DrawScanline(u32 line, Unit* unit) if (forceblank) { - for (int i = 0; i < 256; i++) + for (int i = 0; i < pixelCount; i++) dst[i] = 0xFFFFFFFF; if (GPU3D::CurrentRenderer->Accelerated) { - dst[256*3] = 0; + dst[NATIVE_WIDTH*3] = 0; } return; } @@ -237,7 +254,7 @@ void SoftRenderer::DrawScanline(u32 line, Unit* unit) { case 0: // screen off { - for (int i = 0; i < 256; i++) + for (int i = 0; i < pixelCount; i++) dst[i] = 0x003F3F3F; } break; @@ -256,9 +273,9 @@ void SoftRenderer::DrawScanline(u32 line, Unit* unit) if (GPU::VRAMMap_LCDC & (1<<vrambank)) { u16* vram = (u16*)GPU::VRAM[vrambank]; - vram = &vram[line * 256]; + vram = &vram[line * NATIVE_WIDTH]; - for (int i = 0; i < 256; i++) + for (int i = 0; i < NATIVE_WIDTH; i++) { u16 color = vram[i]; u8 r = (color & 0x001F) << 1; @@ -267,10 +284,11 @@ void SoftRenderer::DrawScanline(u32 line, Unit* unit) dst[i] = r | (g << 8) | (b << 16); } + ExpandLine(dst); } else { - for (int i = 0; i < 256; i++) + for (int i = 0; i < pixelCount; i++) { dst[i] = 0; } @@ -280,7 +298,7 @@ void SoftRenderer::DrawScanline(u32 line, Unit* unit) case 3: // FIFO display { - for (int i = 0; i < 256; i++) + for (int i = 0; i < NATIVE_WIDTH; i++) { u16 color = CurUnit->DispFIFOBuffer[i]; u8 r = (color & 0x001F) << 1; @@ -289,6 +307,7 @@ void SoftRenderer::DrawScanline(u32 line, Unit* unit) dst[i] = r | (g << 8) | (b << 16); } + ExpandLine(dst); } break; } @@ -313,7 +332,7 @@ void SoftRenderer::DrawScanline(u32 line, Unit* unit) if (GPU3D::CurrentRenderer->Accelerated) { - dst[256*3] = masterBrightness | (CurUnit->DispCnt & 0x30000); + dst[NATIVE_WIDTH*3] = masterBrightness | (CurUnit->DispCnt & 0x30000); return; } @@ -326,7 +345,7 @@ void SoftRenderer::DrawScanline(u32 line, Unit* unit) u32 factor = masterBrightness & 0x1F; if (factor > 16) factor = 16; - for (int i = 0; i < 256; i++) + for (int i = 0; i < pixelCount; i++) { dst[i] = ColorBrightnessUp(dst[i], factor, 0x0); } @@ -337,7 +356,7 @@ void SoftRenderer::DrawScanline(u32 line, Unit* unit) u32 factor = masterBrightness & 0x1F; if (factor > 16) factor = 16; - for (int i = 0; i < 256; i++) + for (int i = 0; i < pixelCount; i++) { dst[i] = ColorBrightnessDown(dst[i], factor, 0xF); } @@ -347,7 +366,7 @@ void SoftRenderer::DrawScanline(u32 line, Unit* unit) // convert to 32-bit BGRA // note: 32-bit RGBA would be more straightforward, but // BGRA seems to be more compatible (Direct2D soft, cairo...) - for (int i = 0; i < 256; i+=2) + for (int i = 0; i < pixelCount; i+=2) { u64 c = *(u64*)&dst[i]; @@ -373,6 +392,29 @@ void SoftRenderer::VBlankEnd(Unit* unitA, Unit* unitB) #endif } +void SoftRenderer::ExpandLine(u32* line) +{ + if (GPU3D::CurrentRenderer->Accelerated || GPU::ScaleFactor == 1) + return; + + u32 lineWidth = NATIVE_WIDTH * GPU::ScaleFactor; + + // write to the last line, so that we don't mess up the original line + u32* dst = line + (GPU::ScaleFactor - 1) * lineWidth; + u32* src = line; + for (int x = 0; x < NATIVE_WIDTH; x++) + { + for (int i = 0; i < GPU::ScaleFactor; i++) + *dst++ = *src; + src++; + } + + // copy last line to all other lines + src = line + (GPU::ScaleFactor - 1) * lineWidth; + for (int i = 0; i < GPU::ScaleFactor - 1; i++) + memcpy(line + i * lineWidth, src, lineWidth * sizeof(u32)); +} + void SoftRenderer::DoCapture(u32 line, u32 width) { u32 captureCnt = CurUnit->CaptureCnt; @@ -389,6 +431,7 @@ void SoftRenderer::DoCapture(u32 line, u32 width) // TODO: handle 3D in GPU3D::CurrentRenderer->Accelerated mode!! u32* srcA; + u32 srcAScale = GPU3D::CurrentRenderer->Accelerated ? 1 : GPU::ScaleFactor; if (captureCnt & (1<<24)) { srcA = _3DLine; @@ -402,11 +445,11 @@ void SoftRenderer::DoCapture(u32 line, u32 width) // but when doing display capture, we do need the composited output // so we do it here - for (int i = 0; i < 256; i++) + for (int i = 0; i < NATIVE_WIDTH; i++) { u32 val1 = BGOBJLine[i]; - u32 val2 = BGOBJLine[256+i]; - u32 val3 = BGOBJLine[512+i]; + u32 val2 = BGOBJLine[NATIVE_WIDTH+i]; + u32 val3 = BGOBJLine[NATIVE_WIDTH*2+i]; u32 compmode = (val3 >> 24) & 0xF; @@ -458,7 +501,7 @@ void SoftRenderer::DoCapture(u32 line, u32 width) } u16* srcB = NULL; - u32 srcBaddr = line * 256; + u32 srcBaddr = line * NATIVE_WIDTH; if (captureCnt & (1<<25)) { @@ -487,7 +530,8 @@ void SoftRenderer::DoCapture(u32 line, u32 width) { for (u32 i = 0; i < width; i++) { - u32 val = srcA[i]; + u32 val = *srcA; + srcA += srcAScale; // TODO: check what happens when alpha=0 @@ -538,7 +582,8 @@ void SoftRenderer::DoCapture(u32 line, u32 width) { for (u32 i = 0; i < width; i++) { - u32 val = srcA[i]; + u32 val = *srcA; + srcA += srcAScale; // TODO: check what happens when alpha=0 @@ -572,7 +617,8 @@ void SoftRenderer::DoCapture(u32 line, u32 width) { for (u32 i = 0; i < width; i++) { - u32 val = srcA[i]; + u32 val = *srcA; + srcA += srcAScale; // TODO: check what happens when alpha=0 @@ -601,12 +647,14 @@ void SoftRenderer::DoCapture(u32 line, u32 width) if ((bgCnt[num] & 0x0040) && (CurUnit->BGMosaicSize[0] > 0)) \ { \ if (GPU3D::CurrentRenderer->Accelerated) DrawBG_##type<true, DrawPixel_Accel>(line, num); \ - else DrawBG_##type<true, DrawPixel_Normal>(line, num); \ + else if (GPU::ScaleFactor == 1) DrawBG_##type<true, DrawPixel_Normal>(line, num); \ + else DrawBG_##type<true, DrawPixel_HiRes>(line, num); \ } \ else \ { \ if (GPU3D::CurrentRenderer->Accelerated) DrawBG_##type<false, DrawPixel_Accel>(line, num); \ - else DrawBG_##type<false, DrawPixel_Normal>(line, num); \ + else if (GPU::ScaleFactor == 1) DrawBG_##type<false, DrawPixel_Normal>(line, num); \ + else DrawBG_##type<false, DrawPixel_HiRes>(line, num); \ } \ } while (false) @@ -616,17 +664,21 @@ void SoftRenderer::DoCapture(u32 line, u32 width) if ((bgCnt[2] & 0x0040) && (CurUnit->BGMosaicSize[0] > 0)) \ { \ if (GPU3D::CurrentRenderer->Accelerated) DrawBG_Large<true, DrawPixel_Accel>(line); \ - else DrawBG_Large<true, DrawPixel_Normal>(line); \ + else if (GPU::ScaleFactor == 1) DrawBG_Large<true, DrawPixel_Normal>(line); \ + else DrawBG_Large<true, DrawPixel_HiRes>(line); \ } \ else \ { \ if (GPU3D::CurrentRenderer->Accelerated) DrawBG_Large<false, DrawPixel_Accel>(line); \ - else DrawBG_Large<false, DrawPixel_Normal>(line); \ + else if (GPU::ScaleFactor == 1) DrawBG_Large<false, DrawPixel_Normal>(line); \ + else DrawBG_Large<false, DrawPixel_HiRes>(line); \ } \ } while (false) #define DoInterleaveSprites(prio) \ - if (GPU3D::CurrentRenderer->Accelerated) InterleaveSprites<DrawPixel_Accel>(prio); else InterleaveSprites<DrawPixel_Normal>(prio); + if (GPU3D::CurrentRenderer->Accelerated) InterleaveSprites<DrawPixel_Accel>(prio); \ + else if (GPU::ScaleFactor == 1) InterleaveSprites<DrawPixel_Normal>(prio); \ + else InterleaveSprites<DrawPixel_HiRes>(prio); template<u32 bgmode> void SoftRenderer::DrawScanlineBGMode(u32 line) @@ -746,10 +798,11 @@ void SoftRenderer::DrawScanlineBGMode7(u32 line) void SoftRenderer::DrawScanline_BGOBJ(u32 line) { + int pixelCount = GPU3D::CurrentRenderer->Accelerated ? NATIVE_WIDTH : NATIVE_WIDTH * GPU::ScaleFactor * GPU::ScaleFactor; // forced blank disables BG/OBJ compositing if (CurUnit->DispCnt & (1<<7)) { - for (int i = 0; i < 256; i++) + for (int i = 0; i < pixelCount; i++) BGOBJLine[i] = 0xFF3F3F3F; return; @@ -767,14 +820,14 @@ void SoftRenderer::DrawScanline_BGOBJ(u32 line) backdrop = r | (g << 8) | (b << 16) | 0x20000000; backdrop |= (backdrop << 32); - for (int i = 0; i < 256; i+=2) + for (int i = 0; i < pixelCount; i+=2) *(u64*)&BGOBJLine[i] = backdrop; } if (CurUnit->DispCnt & 0xE000) CurUnit->CalculateWindowMask(line, WindowMask, OBJWindow[CurUnit->Num]); else - memset(WindowMask, 0xFF, 256); + memset(WindowMask, 0xFF, NATIVE_WIDTH); ApplySpriteMosaicX(); CurBGXMosaicTable = MosaicTable[CurUnit->BGMosaicSize[0]]; @@ -796,23 +849,23 @@ void SoftRenderer::DrawScanline_BGOBJ(u32 line) if (!GPU3D::CurrentRenderer->Accelerated) { - for (int i = 0; i < 256; i++) + for (int i = 0; i < pixelCount; i++) { u32 val1 = BGOBJLine[i]; - u32 val2 = BGOBJLine[256+i]; + u32 val2 = BGOBJLine[pixelCount+i]; - BGOBJLine[i] = ColorComposite(i, val1, val2); + BGOBJLine[i] = ColorComposite((i / GPU::ScaleFactor) & 0xFF, val1, val2); } } else { if (CurUnit->Num == 0) { - for (int i = 0; i < 256; i++) + for (int i = 0; i < NATIVE_WIDTH; i++) { u32 val1 = BGOBJLine[i]; - u32 val2 = BGOBJLine[256+i]; - u32 val3 = BGOBJLine[512+i]; + u32 val2 = BGOBJLine[NATIVE_WIDTH+i]; + u32 val3 = BGOBJLine[NATIVE_WIDTH*2+i]; u32 flag1 = val1 >> 24; u32 flag2 = val2 >> 24; @@ -834,8 +887,8 @@ void SoftRenderer::DrawScanline_BGOBJ(u32 line) // 3D on top, blending BGOBJLine[i] = val2; - BGOBJLine[256+i] = ColorComposite(i, val2, val3); - BGOBJLine[512+i] = 0x04000000; + BGOBJLine[NATIVE_WIDTH+i] = ColorComposite(i, val2, val3); + BGOBJLine[NATIVE_WIDTH*2+i] = 0x04000000; } else if ((flag1 & 0xC0) == 0x40) { @@ -846,8 +899,8 @@ void SoftRenderer::DrawScanline_BGOBJ(u32 line) if (!(WindowMask[i] & 0x20)) bldcnteffect = 0; BGOBJLine[i] = val2; - BGOBJLine[256+i] = ColorComposite(i, val2, val3); - BGOBJLine[512+i] = (bldcnteffect << 24) | (CurUnit->EVY << 8); + BGOBJLine[NATIVE_WIDTH+i] = ColorComposite(i, val2, val3); + BGOBJLine[NATIVE_WIDTH*2+i] = (bldcnteffect << 24) | (CurUnit->EVY << 8); } else if (((flag2 & 0xC0) == 0x40) && ((CurUnit->BlendCnt & 0x01C0) == 0x0140)) { @@ -869,29 +922,29 @@ void SoftRenderer::DrawScanline_BGOBJ(u32 line) bldcnteffect = 7; BGOBJLine[i] = val1; - BGOBJLine[256+i] = ColorComposite(i, val1, val3); - BGOBJLine[512+i] = (bldcnteffect << 24) | (CurUnit->EVB << 16) | (CurUnit->EVA << 8); + BGOBJLine[NATIVE_WIDTH+i] = ColorComposite(i, val1, val3); + BGOBJLine[NATIVE_WIDTH*2+i] = (bldcnteffect << 24) | (CurUnit->EVB << 16) | (CurUnit->EVA << 8); } else { // no potential 3D pixel involved BGOBJLine[i] = ColorComposite(i, val1, val2); - BGOBJLine[256+i] = 0; - BGOBJLine[512+i] = 0x07000000; + BGOBJLine[NATIVE_WIDTH+i] = 0; + BGOBJLine[NATIVE_WIDTH*2+i] = 0x07000000; } } } else { - for (int i = 0; i < 256; i++) + for (int i = 0; i < NATIVE_WIDTH; i++) { u32 val1 = BGOBJLine[i]; - u32 val2 = BGOBJLine[256+i]; + u32 val2 = BGOBJLine[NATIVE_WIDTH+i]; BGOBJLine[i] = ColorComposite(i, val1, val2); - BGOBJLine[256+i] = 0; - BGOBJLine[512+i] = 0x07000000; + BGOBJLine[NATIVE_WIDTH+i] = 0; + BGOBJLine[NATIVE_WIDTH*2+i] = 0x07000000; } } } @@ -914,54 +967,92 @@ void SoftRenderer::DrawScanline_BGOBJ(u32 line) } -void SoftRenderer::DrawPixel_Normal(u32* dst, u16 color, u32 flag) +void SoftRenderer::DrawPixel_Normal(u32* dst, u32 index, u16 color, u32 flag) { + dst += index; + u8 r = (color & 0x001F) << 1; u8 g = (color & 0x03E0) >> 4; u8 b = (color & 0x7C00) >> 9; //g |= ((color & 0x8000) >> 15); - *(dst+256) = *dst; + *(dst+NATIVE_WIDTH) = *dst; *dst = r | (g << 8) | (b << 16) | flag; } -void SoftRenderer::DrawPixel_Accel(u32* dst, u16 color, u32 flag) +void SoftRenderer::DrawPixel_HiRes(u32* dst, u32 index, u16 color, u32 flag) { + // note: dst is always BGOBJLine + // The index given is as if ScaleFactor were 1. + dst += index * GPU::ScaleFactor; + u8 r = (color & 0x001F) << 1; u8 g = (color & 0x03E0) >> 4; u8 b = (color & 0x7C00) >> 9; + u32 value = r | (g << 8) | (b << 16) | flag; - *(dst+512) = *(dst+256); - *(dst+256) = *dst; + u32 lineLength = NATIVE_WIDTH * GPU::ScaleFactor; + u32 pixelCount = lineLength * GPU::ScaleFactor; + for (int y = 0; y < GPU::ScaleFactor; y++) + { + u32* addr = dst + y * lineLength; + for (int x = 0; x < GPU::ScaleFactor; x++) + { + addr[x + pixelCount] = addr[x]; + addr[x] = value; + } + } +} + +void SoftRenderer::DrawPixel_Accel(u32* dst, u32 index, u16 color, u32 flag) +{ + dst += index; + + u8 r = (color & 0x001F) << 1; + u8 g = (color & 0x03E0) >> 4; + u8 b = (color & 0x7C00) >> 9; + + *(dst+NATIVE_WIDTH*2) = *(dst+NATIVE_WIDTH); + *(dst+NATIVE_WIDTH) = *dst; *dst = r | (g << 8) | (b << 16) | flag; } void SoftRenderer::DrawBG_3D() { - int i = 0; - if (GPU3D::CurrentRenderer->Accelerated) { - for (i = 0; i < 256; i++) + for (int i = 0; i < NATIVE_WIDTH; i++) { if (!(WindowMask[i] & 0x01)) continue; - BGOBJLine[i+512] = BGOBJLine[i+256]; - BGOBJLine[i+256] = BGOBJLine[i]; + BGOBJLine[i+NATIVE_WIDTH*2] = BGOBJLine[i+NATIVE_WIDTH]; + BGOBJLine[i+NATIVE_WIDTH] = BGOBJLine[i]; BGOBJLine[i] = 0x40000000; // 3D-layer placeholder } } else { - for (i = 0; i < 256; i++) + int pixelCount = NATIVE_WIDTH * GPU::ScaleFactor * GPU::ScaleFactor; + // soft renderer has a 1-pixel border + u32 stride3D = GPU3D::CurrentRenderer->GetStride(); + for (int x = 0; x < NATIVE_WIDTH; x++) { - u32 c = _3DLine[i]; + if (!(WindowMask[x] & 0x01)) + continue; - if ((c >> 24) == 0) continue; - if (!(WindowMask[i] & 0x01)) continue; + for (int y = 0; y < GPU::ScaleFactor; y++) + { + u32* src = _3DLine + y * stride3D + x * GPU::ScaleFactor; + u32* dst = BGOBJLine + y * NATIVE_WIDTH * GPU::ScaleFactor + x * GPU::ScaleFactor; + for (int i = 0; i < GPU::ScaleFactor; i++) + { + u32 c = src[i]; + if ((c >> 24) == 0) continue; - BGOBJLine[i+256] = BGOBJLine[i]; - BGOBJLine[i] = c | 0x40000000; + dst[i+pixelCount] = dst[i]; + dst[i] = c | 0x40000000; + } + } } } } @@ -1041,7 +1132,7 @@ void SoftRenderer::DrawBG_Text(u32 line, u32 bgnum) if (mosaic) lastxpos = xoff; - for (int i = 0; i < 256; i++) + for (int i = 0; i < NATIVE_WIDTH; i++) { u32 xpos; if (mosaic) xpos = xoff - CurBGXMosaicTable[i]; @@ -1069,7 +1160,7 @@ void SoftRenderer::DrawBG_Text(u32 line, u32 bgnum) color = bgvram[(pixelsaddr + tilexoff) & bgvrammask]; if (color) - drawPixel(&BGOBJLine[i], curpal[color], 0x01000000<<bgnum); + drawPixel(BGOBJLine, i, curpal[color], 0x01000000<<bgnum); } xoff++; @@ -1090,7 +1181,7 @@ void SoftRenderer::DrawBG_Text(u32 line, u32 bgnum) if (mosaic) lastxpos = xoff; - for (int i = 0; i < 256; i++) + for (int i = 0; i < NATIVE_WIDTH; i++) { u32 xpos; if (mosaic) xpos = xoff - CurBGXMosaicTable[i]; @@ -1122,7 +1213,7 @@ void SoftRenderer::DrawBG_Text(u32 line, u32 bgnum) } if (color) - drawPixel(&BGOBJLine[i], curpal[color], 0x01000000<<bgnum); + drawPixel(BGOBJLine, i, curpal[color], 0x01000000<<bgnum); } xoff++; @@ -1191,7 +1282,7 @@ void SoftRenderer::DrawBG_Affine(u32 line, u32 bgnum) yshift -= 3; - for (int i = 0; i < 256; i++) + for (int i = 0; i < NATIVE_WIDTH; i++) { if (WindowMask[i] & (1<<bgnum)) { @@ -1219,7 +1310,7 @@ void SoftRenderer::DrawBG_Affine(u32 line, u32 bgnum) color = bgvram[(tilesetaddr + (curtile << 6) + (tileyoff << 3) + tilexoff) & bgvrammask]; if (color) - drawPixel(&BGOBJLine[i], pal[color], 0x01000000<<bgnum); + drawPixel(BGOBJLine, i, pal[color], 0x01000000<<bgnum); } } @@ -1296,7 +1387,7 @@ void SoftRenderer::DrawBG_Extended(u32 line, u32 bgnum) u16 color; - for (int i = 0; i < 256; i++) + for (int i = 0; i < NATIVE_WIDTH; i++) { if (WindowMask[i] & (1<<bgnum)) { @@ -1318,7 +1409,7 @@ void SoftRenderer::DrawBG_Extended(u32 line, u32 bgnum) color = *(u16*)&bgvram[(tilemapaddr + (((((finalY & ymask) >> 8) << yshift) + ((finalX & xmask) >> 8)) << 1)) & bgvrammask]; if (color & 0x8000) - drawPixel(&BGOBJLine[i], color, 0x01000000<<bgnum); + drawPixel(BGOBJLine, i, color, 0x01000000<<bgnum); } } @@ -1335,7 +1426,7 @@ void SoftRenderer::DrawBG_Extended(u32 line, u32 bgnum) u8 color; - for (int i = 0; i < 256; i++) + for (int i = 0; i < NATIVE_WIDTH; i++) { if (WindowMask[i] & (1<<bgnum)) { @@ -1357,7 +1448,7 @@ void SoftRenderer::DrawBG_Extended(u32 line, u32 bgnum) color = bgvram[(tilemapaddr + (((finalY & ymask) >> 8) << yshift) + ((finalX & xmask) >> 8)) & bgvrammask]; if (color) - drawPixel(&BGOBJLine[i], pal[color], 0x01000000<<bgnum); + drawPixel(BGOBJLine, i, pal[color], 0x01000000<<bgnum); } } @@ -1405,7 +1496,7 @@ void SoftRenderer::DrawBG_Extended(u32 line, u32 bgnum) yshift -= 3; - for (int i = 0; i < 256; i++) + for (int i = 0; i < NATIVE_WIDTH; i++) { if (WindowMask[i] & (1<<bgnum)) { @@ -1439,7 +1530,7 @@ void SoftRenderer::DrawBG_Extended(u32 line, u32 bgnum) color = bgvram[(tilesetaddr + ((curtile & 0x03FF) << 6) + (tileyoff << 3) + tilexoff) & bgvrammask]; if (color) - drawPixel(&BGOBJLine[i], curpal[color], 0x01000000<<bgnum); + drawPixel(BGOBJLine, i, curpal[color], 0x01000000<<bgnum); } } @@ -1512,7 +1603,7 @@ void SoftRenderer::DrawBG_Large(u32 line) // BG is always BG2 u8 color; - for (int i = 0; i < 256; i++) + for (int i = 0; i < NATIVE_WIDTH; i++) { if (WindowMask[i] & (1<<2)) { @@ -1534,7 +1625,7 @@ void SoftRenderer::DrawBG_Large(u32 line) // BG is always BG2 color = bgvram[((((finalY & ymask) >> 8) << yshift) + ((finalX & xmask) >> 8)) & bgvrammask]; if (color) - drawPixel(&BGOBJLine[i], pal[color], 0x01000000<<2); + drawPixel(BGOBJLine, i, pal[color], 0x01000000<<2); } } @@ -1566,7 +1657,7 @@ void SoftRenderer::ApplySpriteMosaicX() u32 lastcolor = objLine[0]; - for (u32 i = 1; i < 256; i++) + for (u32 i = 1; i < NATIVE_WIDTH; i++) { u32 currentcolor = objLine[i]; @@ -1587,7 +1678,7 @@ void SoftRenderer::InterleaveSprites(u32 prio) { u16* extpal = CurUnit->GetOBJExtPal(); - for (u32 i = 0; i < 256; i++) + for (u32 i = 0; i < NATIVE_WIDTH; i++) { if ((objLine[i] & 0x70000) != prio) continue; if (!(WindowMask[i] & 0x10)) continue; @@ -1602,14 +1693,14 @@ void SoftRenderer::InterleaveSprites(u32 prio) else color = extpal[pixel & 0xFFF]; - drawPixel(&BGOBJLine[i], color, pixel & 0xFF000000); + drawPixel(BGOBJLine, i, color, pixel & 0xFF000000); } } else { // optimized no-extpal version - for (u32 i = 0; i < 256; i++) + for (u32 i = 0; i < NATIVE_WIDTH; i++) { if ((objLine[i] & 0x70000) != prio) continue; if (!(WindowMask[i] & 0x10)) continue; @@ -1622,7 +1713,7 @@ void SoftRenderer::InterleaveSprites(u32 prio) else color = pal[pixel & 0xFF]; - drawPixel(&BGOBJLine[i], color, pixel & 0xFF000000); + drawPixel(BGOBJLine, i, color, pixel & 0xFF000000); } } } @@ -1665,8 +1756,8 @@ void SoftRenderer::DrawSprites(u32 line, Unit* unit) } NumSprites[CurUnit->Num] = 0; - memset(OBJLine[CurUnit->Num], 0, 256*4); - memset(OBJWindow[CurUnit->Num], 0, 256); + memset(OBJLine[CurUnit->Num], 0, sizeof(OBJLine)); + memset(OBJWindow[CurUnit->Num], 0, sizeof(OBJWindow)); if (!(CurUnit->DispCnt & 0x1000)) return; u16* oam = (u16*)&GPU::OAM[CurUnit->Num ? 0x400 : 0]; @@ -1794,8 +1885,8 @@ void SoftRenderer::DrawSprite_Rotscale(u32 num, u32 boundwidth, u32 boundheight, if (xpos >= 0) { xoff = 0; - if ((xpos+boundwidth) > 256) - boundwidth = 256-xpos; + if ((xpos+boundwidth) > NATIVE_WIDTH) + boundwidth = NATIVE_WIDTH-xpos; } else { @@ -2007,8 +2098,8 @@ void SoftRenderer::DrawSprite_Normal(u32 num, u32 width, u32 height, s32 xpos, s if (xpos >= 0) { xoff = 0; - if ((xpos+xend) > 256) - xend = 256-xpos; + if ((xpos+xend) > NATIVE_WIDTH) + xend = NATIVE_WIDTH-xpos; } else { diff --git a/src/GPU2D_Soft.h b/src/GPU2D_Soft.h index a9fff97..6f0098c 100644 --- a/src/GPU2D_Soft.h +++ b/src/GPU2D_Soft.h @@ -27,24 +27,24 @@ class SoftRenderer : public Renderer2D { public: SoftRenderer(); - ~SoftRenderer() override {} + ~SoftRenderer() override; void DrawScanline(u32 line, Unit* unit) override; void DrawSprites(u32 line, Unit* unit) override; void VBlankEnd(Unit* unitA, Unit* unitB) override; private: - alignas(8) u32 BGOBJLine[256*3]; + u32* BGOBJLine; u32* _3DLine; - alignas(8) u8 WindowMask[256]; + alignas(8) u8 WindowMask[NATIVE_WIDTH]; - alignas(8) u32 OBJLine[2][256]; - alignas(8) u8 OBJWindow[2][256]; + alignas(8) u32 OBJLine[2][NATIVE_WIDTH]; + alignas(8) u8 OBJWindow[2][NATIVE_WIDTH]; u32 NumSprites[2]; u8* CurBGXMosaicTable; - u8 MosaicTable[16][256]; + u8 MosaicTable[16][NATIVE_WIDTH];; u32 ColorBlend4(u32 val1, u32 val2, u32 eva, u32 evb); u32 ColorBlend5(u32 val1, u32 val2); @@ -57,10 +57,11 @@ private: void DrawScanlineBGMode7(u32 line); void DrawScanline_BGOBJ(u32 line); - static void DrawPixel_Normal(u32* dst, u16 color, u32 flag); - static void DrawPixel_Accel(u32* dst, u16 color, u32 flag); + static void DrawPixel_Normal(u32* dst, u32 index, u16 color, u32 flag); + static void DrawPixel_HiRes(u32* dst, u32 index, u16 color, u32 flag); + static void DrawPixel_Accel(u32* dst, u32 index, u16 color, u32 flag); - typedef void (*DrawPixel)(u32* dst, u16 color, u32 flag); + typedef void (*DrawPixel)(u32* dst, u32 index, u16 color, u32 flag); void DrawBG_3D(); template<bool mosaic, DrawPixel drawPixel> void DrawBG_Text(u32 line, u32 bgnum); @@ -74,6 +75,7 @@ private: template<bool window> void DrawSprite_Rotscale(u32 num, u32 boundwidth, u32 boundheight, u32 width, u32 height, s32 xpos, s32 ypos); template<bool window> void DrawSprite_Normal(u32 num, u32 width, u32 height, s32 xpos, s32 ypos); + void ExpandLine(u32* line); void DoCapture(u32 line, u32 width); }; diff --git a/src/GPU3D.cpp b/src/GPU3D.cpp index dcd5bd7..8f16d25 100644 --- a/src/GPU3D.cpp +++ b/src/GPU3D.cpp @@ -275,6 +275,7 @@ u32 RenderNumPolygons; u32 FlushRequest; u32 FlushAttributes; +u32 CalculatePolygonMetadata(Polygon* poly); std::unique_ptr<GPU3D::Renderer3D> CurrentRenderer = {}; bool AbortFrame; @@ -514,7 +515,14 @@ void DoSavestate(Savestate* file) file->Bool32(&vtx->Clipped); - file->VarArray(vtx->FinalPosition, sizeof(s32)*2); + if (file->IsAtleastVersion(7, 3)) + { + file->VarArray(vtx->HiresPosition, sizeof(s32)*2); + vtx->FinalPosition[0] = (vtx->HiresPosition[0] * GPU::ScaleFactor) >> HD_SHIFT; + vtx->FinalPosition[1] = (vtx->HiresPosition[1] * GPU::ScaleFactor) >> HD_SHIFT; + } + else + file->VarArray(vtx->FinalPosition, sizeof(s32)*2); file->VarArray(vtx->FinalColor, sizeof(s32)*3); } @@ -567,27 +575,33 @@ void DoSavestate(Savestate* file) else poly->Type = 0; - file->Var32(&poly->VTop); - file->Var32(&poly->VBottom); - file->Var32((u32*)&poly->YTop); - file->Var32((u32*)&poly->YBottom); - file->Var32((u32*)&poly->XTop); - file->Var32((u32*)&poly->XBottom); - - file->Var32(&poly->SortKey); - - if (!file->Saving) + if (!file->IsAtleastVersion(10, 3)) { poly->Degenerate = false; + file->Var32(&poly->VTop); + file->Var32(&poly->VBottom); + file->Var32((u32*)&poly->YTop); + file->Var32((u32*)&poly->YBottom); + file->Var32((u32*)&poly->XTop); + file->Var32((u32*)&poly->XBottom); - for (u32 j = 0; j < poly->NumVertices; j++) + file->Var32(&poly->SortKey); + + if (!file->Saving) { - if (poly->Vertices[j]->Position[3] == 0) - poly->Degenerate = true; - } + poly->Degenerate = false; + + for (u32 j = 0; j < poly->NumVertices; j++) + { + if (poly->Vertices[j]->Position[3] == 0) + poly->Degenerate = true; + } - if (poly->YBottom > 192) poly->Degenerate = true; + if (poly->YBottom > 192) poly->Degenerate = true; + } } + else if (!file->Saving) + CalculatePolygonMetadata(poly); } // probably not worth storing the vblank-latched Renderxxxxxx variables @@ -1182,7 +1196,7 @@ void SubmitPolygon() // note: the DS performs these divisions using a 32-bit divider // thus, if W is greater than 0xFFFF, some precision is sacrificed // to make the numbers fit into the divider - u32 posX, posY; + u64 posX, posY; u32 w = vtx->Position[3]; if (w == 0) { @@ -1203,23 +1217,15 @@ void SubmitPolygon() } den <<= 1; - posX = ((posX * Viewport[4]) / den) + Viewport[0]; - posY = ((posY * Viewport[5]) / den) + Viewport[3]; + posX = (((posX * Viewport[4]) << HD_SHIFT) / den) + (Viewport[0] << HD_SHIFT); + posY = (((posY * Viewport[5]) << HD_SHIFT) / den) + (Viewport[3] << HD_SHIFT); } - vtx->FinalPosition[0] = posX & 0x1FF; - vtx->FinalPosition[1] = posY & 0xFF; - - // hi-res positions - // to consider: only do this when using the GL renderer? apply the aforementioned quirk to this? - if (w != 0) - { - posX = ((((s64)(vtx->Position[0] + w) * Viewport[4]) << 4) / (((s64)w) << 1)) + (Viewport[0] << 4); - posY = ((((s64)(-vtx->Position[1] + w) * Viewport[5]) << 4) / (((s64)w) << 1)) + (Viewport[3] << 4); + vtx->HiresPosition[0] = posX & (0x200 << HD_SHIFT) - 1; + vtx->HiresPosition[1] = posY & (0x100 << HD_SHIFT) - 1; - vtx->HiresPosition[0] = posX & 0x1FFF; - vtx->HiresPosition[1] = posY & 0xFFF; - } + vtx->FinalPosition[0] = (vtx->HiresPosition[0] * GPU::ScaleFactor) >> HD_SHIFT; + vtx->FinalPosition[1] = (vtx->HiresPosition[1] * GPU::ScaleFactor) >> HD_SHIFT; } // zero-dot W check: @@ -1336,51 +1342,9 @@ void SubmitPolygon() if (vtx->FinalColor[2]) vtx->FinalColor[2] = ((vtx->FinalColor[2] << 4) + 0xF); } - // determine bounds of the polygon - // also determine the W shift and normalize W - // normalization works both ways - // (ie two W's that span 12 bits or less will be brought to 16 bits) - - u32 vtop = 0, vbot = 0; - s32 ytop = 192, ybot = 0; - s32 xtop = 256, xbot = 0; - u32 wsize = 0; - - for (int i = 0; i < nverts; i++) - { - Vertex* vtx = poly->Vertices[i]; - - if (vtx->FinalPosition[1] < ytop || (vtx->FinalPosition[1] == ytop && vtx->FinalPosition[0] < xtop)) - { - xtop = vtx->FinalPosition[0]; - ytop = vtx->FinalPosition[1]; - vtop = i; - } - if (vtx->FinalPosition[1] > ybot || (vtx->FinalPosition[1] == ybot && vtx->FinalPosition[0] > xbot)) - { - xbot = vtx->FinalPosition[0]; - ybot = vtx->FinalPosition[1]; - vbot = i; - } - - u32 w = (u32)vtx->Position[3]; - if (w == 0) poly->Degenerate = true; - - while ((w >> wsize) && (wsize < 32)) - wsize += 4; - } - - poly->VTop = vtop; poly->VBottom = vbot; - poly->YTop = ytop; poly->YBottom = ybot; - poly->XTop = xtop; poly->XBottom = xbot; - - if (ybot > 192) poly->Degenerate = true; - - poly->SortKey = (ybot << 8) | ytop; - if (poly->Translucent) poly->SortKey |= 0x10000; - poly->WBuffer = (FlushAttributes & 0x2); + u32 wsize = CalculatePolygonMetadata(poly); for (int i = 0; i < nverts; i++) { Vertex* vtx = poly->Vertices[i]; @@ -1423,6 +1387,53 @@ void SubmitPolygon() else LastStripPolygon = NULL; } +u32 CalculatePolygonMetadata(Polygon* poly) +{ + // determine bounds of the polygon + // also determine the W shift and normalize W + // normalization works both ways + // (ie two W's that span 12 bits or less will be brought to 16 bits) + + u32 vtop = 0, vbot = 0; + s32 ytop = 192 * GPU::ScaleFactor, ybot = 0; + s32 xtop = 256 * GPU::ScaleFactor, xbot = 0; + u32 wsize = 0; + + for (int i = 0; i < poly->NumVertices; i++) + { + Vertex* vtx = poly->Vertices[i]; + + if (vtx->FinalPosition[1] < ytop || (vtx->FinalPosition[1] == ytop && vtx->FinalPosition[0] < xtop)) + { + xtop = vtx->FinalPosition[0]; + ytop = vtx->FinalPosition[1]; + vtop = i; + } + if (vtx->FinalPosition[1] > ybot || (vtx->FinalPosition[1] == ybot && vtx->FinalPosition[0] > xbot)) + { + xbot = vtx->FinalPosition[0]; + ybot = vtx->FinalPosition[1]; + vbot = i; + } + + u32 w = (u32)vtx->Position[3]; + if (w == 0) poly->Degenerate = true; + + while ((w >> wsize) && (wsize < 32)) + wsize += 4; + } + + poly->VTop = vtop; poly->VBottom = vbot; + poly->YTop = ytop; poly->YBottom = ybot; + poly->XTop = xtop; poly->XBottom = xbot; + + if (ybot > 192 * GPU::ScaleFactor) poly->Degenerate = true; + + poly->SortKey = (ybot << (8 + HD_SHIFT)) | ytop; + if (poly->Translucent) poly->SortKey |= 0x10000 << (HD_SHIFT * 2); + + return wsize; +} void SubmitVertex() { @@ -2615,7 +2626,7 @@ void SetRenderXPos(u16 xpos) RenderXPos = xpos & 0x01FF; } -u32 ScrolledLine[256]; +std::vector<u32> ScrolledLine; u32* GetLine(int line) { @@ -2626,30 +2637,42 @@ u32* GetLine(int line) if (RenderXPos == 0) return rawline; // apply X scroll + int scale = GPU3D::CurrentRenderer->Accelerated ? 1 : GPU::ScaleFactor; + int pixelCount = GPU3D::CurrentRenderer->GetStride() * scale; + if (ScrolledLine.size() != pixelCount) + ScrolledLine.resize(pixelCount); + u32* dst = ScrolledLine.data(); if (RenderXPos & 0x100) { - int i = 0, j = RenderXPos; - for (; j < 512; i++, j++) - ScrolledLine[i] = 0; - for (j = 0; i < 256; i++, j++) - ScrolledLine[i] = rawline[j]; + // IDK why this isn't working + for (int y = 0; y < scale; y++) + { + int blank = (NATIVE_WIDTH*2 - RenderXPos) * scale; + memset(dst, 0, blank * sizeof(u32)); + memcpy(dst+blank, rawline, (NATIVE_WIDTH * scale - blank) * sizeof(u32)); + dst += GPU3D::CurrentRenderer->GetStride(); + rawline += GPU3D::CurrentRenderer->GetStride(); + } } else { - int i = 0, j = RenderXPos; - for (; j < 256; i++, j++) - ScrolledLine[i] = rawline[j]; - for (; i < 256; i++) - ScrolledLine[i] = 0; + for (int y = 0; y < scale; y++) + { + int nonBlank = (NATIVE_WIDTH - RenderXPos) * scale; + memcpy(dst, rawline + (RenderXPos * scale), nonBlank * sizeof(u32)); + memset(dst+nonBlank, 0, (NATIVE_WIDTH * scale - nonBlank) * sizeof(u32)); + dst += GPU3D::CurrentRenderer->GetStride(); + rawline += GPU3D::CurrentRenderer->GetStride(); + } } } else { - memset(ScrolledLine, 0, 256*4); + memset(ScrolledLine, 0, sizeof(ScrolledLine)); } - return ScrolledLine; + return ScrolledLine.data(); } diff --git a/src/GPU3D.h b/src/GPU3D.h index 4a7bfdc..5aacfb0 100644 --- a/src/GPU3D.h +++ b/src/GPU3D.h @@ -25,6 +25,10 @@ #include "GPU.h" #include "Savestate.h" +// should be able to be as high as 7 +// limiting factor: SortKey must contain ytop and ybottom and translucent +#define HD_SHIFT 7 + namespace GPU3D { @@ -159,6 +163,7 @@ public: virtual void RenderFrame() = 0; virtual void RestartFrame() {}; virtual u32* GetLine(int line) = 0; + virtual u32 GetStride() { return NATIVE_WIDTH; } }; extern int Renderer; diff --git a/src/GPU3D_OpenGL.cpp b/src/GPU3D_OpenGL.cpp index ebabd51..006b2d4 100644 --- a/src/GPU3D_OpenGL.cpp +++ b/src/GPU3D_OpenGL.cpp @@ -255,9 +255,9 @@ bool GLRenderer::Init() SetupDefaultTexParams(FramebufferTex[5]); SetupDefaultTexParams(FramebufferTex[7]); - // downscale framebuffer for display capture (always 256x192) + // downscale framebuffer for display capture (always native) SetupDefaultTexParams(FramebufferTex[3]); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 256, 192, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, NATIVE_WIDTH, NATIVE_HEIGHT, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); glEnable(GL_BLEND); glBlendEquationSeparate(GL_FUNC_ADD, GL_MAX); @@ -315,13 +315,12 @@ void GLRenderer::Reset() void GLRenderer::SetRenderSettings(GPU::RenderSettings& settings) { - int scale = settings.GL_ScaleFactor; + int scale = settings.ScaleFactor; - ScaleFactor = scale; BetterPolygons = settings.GL_BetterPolygons; - ScreenW = 256 * scale; - ScreenH = 192 * scale; + ScreenW = NATIVE_WIDTH * scale; + ScreenH = NATIVE_HEIGHT * scale; glBindTexture(GL_TEXTURE_2D, FramebufferTex[0]); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, ScreenW, ScreenH, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); @@ -358,7 +357,7 @@ void GLRenderer::SetRenderSettings(GPU::RenderSettings& settings) glBindFramebuffer(GL_FRAMEBUFFER, FramebufferID[0]); glBindBuffer(GL_PIXEL_PACK_BUFFER, PixelbufferID); - glBufferData(GL_PIXEL_PACK_BUFFER, 256*192*4, NULL, GL_DYNAMIC_READ); + glBufferData(GL_PIXEL_PACK_BUFFER, NATIVE_WIDTH*NATIVE_HEIGHT*4, NULL, GL_DYNAMIC_READ); glBindFramebuffer(GL_FRAMEBUFFER, 0); @@ -425,10 +424,10 @@ u32* GLRenderer::SetupVertex(Polygon* poly, int vid, Vertex* vtx, u32 vtxattr, u while (z > 0xFFFF) { z >>= 1; zshift++; } u32 x, y; - if (ScaleFactor > 1) + if (GPU::ScaleFactor > 1) { - x = (vtx->HiresPosition[0] * ScaleFactor) >> 4; - y = (vtx->HiresPosition[1] * ScaleFactor) >> 4; + x = vtx->FinalPosition[0]; + y = vtx->FinalPosition[1]; } else { @@ -450,10 +449,7 @@ u32* GLRenderer::SetupVertex(Polygon* poly, int vid, Vertex* vtx, u32 vtxattr, u if ((vtop->FinalPosition[1] < vtx->FinalPosition[1]) && (vtx->FinalPosition[0] == vtop->FinalPosition[0]-1)) { - if (ScaleFactor > 1) - x = (vtop->HiresPosition[0] * ScaleFactor) >> 4; - else - x = vtop->FinalPosition[0]; + x = vtop->FinalPosition[0]; } }*/ @@ -591,8 +587,8 @@ void GLRenderer::BuildPolygons(GLRenderer::RendererPolygon* polygons, int npolys { Vertex* vtx = poly->Vertices[j]; - cX += vtx->HiresPosition[0]; - cY += vtx->HiresPosition[1]; + cX += vtx->FinalPosition[0]; + cY += vtx->FinalPosition[1]; float fw = (float)poly->FinalW[j] * poly->NumVertices; cW += 1.0f / fw; @@ -623,9 +619,6 @@ void GLRenderer::BuildPolygons(GLRenderer::RendererPolygon* polygons, int npolys cS *= cW; cT *= cW; - cX = (cX * ScaleFactor) >> 4; - cY = (cY * ScaleFactor) >> 4; - u32 w = (u32)cW; u32 z = (u32)cZ; @@ -752,7 +745,7 @@ void GLRenderer::RenderSceneChunk(int y, int h) u32 flags = 0; if (RenderPolygonRAM[0]->WBuffer) flags |= RenderFlag_WBuffer; - if (h != 192) glScissor(0, y<<ScaleFactor, 256<<ScaleFactor, h<<ScaleFactor); + if (h != NATIVE_HEIGHT) glScissor(0, y * GPU::ScaleFactor, NATIVE_WIDTH * GPU::ScaleFactor, h * GPU::ScaleFactor); GLboolean fogenable = (RenderDispCnt & (1<<7)) ? GL_TRUE : GL_FALSE; @@ -1280,7 +1273,7 @@ void GLRenderer::RenderFrame() glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, NumIndices * 2, IndexBuffer); glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, EdgeIndicesOffset * 2, NumEdgeIndices * 2, IndexBuffer + EdgeIndicesOffset); - RenderSceneChunk(0, 192); + RenderSceneChunk(0, NATIVE_HEIGHT); } FrontBuffer = FrontBuffer ? 0 : 1; @@ -1295,20 +1288,20 @@ void GLRenderer::PrepareCaptureFrame() glReadBuffer(GL_COLOR_ATTACHMENT0); glBindFramebuffer(GL_DRAW_FRAMEBUFFER, FramebufferID[3]); glDrawBuffer(GL_COLOR_ATTACHMENT0); - glBlitFramebuffer(0, 0, ScreenW, ScreenH, 0, 0, 256, 192, GL_COLOR_BUFFER_BIT, GL_NEAREST); + glBlitFramebuffer(0, 0, ScreenW, ScreenH, 0, 0, NATIVE_WIDTH, NATIVE_HEIGHT, GL_COLOR_BUFFER_BIT, GL_NEAREST); glBindFramebuffer(GL_READ_FRAMEBUFFER, FramebufferID[3]); - glReadPixels(0, 0, 256, 192, GL_BGRA, GL_UNSIGNED_BYTE, NULL); + glReadPixels(0, 0, NATIVE_WIDTH, NATIVE_HEIGHT, GL_BGRA, GL_UNSIGNED_BYTE, NULL); } u32* GLRenderer::GetLine(int line) { - int stride = 256; + int stride = NATIVE_WIDTH; if (line == 0) { u8* data = (u8*)glMapBuffer(GL_PIXEL_PACK_BUFFER, GL_READ_ONLY); - if (data) memcpy(&Framebuffer[stride*0], data, 4*stride*192); + if (data) memcpy(&Framebuffer[stride*0], data, 4*stride*NATIVE_HEIGHT); glUnmapBuffer(GL_PIXEL_PACK_BUFFER); } diff --git a/src/GPU3D_OpenGL.h b/src/GPU3D_OpenGL.h index a9dd62c..b4e493b 100644 --- a/src/GPU3D_OpenGL.h +++ b/src/GPU3D_OpenGL.h @@ -145,7 +145,7 @@ private: GLuint FramebufferTex[8]; int FrontBuffer; GLuint FramebufferID[4], PixelbufferID; - u32 Framebuffer[256*192]; + u32 Framebuffer[NATIVE_WIDTH*NATIVE_HEIGHT]; }; diff --git a/src/GPU3D_Soft.cpp b/src/GPU3D_Soft.cpp index 98514ab..afe686f 100644 --- a/src/GPU3D_Soft.cpp +++ b/src/GPU3D_Soft.cpp @@ -77,11 +77,17 @@ SoftRenderer::SoftRenderer() } +SoftRenderer::~SoftRenderer() +{ + DeInit(); +} + bool SoftRenderer::Init() { Sema_RenderStart = Platform::Semaphore_Create(); Sema_RenderDone = Platform::Semaphore_Create(); Sema_ScanlineCount = Platform::Semaphore_Create(); + Mutex_Buffer = Platform::Mutex_Create(); Threaded = false; RenderThreadRunning = false; @@ -94,9 +100,25 @@ void SoftRenderer::DeInit() { StopRenderThread(); - Platform::Semaphore_Free(Sema_RenderStart); - Platform::Semaphore_Free(Sema_RenderDone); - Platform::Semaphore_Free(Sema_ScanlineCount); + if (Sema_RenderStart) Platform::Semaphore_Free(Sema_RenderStart); + if (Sema_RenderDone) Platform::Semaphore_Free(Sema_RenderDone); + if (Sema_ScanlineCount) Platform::Semaphore_Free(Sema_ScanlineCount); + if (Mutex_Buffer) Platform::Mutex_Free(Mutex_Buffer); + + Sema_RenderStart = NULL; + Sema_RenderDone = NULL; + Sema_ScanlineCount = NULL; + Mutex_Buffer = NULL; + + if (ColorBuffer) delete[] ColorBuffer; + if (DepthBuffer) delete[] DepthBuffer; + if (AttrBuffer) delete[] AttrBuffer; + if (StencilBuffer) delete[] StencilBuffer; + + ColorBuffer = NULL; + DepthBuffer = NULL; + AttrBuffer = NULL; + StencilBuffer = NULL; } void SoftRenderer::Reset() @@ -112,7 +134,30 @@ void SoftRenderer::Reset() void SoftRenderer::SetRenderSettings(GPU::RenderSettings& settings) { + Platform::Mutex_Lock(Mutex_Buffer); + Threaded = settings.Soft_Threaded; + + int scale = settings.ScaleFactor; + RenderWidth = NATIVE_WIDTH * scale; + RenderHeight = NATIVE_HEIGHT * scale; + + ScanlineWidth = RenderWidth + 2; + NumScanlines = RenderHeight + 2; + BufferSize = ScanlineWidth * NumScanlines; + FirstPixelOffset = ScanlineWidth + 1; + + if (ColorBuffer) delete[] ColorBuffer; + if (DepthBuffer) delete[] DepthBuffer; + if (AttrBuffer) delete[] AttrBuffer; + ColorBuffer = new u32[BufferSize * 2]; + DepthBuffer = new u32[BufferSize * 2]; + AttrBuffer = new u32[BufferSize * 2]; + + if (StencilBuffer) delete[] StencilBuffer; + StencilBuffer = new u8[NATIVE_WIDTH * scale * 2]; + + Platform::Mutex_Unlock(Mutex_Buffer); SetupRenderThread(); } @@ -695,7 +740,7 @@ void SoftRenderer::RenderShadowMaskScanline(RendererPolygon* rp, s32 y) fnDepthTest = DepthTest_LessThan; if (!PrevIsShadowMask) - memset(&StencilBuffer[256 * (y&0x1)], 0, 256); + memset(&StencilBuffer[RenderWidth * (y&0x1)], 0, RenderWidth); PrevIsShadowMask = true; @@ -824,7 +869,7 @@ void SoftRenderer::RenderShadowMaskScanline(RendererPolygon* rp, s32 y) edge = yedge | 0x1; xlimit = xstart+l_edgelen; if (xlimit > xend+1) xlimit = xend+1; - if (xlimit > 256) xlimit = 256; + if (xlimit > RenderWidth) xlimit = RenderWidth; if (!l_filledge) x = xlimit; else @@ -838,13 +883,13 @@ void SoftRenderer::RenderShadowMaskScanline(RendererPolygon* rp, s32 y) u32 dstattr = AttrBuffer[pixeladdr]; if (!fnDepthTest(DepthBuffer[pixeladdr], z, dstattr)) - StencilBuffer[256*(y&0x1) + x] = 1; + StencilBuffer[RenderWidth*(y&0x1) + x] = 1; if (dstattr & 0xF) { pixeladdr += BufferSize; if (!fnDepthTest(DepthBuffer[pixeladdr], z, AttrBuffer[pixeladdr])) - StencilBuffer[256*(y&0x1) + x] |= 0x2; + StencilBuffer[RenderWidth*(y&0x1) + x] |= 0x2; } } @@ -852,7 +897,7 @@ void SoftRenderer::RenderShadowMaskScanline(RendererPolygon* rp, s32 y) edge = yedge; xlimit = xend-r_edgelen+1; if (xlimit > xend+1) xlimit = xend+1; - if (xlimit > 256) xlimit = 256; + if (xlimit > RenderWidth) xlimit = RenderWidth; if (wireframe && !edge) x = std::max(x, xlimit); else for (; x < xlimit; x++) { @@ -864,20 +909,20 @@ void SoftRenderer::RenderShadowMaskScanline(RendererPolygon* rp, s32 y) u32 dstattr = AttrBuffer[pixeladdr]; if (!fnDepthTest(DepthBuffer[pixeladdr], z, dstattr)) - StencilBuffer[256*(y&0x1) + x] = 1; + StencilBuffer[RenderWidth*(y&0x1) + x] = 1; if (dstattr & 0xF) { pixeladdr += BufferSize; if (!fnDepthTest(DepthBuffer[pixeladdr], z, AttrBuffer[pixeladdr])) - StencilBuffer[256*(y&0x1) + x] |= 0x2; + StencilBuffer[RenderWidth*(y&0x1) + x] |= 0x2; } } // part 3: right edge edge = yedge | 0x2; xlimit = xend+1; - if (xlimit > 256) xlimit = 256; + if (xlimit > RenderWidth) xlimit = RenderWidth; if (r_filledge) for (; x < xlimit; x++) @@ -890,13 +935,13 @@ void SoftRenderer::RenderShadowMaskScanline(RendererPolygon* rp, s32 y) u32 dstattr = AttrBuffer[pixeladdr]; if (!fnDepthTest(DepthBuffer[pixeladdr], z, dstattr)) - StencilBuffer[256*(y&0x1) + x] = 1; + StencilBuffer[RenderWidth*(y&0x1) + x] = 1; if (dstattr & 0xF) { pixeladdr += BufferSize; if (!fnDepthTest(DepthBuffer[pixeladdr], z, AttrBuffer[pixeladdr])) - StencilBuffer[256*(y&0x1) + x] |= 0x2; + StencilBuffer[RenderWidth*(y&0x1) + x] |= 0x2; } } @@ -1071,7 +1116,7 @@ void SoftRenderer::RenderPolygonScanline(RendererPolygon* rp, s32 y) edge = yedge | 0x1; xlimit = xstart+l_edgelen; if (xlimit > xend+1) xlimit = xend+1; - if (xlimit > 256) xlimit = 256; + if (xlimit > RenderWidth) xlimit = RenderWidth; if (l_edgecov & (1<<31)) { xcov = (l_edgecov >> 12) & 0x3FF; @@ -1088,7 +1133,7 @@ void SoftRenderer::RenderPolygonScanline(RendererPolygon* rp, s32 y) // check stencil buffer for shadows if (polygon->IsShadow) { - u8 stencil = StencilBuffer[256*(y&0x1) + x]; + u8 stencil = StencilBuffer[RenderWidth*(y&0x1) + x]; if (!stencil) continue; if (!(stencil & 0x1)) @@ -1172,7 +1217,7 @@ void SoftRenderer::RenderPolygonScanline(RendererPolygon* rp, s32 y) edge = yedge; xlimit = xend-r_edgelen+1; if (xlimit > xend+1) xlimit = xend+1; - if (xlimit > 256) xlimit = 256; + if (xlimit > RenderWidth) xlimit = RenderWidth; if (wireframe && !edge) x = std::max(x, xlimit); else @@ -1184,7 +1229,7 @@ void SoftRenderer::RenderPolygonScanline(RendererPolygon* rp, s32 y) // check stencil buffer for shadows if (polygon->IsShadow) { - u8 stencil = StencilBuffer[256*(y&0x1) + x]; + u8 stencil = StencilBuffer[RenderWidth*(y&0x1) + x]; if (!stencil) continue; if (!(stencil & 0x1)) @@ -1260,7 +1305,7 @@ void SoftRenderer::RenderPolygonScanline(RendererPolygon* rp, s32 y) // part 3: right edge edge = yedge | 0x2; xlimit = xend+1; - if (xlimit > 256) xlimit = 256; + if (xlimit > RenderWidth) xlimit = RenderWidth; if (r_edgecov & (1<<31)) { xcov = (r_edgecov >> 12) & 0x3FF; @@ -1276,7 +1321,7 @@ void SoftRenderer::RenderPolygonScanline(RendererPolygon* rp, s32 y) // check stencil buffer for shadows if (polygon->IsShadow) { - u8 stencil = StencilBuffer[256*(y&0x1) + x]; + u8 stencil = StencilBuffer[RenderWidth*(y&0x1) + x]; if (!stencil) continue; if (!(stencil & 0x1)) @@ -1427,7 +1472,7 @@ void SoftRenderer::ScanlineFinalPass(s32 y) // edge marking // only applied to topmost pixels - for (int x = 0; x < 256; x++) + for (int x = 0; x < RenderWidth; x++) { u32 pixeladdr = FirstPixelOffset + (y*ScanlineWidth) + x; @@ -1475,7 +1520,7 @@ void SoftRenderer::ScanlineFinalPass(s32 y) u32 fogB = (RenderFogColor >> 9) & 0x3E; if (fogB) fogB++; u32 fogA = (RenderFogColor >> 16) & 0x1F; - for (int x = 0; x < 256; x++) + for (int x = 0; x < RenderWidth; x++) { u32 pixeladdr = FirstPixelOffset + (y*ScanlineWidth) + x; u32 density, srccolor, srcR, srcG, srcB, srcA; @@ -1540,7 +1585,7 @@ void SoftRenderer::ScanlineFinalPass(s32 y) // edges were flagged and their coverages calculated during rendering // this is where such edge pixels are blended with the pixels underneath - for (int x = 0; x < 256; x++) + for (int x = 0; x < RenderWidth; x++) { u32 pixeladdr = FirstPixelOffset + (y*ScanlineWidth) + x; @@ -1624,9 +1669,9 @@ void SoftRenderer::ClearBuffers() u8 xoff = (RenderClearAttr2 >> 16) & 0xFF; u8 yoff = (RenderClearAttr2 >> 24) & 0xFF; - for (int y = 0; y < ScanlineWidth*192; y+=ScanlineWidth) + for (int y = 0; y < ScanlineWidth * RenderHeight; y+=ScanlineWidth) { - for (int x = 0; x < 256; x++) + for (int x = 0; x < RenderWidth; x++) { u16 val2 = ReadVRAM_Texture<u16>(0x40000 + (yoff << 9) + (xoff << 1)); u16 val3 = ReadVRAM_Texture<u16>(0x60000 + (yoff << 9) + (xoff << 1)); @@ -1645,10 +1690,12 @@ void SoftRenderer::ClearBuffers() DepthBuffer[pixeladdr] = z; AttrBuffer[pixeladdr] = polyid | (val3 & 0x8000); - xoff++; + if (x % GPU::ScaleFactor == 0) + xoff++; } - yoff++; + if (y % GPU::ScaleFactor == 0) + yoff++; } } else @@ -1662,9 +1709,9 @@ void SoftRenderer::ClearBuffers() polyid |= (RenderClearAttr1 & 0x8000); - for (int y = 0; y < ScanlineWidth*192; y+=ScanlineWidth) + for (int y = 0; y < ScanlineWidth * RenderHeight; y+=ScanlineWidth) { - for (int x = 0; x < 256; x++) + for (int x = 0; x < RenderWidth; x++) { u32 pixeladdr = FirstPixelOffset + y + x; ColorBuffer[pixeladdr] = color; @@ -1686,16 +1733,16 @@ void SoftRenderer::RenderPolygons(bool threaded, Polygon** polygons, int npolys) RenderScanline(0, j); - for (s32 y = 1; y < 192; y++) + for (s32 y = 1; y < RenderHeight; y++) { RenderScanline(y, j); ScanlineFinalPass(y-1); - if (threaded) + if (threaded && (y % GPU::ScaleFactor == 0)) Platform::Semaphore_Post(Sema_ScanlineCount); } - ScanlineFinalPass(191); + ScanlineFinalPass(RenderHeight - 1); if (threaded) Platform::Semaphore_Post(Sema_ScanlineCount); @@ -1723,8 +1770,11 @@ void SoftRenderer::RenderFrame() } else if (!FrameIdentical) { + // It is possible that the UI will try to update settings mid-render. + Platform::Mutex_Lock(Mutex_Buffer); ClearBuffers(); RenderPolygons(false, &RenderPolygonRAM[0], RenderNumPolygons); + Platform::Mutex_Unlock(Mutex_Buffer); } } @@ -1740,16 +1790,18 @@ void SoftRenderer::RenderThreadFunc() Platform::Semaphore_Wait(Sema_RenderStart); if (!RenderThreadRunning) return; + Platform::Mutex_Lock(Mutex_Buffer); RenderThreadRendering = true; if (FrameIdentical) { - Platform::Semaphore_Post(Sema_ScanlineCount, 192); + Platform::Semaphore_Post(Sema_ScanlineCount, NATIVE_HEIGHT); } else { ClearBuffers(); RenderPolygons(true, &RenderPolygonRAM[0], RenderNumPolygons); } + Platform::Mutex_Unlock(Mutex_Buffer); Platform::Semaphore_Post(Sema_RenderDone); RenderThreadRendering = false; @@ -1759,12 +1811,14 @@ void SoftRenderer::RenderThreadFunc() u32* SoftRenderer::GetLine(int line) { if (RenderThreadRunning.load(std::memory_order_relaxed)) - { - if (line < 192) - Platform::Semaphore_Wait(Sema_ScanlineCount); - } + Platform::Semaphore_Wait(Sema_ScanlineCount); return &ColorBuffer[(line * ScanlineWidth) + FirstPixelOffset]; } +u32 SoftRenderer::GetStride() +{ + return ScanlineWidth; +} + } diff --git a/src/GPU3D_Soft.h b/src/GPU3D_Soft.h index 0c6ca43..6c9062a 100644 --- a/src/GPU3D_Soft.h +++ b/src/GPU3D_Soft.h @@ -29,7 +29,7 @@ class SoftRenderer : public Renderer3D { public: SoftRenderer(); - virtual ~SoftRenderer() override {}; + virtual ~SoftRenderer() override; virtual bool Init() override; virtual void DeInit() override; virtual void Reset() override; @@ -40,6 +40,7 @@ public: virtual void RenderFrame() override; virtual void RestartFrame() override; virtual u32* GetLine(int line) override; + virtual u32 GetStride() override; void SetupRenderThread(); void StopRenderThread(); @@ -474,14 +475,17 @@ private: // TODO: check if the hardware can accidentally plot pixels // offscreen in that border - static constexpr int ScanlineWidth = 258; - static constexpr int NumScanlines = 194; - static constexpr int BufferSize = ScanlineWidth * NumScanlines; - static constexpr int FirstPixelOffset = ScanlineWidth + 1; + int ScanlineWidth = NATIVE_WIDTH + 2; + int NumScanlines = NATIVE_HEIGHT + 2; + int BufferSize = ScanlineWidth * NumScanlines; + int FirstPixelOffset = ScanlineWidth + 1; - u32 ColorBuffer[BufferSize * 2]; - u32 DepthBuffer[BufferSize * 2]; - u32 AttrBuffer[BufferSize * 2]; + int RenderWidth = NATIVE_WIDTH; + int RenderHeight = NATIVE_HEIGHT; + + u32* ColorBuffer; + u32* DepthBuffer; + u32* AttrBuffer; // attribute buffer: // bit0-3: edge flags (left/right/top/bottom) @@ -492,7 +496,7 @@ private: // bit22: translucent flag // bit24-29: polygon ID for opaque pixels - u8 StencilBuffer[256*2]; + u8* StencilBuffer; bool PrevIsShadowMask; bool Enabled; @@ -508,5 +512,6 @@ private: Platform::Semaphore* Sema_RenderStart; Platform::Semaphore* Sema_RenderDone; Platform::Semaphore* Sema_ScanlineCount; + Platform::Mutex* Mutex_Buffer; }; } \ No newline at end of file diff --git a/src/GPU_OpenGL.cpp b/src/GPU_OpenGL.cpp index 837d224..6f98721 100644 --- a/src/GPU_OpenGL.cpp +++ b/src/GPU_OpenGL.cpp @@ -143,7 +143,7 @@ void GLCompositor::Reset() void GLCompositor::SetRenderSettings(RenderSettings& settings) { - int scale = settings.GL_ScaleFactor; + int scale = settings.ScaleFactor; Scale = scale; ScreenW = 256 * scale; diff --git a/src/Savestate.h b/src/Savestate.h index 0aef517..03c9d88 100644 --- a/src/Savestate.h +++ b/src/Savestate.h @@ -25,7 +25,7 @@ #include "types.h" #define SAVESTATE_MAJOR 10 -#define SAVESTATE_MINOR 0 +#define SAVESTATE_MINOR 3 class Savestate { diff --git a/src/frontend/FrontendUtil.h b/src/frontend/FrontendUtil.h index 51f8f61..5665497 100644 --- a/src/frontend/FrontendUtil.h +++ b/src/frontend/FrontendUtil.h @@ -117,3 +117,4 @@ void Mic_SetExternalBuffer(s16* buffer, u32 len); } #endif // FRONTENDUTIL_H + int scaleFactor, diff --git a/src/frontend/Util_Video.cpp b/src/frontend/Util_Video.cpp index e4c49e9..b99489f 100644 --- a/src/frontend/Util_Video.cpp +++ b/src/frontend/Util_Video.cpp @@ -126,6 +126,7 @@ void SetupScreenLayout(int screenWidth, int screenHeight, ScreenLayout screenLayout, ScreenRotation rotation, ScreenSizing sizing, + int scaleFactor, int screenGap, bool integerScale, bool swapScreens, @@ -141,12 +142,15 @@ void SetupScreenLayout(int screenWidth, int screenHeight, topAspect = botAspect = 1; HybPrevTouchScreen = 0; } + + int width = 256 * scaleFactor; + int height = 192 * scaleFactor; float refpoints[6][2] = { - {0, 0}, {256, 192}, - {0, 0}, {256, 192}, - {0, 0}, {256, 192} + {0, 0}, {width, height}, + {0, 0}, {width, height}, + {0, 0}, {width, height} }; int layout = screenLayout == screenLayout_Natural @@ -162,8 +166,8 @@ void SetupScreenLayout(int screenWidth, int screenHeight, M23_Identity(BotScreenMtx); M23_Identity(HybScreenMtx); - M23_Translate(TopScreenMtx, -256/2, -192/2); - M23_Translate(BotScreenMtx, -256/2, -192/2); + M23_Translate(TopScreenMtx, -width/2, -height/2); + M23_Translate(BotScreenMtx, -width/2, -height/2); M23_Scale(TopScreenMtx, topAspect, 1); M23_Scale(BotScreenMtx, botAspect, 1); @@ -223,8 +227,8 @@ void SetupScreenLayout(int screenWidth, int screenHeight, bool moveV = rotation % 2 == layout; - float offsetBot = (moveV ? 192.0 : 256.0 * botAspect) / 2.0 + screenGap / 2.0; - float offsetTop = -((moveV ? 192.0 : 256.0 * topAspect) / 2.0 + screenGap / 2.0); + float offsetBot = (moveV ? height : width * botAspect) / 2.0 + screenGap / 2.0; + float offsetTop = -((moveV ? height : width * topAspect) / 2.0 + screenGap / 2.0); if ((rotation == 1 || rotation == 2) ^ swapScreens) { @@ -435,7 +439,10 @@ void SetupScreenLayout(int screenWidth, int screenHeight, M23_Multiply(TouchMtx, rotmtx, TouchMtx); M23_Scale(TouchMtx, 1.f/botAspect, 1); - M23_Translate(TouchMtx, 256/2, 192/2); + M23_Translate(TouchMtx, width/2, height/2); + + // it should also undo the scaleFactor + M23_Scale(TouchMtx, 1.f / scaleFactor); if (HybEnable && HybScreen == 1) { @@ -445,6 +452,8 @@ void SetupScreenLayout(int screenWidth, int screenHeight, M23_Scale(HybTouchMtx, 1.f/hybScale); M23_Multiply(HybTouchMtx, rotmtx, HybTouchMtx); } + + M23_Scale(HybTouchMtx, 1.f / scaleFactor); } } diff --git a/src/frontend/qt_sdl/VideoSettingsDialog.cpp b/src/frontend/qt_sdl/VideoSettingsDialog.cpp index 95ec7d3..b8ad4f5 100644 --- a/src/frontend/qt_sdl/VideoSettingsDialog.cpp +++ b/src/frontend/qt_sdl/VideoSettingsDialog.cpp @@ -46,7 +46,7 @@ VideoSettingsDialog::VideoSettingsDialog(QWidget* parent) : QDialog(parent), ui( oldVSync = Config::ScreenVSync; oldVSyncInterval = Config::ScreenVSyncInterval; oldSoftThreaded = Config::Threaded3D; - oldGLScale = Config::GL_ScaleFactor; + oldGLScale = Config::ScaleFactor; oldGLBetterPolygons = Config::GL_BetterPolygons; grp3DRenderer = new QButtonGroup(this); @@ -71,8 +71,8 @@ VideoSettingsDialog::VideoSettingsDialog(QWidget* parent) : QDialog(parent), ui( ui->cbSoftwareThreaded->setChecked(Config::Threaded3D != 0); for (int i = 1; i <= 16; i++) - ui->cbxGLResolution->addItem(QString("%1x native (%2x%3)").arg(i).arg(256*i).arg(192*i)); - ui->cbxGLResolution->setCurrentIndex(Config::GL_ScaleFactor-1); + ui->cbxResolution->addItem(QString("%1x native (%2x%3)").arg(i).arg(256*i).arg(192*i)); + ui->cbxResolution->setCurrentIndex(Config::ScaleFactor-1); ui->cbBetterPolygons->setChecked(Config::GL_BetterPolygons != 0); @@ -84,14 +84,12 @@ VideoSettingsDialog::VideoSettingsDialog(QWidget* parent) : QDialog(parent), ui( { ui->cbGLDisplay->setEnabled(true); ui->cbSoftwareThreaded->setEnabled(true); - ui->cbxGLResolution->setEnabled(false); ui->cbBetterPolygons->setEnabled(false); } else { ui->cbGLDisplay->setEnabled(false); ui->cbSoftwareThreaded->setEnabled(false); - ui->cbxGLResolution->setEnabled(true); ui->cbBetterPolygons->setEnabled(true); } } @@ -117,10 +115,10 @@ void VideoSettingsDialog::on_VideoSettingsDialog_rejected() Config::ScreenVSync = oldVSync; Config::ScreenVSyncInterval = oldVSyncInterval; Config::Threaded3D = oldSoftThreaded; - Config::GL_ScaleFactor = oldGLScale; + Config::ScaleFactor = oldGLScale; Config::GL_BetterPolygons = oldGLBetterPolygons; - emit updateVideoSettings(old_gl != UsesGL()); + emit updateVideoSettings(old_gl != UsesGL || old_scale != Config::ScaleFactor); closeDlg(); } @@ -134,6 +132,7 @@ void VideoSettingsDialog::setVsyncControlEnable(bool hasOGL) void VideoSettingsDialog::onChange3DRenderer(int renderer) { bool old_gl = (Config::ScreenUseGL != 0) || (Config::_3DRenderer != 0); + int old_scale = Config::ScaleFactor; Config::_3DRenderer = renderer; @@ -141,14 +140,12 @@ void VideoSettingsDialog::onChange3DRenderer(int renderer) { ui->cbGLDisplay->setEnabled(true); ui->cbSoftwareThreaded->setEnabled(true); - ui->cbxGLResolution->setEnabled(false); ui->cbBetterPolygons->setEnabled(false); } else { ui->cbGLDisplay->setEnabled(false); ui->cbSoftwareThreaded->setEnabled(false); - ui->cbxGLResolution->setEnabled(true); ui->cbBetterPolygons->setEnabled(true); } @@ -187,12 +184,12 @@ void VideoSettingsDialog::on_cbSoftwareThreaded_stateChanged(int state) emit updateVideoSettings(false); } -void VideoSettingsDialog::on_cbxGLResolution_currentIndexChanged(int idx) +void VideoSettingsDialog::on_cbxResolution_currentIndexChanged(int idx) { // prevent a spurious change - if (ui->cbxGLResolution->count() < 16) return; + if (ui->cbxResolution->count() < 16) return; - Config::GL_ScaleFactor = idx+1; + Config::ScaleFactor = idx+1; setVsyncControlEnable(UsesGL()); @@ -203,5 +200,5 @@ void VideoSettingsDialog::on_cbBetterPolygons_stateChanged(int state) { Config::GL_BetterPolygons = (state != 0); - emit updateVideoSettings(false); + emit updateVideoSettings(true); } diff --git a/src/frontend/qt_sdl/VideoSettingsDialog.h b/src/frontend/qt_sdl/VideoSettingsDialog.h index 7fee5bb..16ca438 100644 --- a/src/frontend/qt_sdl/VideoSettingsDialog.h +++ b/src/frontend/qt_sdl/VideoSettingsDialog.h @@ -63,7 +63,7 @@ private slots: void on_cbVSync_stateChanged(int state); void on_sbVSyncInterval_valueChanged(int val); - void on_cbxGLResolution_currentIndexChanged(int idx); + void on_cbxResolution_currentIndexChanged(int idx); void on_cbBetterPolygons_stateChanged(int state); void on_cbSoftwareThreaded_stateChanged(int state); diff --git a/src/frontend/qt_sdl/VideoSettingsDialog.ui b/src/frontend/qt_sdl/VideoSettingsDialog.ui index 11cfe3d..ad086bd 100644 --- a/src/frontend/qt_sdl/VideoSettingsDialog.ui +++ b/src/frontend/qt_sdl/VideoSettingsDialog.ui @@ -33,20 +33,6 @@ </property> <layout class="QGridLayout" name="gridLayout_4"> <item row="0" column="0"> - <widget class="QLabel" name="label_3"> - <property name="text"> - <string>Internal resolution:</string> - </property> - </widget> - </item> - <item row="1" column="0"> - <widget class="QComboBox" name="cbxGLResolution"> - <property name="whatsThis"> - <string><html><head/><body><p>The resolution at which the 3D graphics will be rendered. Higher resolutions improve graphics quality when the main window is enlarged, but may also cause glitches.</p></body></html></string> - </property> - </widget> - </item> - <item row="2" column="0"> <widget class="QCheckBox" name="cbBetterPolygons"> <property name="whatsThis"> <string><html><head/><body><p>Enabling this may help reduce distortion on quads and more complex polygons, but may also reduce performance.</p></body></html></string> @@ -94,6 +80,36 @@ <string>Display settings</string> </property> <layout class="QGridLayout" name="gridLayout_2"> + <item row="9" column="0"> + <widget class="QComboBox" name="cbxResolution"> + <property name="whatsThis"> + <string><html><head/><body><p>The resolution at which the 3D graphics will be rendered. Higher resolutions improve graphics quality when the main window is enlarged, but may also cause glitches.</p></body></html></string> + </property> + </widget> + </item> + <item row="8" column="0"> + <widget class="QLabel" name="label_3"> + <property name="text"> + <string>3D resolution:</string> + </property> + </widget> + </item> + <item row="7" column="0" colspan="2"> + <spacer name="verticalSpacer"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <property name="sizeType"> + <enum>QSizePolicy::Fixed</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>20</width> + <height>20</height> + </size> + </property> + </spacer> + </item> <item row="6" column="0"> <widget class="QLabel" name="label_2"> <property name="sizePolicy"> diff --git a/src/frontend/qt_sdl/main.cpp b/src/frontend/qt_sdl/main.cpp index 7f0c0ef..3bfcb80 100644 --- a/src/frontend/qt_sdl/main.cpp +++ b/src/frontend/qt_sdl/main.cpp @@ -151,6 +151,9 @@ const QStringList ArchiveExtensions #endif }; +int screenWidth; +int screenHeight; + bool RunningSomething; @@ -244,24 +247,26 @@ void EmuThread::initOpenGL() // to prevent bleeding between both parts of the screen // with bilinear filtering enabled - const int paddedHeight = 192*2+2; + const int paddedHeight = screenHeight*2+2; const float padPixels = 1.f / paddedHeight; - const float vertices[] = - { - 0.f, 0.f, 0.f, 0.f, - 0.f, 192.f, 0.f, 0.5f - padPixels, - 256.f, 192.f, 1.f, 0.5f - padPixels, - 0.f, 0.f, 0.f, 0.f, - 256.f, 192.f, 1.f, 0.5f - padPixels, - 256.f, 0.f, 1.f, 0.f, - - 0.f, 0.f, 0.f, 0.5f + padPixels, - 0.f, 192.f, 0.f, 1.f, - 256.f, 192.f, 1.f, 1.f, - 0.f, 0.f, 0.f, 0.5f + padPixels, - 256.f, 192.f, 1.f, 1.f, - 256.f, 0.f, 1.f, 0.5f + padPixels + float w = screenWidth; + float h = screenHeight; + float vertices[] = + { + 0.f, 0.f, 0.f, 0.f, + 0.f, h , 0.f, 0.5f - padPixels, + w , h , 1.f, 0.5f - padPixels, + 0.f, 0.f, 0.f, 0.f, + w , h , 1.f, 0.5f - padPixels, + w , 0.f, 1.f, 0.f, + + 0.f, 0.f, 0.f, 0.5f + padPixels, + 0.f, h , 0.f, 1.f, + w , h , 1.f, 1.f, + 0.f, 0.f, 0.f, 0.5f + padPixels, + w , h , 1.f, 1.f, + w , 0.f, 1.f, 0.5f + padPixels }; glGenBuffers(1, &screenVertexBuffer); @@ -282,11 +287,12 @@ void EmuThread::initOpenGL() glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 256, paddedHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, screenWidth, paddedHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); // fill the padding - u8 zeroData[256*4*4]; - memset(zeroData, 0, sizeof(zeroData)); - glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 192, 256, 2, GL_RGBA, GL_UNSIGNED_BYTE, zeroData); + u8 zeroData[screenWidth*4*4]; + memset(zeroData, 0, screenWidth*4*4); + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, screenHeight, screenWidth, 2, GL_RGBA, GL_UNSIGNED_BYTE, zeroData); + delete[] zeroData; OSD::Init(true); @@ -310,6 +316,42 @@ void EmuThread::deinitOpenGL() lastScreenWidth = lastScreenHeight = -1; } +void EmuThread::updateDisplay(bool forceInit) +{ + // update render settings if needed + // HACK: + // once the fast forward hotkey is released, we need to update vsync + // to the old setting again + if (videoSettingsDirty || Input::HotkeyReleased(HK_FastForward)) + { + if (oglContext) + { + oglContext->SetSwapInterval(Config::ScreenVSync ? Config::ScreenVSyncInterval : 0); + videoRenderer = Config::_3DRenderer; + } +#ifdef OGLRENDERER_ENABLED + else +#endif + { + videoRenderer = 0; + } + + videoRenderer = oglContext ? Config::_3DRenderer : 0; + + videoSettingsDirty = false; + + videoSettings.Soft_Threaded = Config::Threaded3D != 0; + videoSettings.ScaleFactor = Config::ScaleFactor; + videoSettings.GL_BetterPolygons = Config::GL_BetterPolygons; + + FrontBufferLock.lock(); + GPU::SetRenderSettings(videoRenderer, videoSettings); + FrontBufferLock.unlock(); + } + + emit windowUpdate(); +} + void EmuThread::run() { u32 mainScreenPos[3]; @@ -321,23 +363,8 @@ void EmuThread::run() mainScreenPos[2] = 0; autoScreenSizing = 0; - videoSettingsDirty = false; - videoSettings.Soft_Threaded = Config::Threaded3D != 0; - videoSettings.GL_ScaleFactor = Config::GL_ScaleFactor; - videoSettings.GL_BetterPolygons = Config::GL_BetterPolygons; - - if (mainWindow->hasOGL) - { - initOpenGL(); - videoRenderer = Config::_3DRenderer; - } - else - { - videoRenderer = 0; - } - GPU::InitRenderer(videoRenderer); - GPU::SetRenderSettings(videoRenderer, videoSettings); + updateDisplay(true); SPU::SetInterpolation(Config::AudioInterp); @@ -431,35 +458,6 @@ void EmuThread::run() EmuStatus = emuStatus_Running; if (EmuRunning == emuStatus_FrameStep) EmuRunning = emuStatus_Paused; - // update render settings if needed - // HACK: - // once the fast forward hotkey is released, we need to update vsync - // to the old setting again - if (videoSettingsDirty || Input::HotkeyReleased(HK_FastForward)) - { - if (oglContext) - { - oglContext->SetSwapInterval(Config::ScreenVSync ? Config::ScreenVSyncInterval : 0); - videoRenderer = Config::_3DRenderer; - } -#ifdef OGLRENDERER_ENABLED - else -#endif - { - videoRenderer = 0; - } - - videoRenderer = oglContext ? Config::_3DRenderer : 0; - - videoSettingsDirty = false; - - videoSettings.Soft_Threaded = Config::Threaded3D != 0; - videoSettings.GL_ScaleFactor = Config::GL_ScaleFactor; - videoSettings.GL_BetterPolygons = Config::GL_BetterPolygons; - - GPU::SetRenderSettings(videoRenderer, videoSettings); - } - // process input and hotkeys NDS::SetKeyMask(Input::InputMask); @@ -617,7 +615,7 @@ void EmuThread::run() lastTime = SDL_GetPerformanceCounter() * perfCountsSec; lastMeasureTime = lastTime; - emit windowUpdate(); + updateDisplay(); EmuStatus = EmuRunning; @@ -766,9 +764,9 @@ void EmuThread::drawScreenGL() if (GPU::Framebuffer[frontbuf][0] && GPU::Framebuffer[frontbuf][1]) { - glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 256, 192, GL_RGBA, + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, screenWidth, screenHeight, GL_RGBA, GL_UNSIGNED_BYTE, GPU::Framebuffer[frontbuf][0]); - glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 192+2, 256, 192, GL_RGBA, + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, screenHeight+2, screenWidth, screenHeight, GL_RGBA, GL_UNSIGNED_BYTE, GPU::Framebuffer[frontbuf][1]); } } @@ -835,6 +833,7 @@ void ScreenHandler::screenSetupLayout(int w, int h) static_cast<Frontend::ScreenRotation>(Config::ScreenRotation), static_cast<Frontend::ScreenSizing>(sizing), Config::ScreenGap, + Config::ScaleFactor, Config::IntegerScaling != 0, Config::ScreenSwap != 0, aspectTop, @@ -849,8 +848,8 @@ QSize ScreenHandler::screenGetMinSize(int factor = 1) || Config::ScreenRotation == Frontend::screenRot_270Deg); int gap = Config::ScreenGap * factor; - int w = 256 * factor; - int h = 192 * factor; + int w = NATIVE_WIDTH * factor; + int h = NATIVE_HEIGHT * factor; if (Config::ScreenSizing == Frontend::screenSizing_TopOnly || Config::ScreenSizing == Frontend::screenSizing_BotOnly) @@ -1013,8 +1012,8 @@ QTimer* ScreenHandler::setupMouseTimer() ScreenPanelNative::ScreenPanelNative(QWidget* parent) : QWidget(parent), ScreenHandler(this) { - screen[0] = QImage(256, 192, QImage::Format_RGB32); - screen[1] = QImage(256, 192, QImage::Format_RGB32); + screen[0] = QImage(screenWidth, screenHeight, QImage::Format_RGB32); + screen[1] = QImage(screenWidth, screenHeight, QImage::Format_RGB32); screenTrans[0].reset(); screenTrans[1].reset(); @@ -1045,6 +1044,9 @@ void ScreenPanelNative::setupScreenLayout() void ScreenPanelNative::paintEvent(QPaintEvent* event) { + if (videoSettingsDirty) + return; + QPainter painter(this); // fill background @@ -1052,7 +1054,7 @@ void ScreenPanelNative::paintEvent(QPaintEvent* event) if (emuThread->emuIsActive()) { - emuThread->FrontBufferLock.lock(); + emuThread->FrontBufferLock.lock(); locked = true; int frontbuf = emuThread->FrontBuffer; if (!GPU::Framebuffer[frontbuf][0] || !GPU::Framebuffer[frontbuf][1]) { @@ -1060,11 +1062,11 @@ void ScreenPanelNative::paintEvent(QPaintEvent* event) return; } - memcpy(screen[0].scanLine(0), GPU::Framebuffer[frontbuf][0], 256 * 192 * 4); - memcpy(screen[1].scanLine(0), GPU::Framebuffer[frontbuf][1], 256 * 192 * 4); + memcpy(screen[0].scanLine(0), GPU::Framebuffer[frontbuf][0], screenWidth * screenHeight * 4); + memcpy(screen[1].scanLine(0), GPU::Framebuffer[frontbuf][1], screenWidth * screenHeight * 4); emuThread->FrontBufferLock.unlock(); - QRect screenrc(0, 0, 256, 192); + QRect screenrc(0, 0, screenWidth, screenHeight); for (int i = 0; i < numScreens; i++) { @@ -1116,7 +1118,7 @@ bool ScreenPanelNative::event(QEvent* event) void ScreenPanelNative::onScreenLayoutChanged() { - setMinimumSize(screenGetMinSize()); + setMinimumSize(screenGetMinSize(Config::ScaleFactor)); setupScreenLayout(); } @@ -1221,6 +1223,9 @@ QPaintEngine* ScreenPanelGL::paintEngine() const void ScreenPanelGL::setupScreenLayout() { + if (videoSettingsDirty) + return; + int w = width(); int h = height(); @@ -1238,6 +1243,7 @@ void ScreenPanelGL::resizeEvent(QResizeEvent* event) void ScreenPanelGL::mousePressEvent(QMouseEvent* event) { + bool locked = false; screenOnMousePress(event); } @@ -1277,7 +1283,7 @@ void ScreenPanelGL::transferLayout(EmuThread* thread) void ScreenPanelGL::onScreenLayoutChanged() { - setMinimumSize(screenGetMinSize()); + setMinimumSize(screenGetMinSize(Config::ScaleFactor)); setupScreenLayout(); } @@ -1860,6 +1866,8 @@ void MainWindow::closeEvent(QCloseEvent* event) void MainWindow::createScreenPanel() { hasOGL = (Config::ScreenUseGL != 0) || (Config::_3DRenderer != 0); + screenWidth = NATIVE_WIDTH * Config::ScaleFactor; + screenHeight = NATIVE_HEIGHT * Config::ScaleFactor; if (hasOGL) { @@ -3171,9 +3179,11 @@ void MainWindow::onEmuStop() actTitleManager->setEnabled(!Config::DSiNANDPath.empty()); } -void MainWindow::onUpdateVideoSettings(bool glchange) +void MainWindow::onUpdateVideoSettings(bool displayChange) { - if (glchange) + videoSettingsDirty = true; + + if (displayChange) { emuThread->emuPause(); if (hasOGL) emuThread->deinitContext(); @@ -3183,9 +3193,7 @@ void MainWindow::onUpdateVideoSettings(bool glchange) connect(emuThread, SIGNAL(windowUpdate()), panelWidget, SLOT(repaint())); } - videoSettingsDirty = true; - - if (glchange) + if (displayChange) { if (hasOGL) emuThread->initContext(); emuThread->emuUnpause(); @@ -3280,7 +3288,7 @@ int main(int argc, char** argv) #endif ); SANITIZE(Config::ScreenVSyncInterval, 1, 20); - SANITIZE(Config::GL_ScaleFactor, 1, 16); + SANITIZE(Config::ScaleFactor, 1, 16); SANITIZE(Config::AudioInterp, 0, 3); SANITIZE(Config::AudioVolume, 0, 256); SANITIZE(Config::MicInputType, 0, (int)micInputType_MAX); diff --git a/src/frontend/qt_sdl/main.h b/src/frontend/qt_sdl/main.h index 073a4da..f9ea1f7 100644 --- a/src/frontend/qt_sdl/main.h +++ b/src/frontend/qt_sdl/main.h @@ -89,6 +89,9 @@ signals: void syncVolumeLevel(); + bool hasOGL; + + void updateDisplay(bool forceInit = false); private: void drawScreenGL(); void initOpenGL(); @@ -261,6 +264,8 @@ public: bool preloadROMs(QStringList file, QStringList gbafile, bool boot); QStringList splitArchivePath(const QString& filename, bool useMemberSyntax); + void createScreenPanel(); + void onAppStateChanged(Qt::ApplicationState state); protected: @@ -348,7 +353,7 @@ private slots: void onEmuStart(); void onEmuStop(); - void onUpdateVideoSettings(bool glchange); + void onUpdateVideoSettings(bool displayChange); void onFullscreenToggled(); void onScreenEmphasisToggled(); @@ -367,8 +372,6 @@ private: QStringList pickROM(bool gba); void updateCartInserted(bool gba); - void createScreenPanel(); - bool pausedManually = false; int oldW, oldH; -- 2.42.0
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor