diff --git a/Aerofoil/GpFileSystem_Win32.cpp b/Aerofoil/GpFileSystem_Win32.cpp index 2e33820..2533ec6 100644 --- a/Aerofoil/GpFileSystem_Win32.cpp +++ b/Aerofoil/GpFileSystem_Win32.cpp @@ -322,6 +322,11 @@ bool GpFileSystem_Win32::IsVirtualDirectoryLooseResources(PortabilityLayer::Virt return false; } +void GpFileSystem_Win32::SetMainThreadRelay(IGpThreadRelay *relay) +{ + (void)relay; +} + bool GpFileSystem_Win32::ValidateFilePath(const char *str, size_t length) const { for (size_t i = 0; i < length; i++) diff --git a/Aerofoil/GpFileSystem_Win32.h b/Aerofoil/GpFileSystem_Win32.h index ebd09eb..903a434 100644 --- a/Aerofoil/GpFileSystem_Win32.h +++ b/Aerofoil/GpFileSystem_Win32.h @@ -23,6 +23,8 @@ public: bool IsVirtualDirectoryLooseResources(PortabilityLayer::VirtualDirectory_t virtualDir) const override; + void SetMainThreadRelay(IGpThreadRelay *relay) override; + const wchar_t *GetBasePath() const; static GpFileSystem_Win32 *GetInstance(); diff --git a/AerofoilAndroid/app/jni/main/GpFileSystem_Android.cpp b/AerofoilAndroid/app/jni/main/GpFileSystem_Android.cpp index 6de3321..ee60a89 100644 --- a/AerofoilAndroid/app/jni/main/GpFileSystem_Android.cpp +++ b/AerofoilAndroid/app/jni/main/GpFileSystem_Android.cpp @@ -2,6 +2,7 @@ #include "GpFileSystem_Android.h" #include "GpIOStream.h" #include "HostDirectoryCursor.h" +#include "IGpThreadRelay.h" #include "VirtualDirectory.h" #include "SDL.h" @@ -254,7 +255,32 @@ void GpFileStream_Android_File::Flush() fflush(m_f); } -static bool ResolvePath(PortabilityLayer::VirtualDirectory_t virtualDirectory, char const* const* paths, size_t numPaths, std::string &resolution, bool &isAsset) +bool GpFileSystem_Android::ResolvePathInDownloadsDirectory(PortabilityLayer::VirtualDirectory_t virtualDirectory, char const* const* paths, size_t numPaths, std::string &resolution, bool &isAsset) +{ + JNIEnv *jni = static_cast(SDL_AndroidGetJNIEnv()); + + jstring fname = jni->NewStringUTF(paths[0]); + + jobject resultName = jni->CallObjectMethod(m_activity, this->m_selectSourceExportPathMID, fname); + int n = 0; + jstring resultPath = static_cast(resultName); + jni->DeleteLocalRef(fname); + + const char *pathStrChars = jni->GetStringUTFChars(resultPath, nullptr); + resolution = std::string(pathStrChars, static_cast(jni->GetStringUTFLength(resultPath))); + + jni->ReleaseStringUTFChars(resultPath, pathStrChars); + jni->DeleteLocalRef(resultPath); + + resolution = SDL_AndroidGetExternalStoragePath(); + resolution += "/SourceCode.zip"; + + isAsset = false; + + return true; +} + +bool GpFileSystem_Android::ResolvePath(PortabilityLayer::VirtualDirectory_t virtualDirectory, char const* const* paths, size_t numPaths, std::string &resolution, bool &isAsset) { const char *prefsAppend = nullptr; @@ -285,6 +311,8 @@ static bool ResolvePath(PortabilityLayer::VirtualDirectory_t virtualDirectory, c case PortabilityLayer::VirtualDirectories::kPrefs: prefsAppend = "Prefs"; break; + case PortabilityLayer::VirtualDirectories::kSourceExport: + return ResolvePathInDownloadsDirectory(virtualDirectory, paths, numPaths, resolution, isAsset); default: return false; }; @@ -308,6 +336,7 @@ static bool ResolvePath(PortabilityLayer::VirtualDirectory_t virtualDirectory, c GpFileSystem_Android::GpFileSystem_Android() : m_activity(nullptr) + , m_relay(nullptr) { } @@ -323,6 +352,7 @@ void GpFileSystem_Android::InitJNI() jclass activityClassLR = static_cast(jni->GetObjectClass(activityLR)); m_scanAssetDirectoryMID = jni->GetMethodID(activityClassLR, "scanAssetDirectory", "(Ljava/lang/String;)[Ljava/lang/String;"); + m_selectSourceExportPathMID = jni->GetMethodID(activityClassLR, "selectSourceExportPath", "(Ljava/lang/String;)Ljava/lang/String;"); m_activity = jni->NewGlobalRef(activityLR); @@ -407,7 +437,8 @@ GpIOStream *GpFileSystem_Android::OpenFileNested(PortabilityLayer::VirtualDirect bool canWrite = false; bool needResetPosition = false; - switch (createDisposition) { + switch (createDisposition) + { case GpFileCreationDispositions::kCreateOrOverwrite: mode = "w+b"; break; @@ -506,6 +537,25 @@ bool GpFileSystem_Android::DeleteFile(PortabilityLayer::VirtualDirectory_t virtu } PortabilityLayer::HostDirectoryCursor *GpFileSystem_Android::ScanDirectoryNested(PortabilityLayer::VirtualDirectory_t virtualDirectory, const char *const *paths, size_t numPaths) +{ + ScanDirectoryNestedContext ctx; + ctx.m_this = this; + ctx.m_returnValue = nullptr; + ctx.m_virtualDirectory = virtualDirectory; + ctx.m_paths = paths; + ctx.m_numPaths = numPaths; + m_relay->Invoke(ScanDirectoryNestedThunk, &ctx); + + return ctx.m_returnValue; +} + +void GpFileSystem_Android::ScanDirectoryNestedThunk(void *context) +{ + ScanDirectoryNestedContext *ctx = static_cast(context); + ctx->m_returnValue = ctx->m_this->ScanDirectoryNestedInternal(ctx->m_virtualDirectory, ctx->m_paths, ctx->m_numPaths); +} + +PortabilityLayer::HostDirectoryCursor *GpFileSystem_Android::ScanDirectoryNestedInternal(PortabilityLayer::VirtualDirectory_t virtualDirectory, const char *const *paths, size_t numPaths) { if (virtualDirectory == PortabilityLayer::VirtualDirectories::kGameData || virtualDirectory == PortabilityLayer::VirtualDirectories::kApplicationData) return ScanAssetDirectory(virtualDirectory, paths, numPaths); @@ -564,6 +614,11 @@ bool GpFileSystem_Android::IsVirtualDirectoryLooseResources(PortabilityLayer::Vi return false; } +void GpFileSystem_Android::SetMainThreadRelay(IGpThreadRelay *relay) +{ + m_relay = relay; +} + GpFileSystem_Android *GpFileSystem_Android::GetInstance() { return &ms_instance; @@ -647,6 +702,7 @@ void GpDirectoryCursor_POSIX::Destroy() PortabilityLayer::HostDirectoryCursor *GpFileSystem_Android::ScanAssetDirectory(PortabilityLayer::VirtualDirectory_t virtualDirectory, char const* const* paths, size_t numPaths) { + std::string resolvedPath; std::vector subPaths; bool isAsset = true; diff --git a/AerofoilAndroid/app/jni/main/GpFileSystem_Android.h b/AerofoilAndroid/app/jni/main/GpFileSystem_Android.h index fe455be..0381fdd 100644 --- a/AerofoilAndroid/app/jni/main/GpFileSystem_Android.h +++ b/AerofoilAndroid/app/jni/main/GpFileSystem_Android.h @@ -5,6 +5,7 @@ #include "GpCoreDefs.h" #include +#include class GpFileSystem_Android final : public PortabilityLayer::HostFileSystem { @@ -26,14 +27,35 @@ public: bool IsVirtualDirectoryLooseResources(PortabilityLayer::VirtualDirectory_t virtualDir) const override; + void SetMainThreadRelay(IGpThreadRelay *relay) override; + static GpFileSystem_Android *GetInstance(); private: + struct ScanDirectoryNestedContext + { + GpFileSystem_Android *m_this; + + PortabilityLayer::HostDirectoryCursor *m_returnValue; + PortabilityLayer::VirtualDirectory_t m_virtualDirectory; + char const *const *m_paths; + size_t m_numPaths; + }; + + static void ScanDirectoryNestedThunk(void *context); + PortabilityLayer::HostDirectoryCursor *ScanDirectoryNestedInternal(PortabilityLayer::VirtualDirectory_t virtualDirectory, char const* const* paths, size_t numPaths); + PortabilityLayer::HostDirectoryCursor *ScanAssetDirectory(PortabilityLayer::VirtualDirectory_t virtualDirectory, char const* const* paths, size_t numPaths); PortabilityLayer::HostDirectoryCursor *ScanStorageDirectory(PortabilityLayer::VirtualDirectory_t virtualDirectory, char const* const* paths, size_t numPaths); + bool ResolvePathInDownloadsDirectory(PortabilityLayer::VirtualDirectory_t virtualDirectory, char const* const* paths, size_t numPaths, std::string &resolution, bool &isAsset); + bool ResolvePath(PortabilityLayer::VirtualDirectory_t virtualDirectory, char const* const* paths, size_t numPaths, std::string &resolution, bool &isAsset); + + IGpThreadRelay *m_relay; + jobject m_activity; jmethodID m_scanAssetDirectoryMID; + jmethodID m_selectSourceExportPathMID; static GpFileSystem_Android ms_instance; }; diff --git a/AerofoilAndroid/app/jni/main/GpMain_SDL_Android.cpp b/AerofoilAndroid/app/jni/main/GpMain_SDL_Android.cpp index 9200bee..402a880 100644 --- a/AerofoilAndroid/app/jni/main/GpMain_SDL_Android.cpp +++ b/AerofoilAndroid/app/jni/main/GpMain_SDL_Android.cpp @@ -30,6 +30,8 @@ IGpAudioDriver *GpDriver_CreateAudioDriver_SDL(const GpAudioDriverProperties &pr int main(int argc, char* argv[]) { + SDL_LogSetAllPriority(SDL_LOG_PRIORITY_WARN); + if (SDL_Init(SDL_INIT_VIDEO) < 0) return -1; diff --git a/AerofoilAndroid/app/src/main/AndroidManifest.xml b/AerofoilAndroid/app/src/main/AndroidManifest.xml index f3294c7..6ce7d5b 100644 --- a/AerofoilAndroid/app/src/main/AndroidManifest.xml +++ b/AerofoilAndroid/app/src/main/AndroidManifest.xml @@ -9,7 +9,7 @@ android:installLocation="auto"> - + ::GetID() const class GpDisplayDriverSurface_GL2 : public IGpDisplayDriverSurface { public: - GpDisplayDriverSurface_GL2(GpDisplayDriver_SDL_GL2 *driver, size_t width, size_t height, size_t pitch, GpGLTexture *texture, GpPixelFormat_t pixelFormat); + GpDisplayDriverSurface_GL2(GpDisplayDriver_SDL_GL2 *driver, size_t width, size_t height, size_t pitch, GpGLTexture *texture, GpPixelFormat_t pixelFormat, IGpDisplayDriver::SurfaceInvalidateCallback_t invalidateCallback, void *invalidateContext); ~GpDisplayDriverSurface_GL2(); - static GpDisplayDriverSurface_GL2 *Create(GpDisplayDriver_SDL_GL2 *driver, size_t width, size_t height, size_t pitch, GpPixelFormat_t pixelFormat); + static GpDisplayDriverSurface_GL2 *Create(GpDisplayDriver_SDL_GL2 *driver, size_t width, size_t height, size_t pitch, GpPixelFormat_t pixelFormat, GpDisplayDriverSurface_GL2 *prevSurface, IGpDisplayDriver::SurfaceInvalidateCallback_t invalidateCallback, void *invalidateContext); void Upload(const void *data, size_t x, size_t y, size_t width, size_t height, size_t pitch); void UploadEntire(const void *data, size_t pitch); void Destroy(); + bool RecreateAll(); + size_t GetImageWidth() const; size_t GetPaddedTextureWidth() const; size_t GetHeight() const; @@ -645,7 +647,8 @@ public: GpGLTexture *GetTexture() const; private: - bool Init(); + bool Init(GpDisplayDriverSurface_GL2 *prevSurface); + bool RecreateSingle(); GLenum ResolveGLFormat() const; GLenum ResolveGLInternalFormat() const; GLenum ResolveGLType() const; @@ -657,6 +660,13 @@ private: size_t m_paddedTextureWidth; size_t m_pitch; size_t m_height; + + GpDisplayDriver_SDL_GL2 *m_driver; + GpDisplayDriverSurface_GL2 *m_next; + GpDisplayDriverSurface_GL2 *m_prev; + + IGpDisplayDriver::SurfaceInvalidateCallback_t m_invalidateCallback; + void *m_invalidateContext; }; class GpCursor_SDL2 final : public IGpCursor @@ -714,7 +724,7 @@ public: void Run() override; void Shutdown() override; void GetDisplayResolution(unsigned int *width, unsigned int *height) override; - IGpDisplayDriverSurface *CreateSurface(size_t width, size_t height, size_t pitch, GpPixelFormat_t pixelFormat) override; + IGpDisplayDriverSurface *CreateSurface(size_t width, size_t height, size_t pitch, GpPixelFormat_t pixelFormat, SurfaceInvalidateCallback_t invalidateCallback, void *invalidateContext) override; void DrawSurface(IGpDisplayDriverSurface *surface, int32_t x, int32_t y, size_t width, size_t height, const GpDisplayDriverSurfaceEffects *effects) override; IGpCursor *CreateBWCursor(size_t width, size_t height, const void *pixelData, const void *maskData, size_t hotSpotX, size_t hotSpotY) override; IGpCursor *CreateColorCursor(size_t width, size_t height, const void *pixelDataRGBA, size_t hotSpotX, size_t hotSpotY) override; @@ -733,6 +743,8 @@ public: void ApplyPrefs(const void *identifier, size_t identifierSize, const void *contents, size_t contentsSize, uint32_t version) override; bool SavePrefs(void *context, WritePrefsFunc_t writeFunc) override; + void UnlinkSurface(GpDisplayDriverSurface_GL2 *surface, GpDisplayDriverSurface_GL2 *prev, GpDisplayDriverSurface_GL2 *next); + const GpGLFunctions *GetGLFunctions() const; template GpComPtr > CreateShader(const char *shaderSrc); @@ -776,15 +788,6 @@ private: GpGLFunctions m_gl; GpDisplayDriverProperties m_properties; - GpComPtr m_virtualScreenTextureRTV; - GpComPtr m_virtualScreenTexture; - - GpComPtr m_quadVertexArray; - GpComPtr m_quadVertexBufferKeepalive; - GpComPtr m_quadIndexBuffer; - - GpComPtr m_paletteTexture; - struct DrawQuadProgram { GpComPtr m_program; @@ -815,17 +818,31 @@ private: bool Link(GpDisplayDriver_SDL_GL2 *driver, const GpGLShader *vertexShader, const GpGLShader *pixelShader); }; - BlitQuadProgram m_scaleQuadProgram; - BlitQuadProgram m_copyQuadProgram; + struct InstancedResources + { + GpComPtr m_virtualScreenTextureRTV; + GpComPtr m_virtualScreenTexture; - DrawQuadProgram m_drawQuadPaletteNoFlickerProgram; - DrawQuadProgram m_drawQuadPaletteFlickerProgram; - DrawQuadProgram m_drawQuadRGBProgram; - DrawQuadProgram m_drawQuad15BitProgram; - DrawQuadProgram m_drawQuadPaletteICCNoFlickerProgram; - DrawQuadProgram m_drawQuadPaletteICCFlickerProgram; - DrawQuadProgram m_drawQuadRGBICCProgram; - DrawQuadProgram m_drawQuad15BitICCProgram; + GpComPtr m_quadVertexArray; + GpComPtr m_quadVertexBufferKeepalive; + GpComPtr m_quadIndexBuffer; + + GpComPtr m_paletteTexture; + + BlitQuadProgram m_scaleQuadProgram; + BlitQuadProgram m_copyQuadProgram; + + DrawQuadProgram m_drawQuadPaletteNoFlickerProgram; + DrawQuadProgram m_drawQuadPaletteFlickerProgram; + DrawQuadProgram m_drawQuadRGBProgram; + DrawQuadProgram m_drawQuad15BitProgram; + DrawQuadProgram m_drawQuadPaletteICCNoFlickerProgram; + DrawQuadProgram m_drawQuadPaletteICCFlickerProgram; + DrawQuadProgram m_drawQuadRGBICCProgram; + DrawQuadProgram m_drawQuad15BitICCProgram; + }; + + InstancedResources m_res; SDL_Window *m_window; SDL_GLContext m_glContext; @@ -834,6 +851,7 @@ private: SDL_Cursor *m_iBeamCursor; SDL_Cursor *m_arrowCursor; bool m_cursorIsHidden; + bool m_contextLost; bool m_isResettingSwapChain; @@ -872,10 +890,16 @@ private: std::chrono::time_point::duration m_syncTimeBase; GpRingBuffer m_presentHistory; + + GpDisplayDriverSurface_GL2 *m_firstSurface; + GpDisplayDriverSurface_GL2 *m_lastSurface; + + uint8_t m_paletteStorage[256 * 4 + GP_SYSTEM_MEMORY_ALIGNMENT]; + uint8_t *m_paletteData; }; -GpDisplayDriverSurface_GL2::GpDisplayDriverSurface_GL2(GpDisplayDriver_SDL_GL2 *driver, size_t width, size_t height, size_t pitch, GpGLTexture *texture, GpPixelFormat_t pixelFormat) +GpDisplayDriverSurface_GL2::GpDisplayDriverSurface_GL2(GpDisplayDriver_SDL_GL2 *driver, size_t width, size_t height, size_t pitch, GpGLTexture *texture, GpPixelFormat_t pixelFormat, IGpDisplayDriver::SurfaceInvalidateCallback_t invalidateCallback, void *invalidateContext) : m_gl(driver->GetGLFunctions()) , m_texture(texture) , m_pixelFormat(pixelFormat) @@ -883,6 +907,11 @@ GpDisplayDriverSurface_GL2::GpDisplayDriverSurface_GL2(GpDisplayDriver_SDL_GL2 * , m_paddedTextureWidth(0) , m_height(height) , m_pitch(pitch) + , m_driver(driver) + , m_prev(nullptr) + , m_next(nullptr) + , m_invalidateCallback(invalidateCallback) + , m_invalidateContext(invalidateContext) { size_t paddingPixels = 0; @@ -915,9 +944,15 @@ GpDisplayDriverSurface_GL2::GpDisplayDriverSurface_GL2(GpDisplayDriver_SDL_GL2 * GpDisplayDriverSurface_GL2::~GpDisplayDriverSurface_GL2() { + if (m_prev) + m_prev->m_next = m_next; + if (m_next) + m_next->m_prev = m_prev; + + m_driver->UnlinkSurface(this, m_prev, m_next); } -GpDisplayDriverSurface_GL2 *GpDisplayDriverSurface_GL2::Create(GpDisplayDriver_SDL_GL2 *driver, size_t width, size_t height, size_t pitch, GpPixelFormat_t pixelFormat) +GpDisplayDriverSurface_GL2 *GpDisplayDriverSurface_GL2::Create(GpDisplayDriver_SDL_GL2 *driver, size_t width, size_t height, size_t pitch, GpPixelFormat_t pixelFormat, GpDisplayDriverSurface_GL2 *prevSurface, IGpDisplayDriver::SurfaceInvalidateCallback_t invalidateCallback, void *invalidateContext) { GpComPtr texture = GpComPtr(GpGLTexture::Create(driver)); if (!texture) @@ -927,8 +962,8 @@ GpDisplayDriverSurface_GL2 *GpDisplayDriverSurface_GL2::Create(GpDisplayDriver_S if (!surface) return nullptr; - new (surface) GpDisplayDriverSurface_GL2(driver, width, height, pitch, texture, pixelFormat); - if (!surface->Init()) + new (surface) GpDisplayDriverSurface_GL2(driver, width, height, pitch, texture, pixelFormat, invalidateCallback, invalidateContext); + if (!surface->Init(prevSurface)) { surface->Destroy(); return nullptr; @@ -967,6 +1002,23 @@ void GpDisplayDriverSurface_GL2::Destroy() free(this); } +bool GpDisplayDriverSurface_GL2::RecreateAll() +{ + for (GpDisplayDriverSurface_GL2 *scan = this; scan; scan = scan->m_next) + { + scan->m_invalidateCallback(scan->m_invalidateContext); + scan->m_texture = nullptr; + } + + for (GpDisplayDriverSurface_GL2 *scan = this; scan; scan = scan->m_next) + { + if (!scan->RecreateSingle()) + return false; + } + + return true; +} + size_t GpDisplayDriverSurface_GL2::GetImageWidth() const { return m_imageWidth; @@ -993,7 +1045,7 @@ GpGLTexture *GpDisplayDriverSurface_GL2::GetTexture() const } -bool GpDisplayDriverSurface_GL2::Init() +bool GpDisplayDriverSurface_GL2::Init(GpDisplayDriverSurface_GL2 *prevSurface) { CheckGLError(*m_gl); @@ -1011,6 +1063,12 @@ bool GpDisplayDriverSurface_GL2::Init() return true; } +bool GpDisplayDriverSurface_GL2::RecreateSingle() +{ + m_texture = GpGLTexture::Create(m_driver); + return m_texture != nullptr; +} + GLenum GpDisplayDriverSurface_GL2::ResolveGLFormat() const { switch (m_pixelFormat) @@ -1101,6 +1159,9 @@ GpDisplayDriver_SDL_GL2::GpDisplayDriver_SDL_GL2(const GpDisplayDriverProperties , m_iBeamCursor(nullptr) , m_arrowCursor(nullptr) , m_cursorIsHidden(false) + , m_contextLost(true) + , m_lastSurface(nullptr) + , m_firstSurface(nullptr) { m_bgColor[0] = 0.f; m_bgColor[1] = 0.f; @@ -1118,6 +1179,12 @@ GpDisplayDriver_SDL_GL2::GpDisplayDriver_SDL_GL2(const GpDisplayDriverProperties m_waitCursor = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_WAIT); m_iBeamCursor = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_IBEAM); m_arrowCursor = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_ARROW); + + m_paletteData = m_paletteStorage; + while (reinterpret_cast(m_paletteData) % GP_SYSTEM_MEMORY_ALIGNMENT != 0) + m_paletteData++; + + memset(m_paletteData, 255, 256 * 4); } template @@ -1724,7 +1791,45 @@ void GpDisplayDriver_SDL_GL2::Run() m_vosEvent = m_properties.m_systemServices->CreateThreadEvent(true, false); m_vosFiber = new GpFiber_SDL(nullptr, m_vosEvent); - m_window = SDL_CreateWindow(GP_APPLICATION_NAME, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, m_windowWidthPhysical, m_windowHeightPhysical, SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE); + uint32_t windowFlags = SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN; + if (m_isFullScreenDesired) + { + windowFlags |= SDL_WINDOW_FULLSCREEN_DESKTOP; + m_isFullScreen = true; + } + else + windowFlags |= SDL_WINDOW_RESIZABLE; + + m_window = SDL_CreateWindow(GP_APPLICATION_NAME, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, m_windowWidthPhysical, m_windowHeightPhysical, windowFlags); + + if (m_isFullScreen) + { + m_windowModeRevertWidth = m_windowWidthPhysical; + m_windowModeRevertHeight = m_windowHeightPhysical; + + int windowWidth = 0; + int windowHeight = 0; + SDL_GetWindowSize(m_window, &windowWidth, &windowHeight); + + m_windowWidthPhysical = windowWidth; + m_windowHeightPhysical = windowHeight; + + + uint32_t desiredWidth = windowWidth; + uint32_t desiredHeight = windowHeight; + uint32_t virtualWidth = m_windowWidthVirtual; + uint32_t virtualHeight = m_windowHeightVirtual; + float pixelScaleX = m_pixelScaleX; + float pixelScaleY = m_pixelScaleY; + + if (m_properties.m_adjustRequestedResolutionFunc(m_properties.m_adjustRequestedResolutionFuncContext, desiredWidth, desiredHeight, virtualWidth, virtualHeight, pixelScaleX, pixelScaleY)) + { + m_windowWidthVirtual = virtualWidth; + m_windowHeightVirtual = virtualHeight; + m_pixelScaleX = pixelScaleX; + m_pixelScaleY = pixelScaleY; + } + } const bool obstructiveTextInput = m_properties.m_systemServices->IsTextInputObstructive(); @@ -1736,8 +1841,6 @@ void GpDisplayDriver_SDL_GL2::Run() if (!m_gl.LookUpFunctions()) return; - InitResources(m_windowWidthVirtual, m_windowHeightVirtual); - for (;;) { SDL_Event msg; @@ -1750,8 +1853,11 @@ void GpDisplayDriver_SDL_GL2::Run() } //else if (msg.type == SDL_MOUSELEAVE) // Does SDL support this?? // m_mouseIsInClientArea = false; + else if (msg.type == SDL_RENDER_DEVICE_RESET || msg.type == SDL_RENDER_TARGETS_RESET) + m_contextLost = true; TranslateSDLMessage(&msg, m_properties.m_eventQueue, m_pixelScaleX, m_pixelScaleY, obstructiveTextInput); + } else { @@ -1761,6 +1867,9 @@ void GpDisplayDriver_SDL_GL2::Run() BecomeFullScreen(); else BecomeWindowed(); + + m_contextLost = true; + continue; } int clientWidth = 0; @@ -1784,7 +1893,6 @@ void GpDisplayDriver_SDL_GL2::Run() if (m_properties.m_adjustRequestedResolutionFunc(m_properties.m_adjustRequestedResolutionFuncContext, desiredWidth, desiredHeight, virtualWidth, virtualHeight, pixelScaleX, pixelScaleY)) { bool resizedOK = ResizeOpenGLWindow(m_windowWidthPhysical, m_windowHeightPhysical, desiredWidth, desiredHeight, logger); - resizedOK = resizedOK && InitBackBuffer(virtualWidth, virtualHeight); if (!resizedOK) break; // Critical video driver error, exit @@ -1803,9 +1911,30 @@ void GpDisplayDriver_SDL_GL2::Run() resizeEvent->m_event.m_resolutionChangedEvent.m_newWidth = m_windowWidthVirtual; resizeEvent->m_event.m_resolutionChangedEvent.m_newHeight = m_windowHeightVirtual; } + + m_contextLost = true; + continue; } } + if (m_contextLost) + { + // Drop everything and reset + m_res.~InstancedResources(); + new (&m_res) InstancedResources(); + + if (m_firstSurface) + m_firstSurface->RecreateAll(); + + if (!InitBackBuffer(m_windowWidthVirtual, m_windowHeightVirtual)) + break; + + InitResources(m_windowWidthVirtual, m_windowHeightVirtual); + + m_contextLost = false; + continue; + } + GpDisplayDriverTickStatus_t tickStatus = PresentFrameAndSync(); if (tickStatus == GpDisplayDriverTickStatuses::kFatalFault || tickStatus == GpDisplayDriverTickStatuses::kApplicationTerminated) break; @@ -1830,9 +1959,16 @@ void GpDisplayDriver_SDL_GL2::GetDisplayResolution(unsigned int *width, unsigned *height = m_windowHeightVirtual; } -IGpDisplayDriverSurface *GpDisplayDriver_SDL_GL2::CreateSurface(size_t width, size_t height, size_t pitch, GpPixelFormat_t pixelFormat) +IGpDisplayDriverSurface *GpDisplayDriver_SDL_GL2::CreateSurface(size_t width, size_t height, size_t pitch, GpPixelFormat_t pixelFormat, SurfaceInvalidateCallback_t invalidateCallback, void *invalidateContext) { - return GpDisplayDriverSurface_GL2::Create(this, width, height, pitch, pixelFormat); + GpDisplayDriverSurface_GL2 *surface = GpDisplayDriverSurface_GL2::Create(this, width, height, pitch, pixelFormat, m_lastSurface, invalidateCallback, invalidateContext); + if (surface) + { + m_lastSurface = surface; + if (m_firstSurface == nullptr) + m_firstSurface = surface; + } + return surface; } void GpDisplayDriver_SDL_GL2::DrawSurface(IGpDisplayDriverSurface *surface, int32_t x, int32_t y, size_t width, size_t height, const GpDisplayDriverSurfaceEffects *effects) @@ -1840,7 +1976,7 @@ void GpDisplayDriver_SDL_GL2::DrawSurface(IGpDisplayDriverSurface *surface, int3 if (!effects) effects = &gs_defaultEffects; - GpGLVertexArray *vaPtr = m_quadVertexArray; + GpGLVertexArray *vaPtr = m_res.m_quadVertexArray; size_t vbStride = sizeof(float) * 2; size_t zero = 0; @@ -1854,16 +1990,16 @@ void GpDisplayDriver_SDL_GL2::DrawSurface(IGpDisplayDriverSurface *surface, int3 if (m_useICCProfile) { if (effects->m_flicker) - program = &m_drawQuadPaletteICCFlickerProgram; + program = &m_res.m_drawQuadPaletteICCFlickerProgram; else - program = &m_drawQuadPaletteICCNoFlickerProgram; + program = &m_res.m_drawQuadPaletteICCNoFlickerProgram; } else { if (effects->m_flicker) - program = &m_drawQuadPaletteFlickerProgram; + program = &m_res.m_drawQuadPaletteFlickerProgram; else - program = &m_drawQuadPaletteNoFlickerProgram; + program = &m_res.m_drawQuadPaletteNoFlickerProgram; } } else if (pixelFormat == GpPixelFormats::kRGB555) @@ -1937,7 +2073,7 @@ void GpDisplayDriver_SDL_GL2::DrawSurface(IGpDisplayDriverSurface *surface, int3 GLint vpos[1] = { program->m_vertexPosUVLocation }; - m_quadVertexArray->Activate(vpos); + m_res.m_quadVertexArray->Activate(vpos); m_gl.ActiveTexture(GL_TEXTURE0); m_gl.BindTexture(GL_TEXTURE_2D, glSurface->GetTexture()->GetID()); @@ -1946,11 +2082,11 @@ void GpDisplayDriver_SDL_GL2::DrawSurface(IGpDisplayDriverSurface *surface, int3 if (pixelFormat == GpPixelFormats::k8BitStandard || pixelFormat == GpPixelFormats::k8BitCustom) { m_gl.ActiveTexture(GL_TEXTURE1); - m_gl.BindTexture(GL_TEXTURE_2D, m_paletteTexture->GetID()); + m_gl.BindTexture(GL_TEXTURE_2D, m_res.m_paletteTexture->GetID()); m_gl.Uniform1i(program->m_pixelPaletteTextureLocation, 1); } - m_gl.BindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_quadIndexBuffer->GetID()); + m_gl.BindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_res.m_quadIndexBuffer->GetID()); m_gl.DrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, nullptr); m_gl.BindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); @@ -1965,7 +2101,7 @@ void GpDisplayDriver_SDL_GL2::DrawSurface(IGpDisplayDriverSurface *surface, int3 m_gl.ActiveTexture(GL_TEXTURE0); m_gl.BindTexture(GL_TEXTURE_2D, 0); - m_quadVertexArray->Deactivate(vpos); + m_res.m_quadVertexArray->Deactivate(vpos); m_gl.UseProgram(0); @@ -2032,8 +2168,11 @@ void GpDisplayDriver_SDL_GL2::SetStandardCursor(EGpStandardCursor_t standardCurs void GpDisplayDriver_SDL_GL2::UpdatePalette(const void *paletteData) { - m_gl.BindTexture(GL_TEXTURE_2D, m_paletteTexture->GetID()); - m_gl.TexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 256, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, paletteData); + memcpy(m_paletteData, paletteData, 256 * 4); + + m_gl.BindTexture(GL_TEXTURE_2D, m_res.m_paletteTexture->GetID()); + m_gl.PixelStorei(GL_UNPACK_ALIGNMENT, 1); + m_gl.TexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 256, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, m_paletteData); m_gl.BindTexture(GL_TEXTURE_2D, 0); } @@ -2093,6 +2232,15 @@ bool GpDisplayDriver_SDL_GL2::SavePrefs(void *context, WritePrefsFunc_t writeFun return true; } +void GpDisplayDriver_SDL_GL2::UnlinkSurface(GpDisplayDriverSurface_GL2 *surface, GpDisplayDriverSurface_GL2 *prev, GpDisplayDriverSurface_GL2 *next) +{ + if (m_lastSurface == surface) + m_lastSurface = prev; + + if (m_firstSurface == surface) + m_firstSurface = next; +} + const GpGLFunctions *GpDisplayDriver_SDL_GL2::GetGLFunctions() const { return &m_gl; @@ -2154,8 +2302,8 @@ bool GpDisplayDriver_SDL_GL2::InitResources(uint32_t virtualWidth, uint32_t virt { const uint16_t indexBufferData[] = { 0, 1, 2, 1, 3, 2 }; - m_quadIndexBuffer = GpGLBuffer::Create(this); - if (!m_quadIndexBuffer) + m_res.m_quadIndexBuffer = GpGLBuffer::Create(this); + if (!m_res.m_quadIndexBuffer) { if (logger) logger->Printf(IGpLogDriver::Category_Error, "GpDisplayDriver_SDL_GL2::InitResources: CreateBuffer for draw quad index buffer failed"); @@ -2163,7 +2311,7 @@ bool GpDisplayDriver_SDL_GL2::InitResources(uint32_t virtualWidth, uint32_t virt return false; } - m_gl.BindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_quadIndexBuffer->GetID()); + m_gl.BindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_res.m_quadIndexBuffer->GetID()); m_gl.BufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indexBufferData), indexBufferData, GL_STATIC_DRAW); m_gl.BindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); } @@ -2178,8 +2326,8 @@ bool GpDisplayDriver_SDL_GL2::InitResources(uint32_t virtualWidth, uint32_t virt 1.f, 1.f, }; - m_quadVertexBufferKeepalive = GpGLBuffer::Create(this); - if (!m_quadVertexBufferKeepalive) + m_res.m_quadVertexBufferKeepalive = GpGLBuffer::Create(this); + if (!m_res.m_quadVertexBufferKeepalive) { if (logger) logger->Printf(IGpLogDriver::Category_Error, "GpDisplayDriver_SDL_GL2::InitResources: GpGLBuffer::Create for draw quad vertex buffer failed"); @@ -2187,12 +2335,12 @@ bool GpDisplayDriver_SDL_GL2::InitResources(uint32_t virtualWidth, uint32_t virt return false; } - m_gl.BindBuffer(GL_ARRAY_BUFFER, m_quadVertexBufferKeepalive->GetID()); + m_gl.BindBuffer(GL_ARRAY_BUFFER, m_res.m_quadVertexBufferKeepalive->GetID()); m_gl.BufferData(GL_ARRAY_BUFFER, sizeof(vertexBufferData), vertexBufferData, GL_STATIC_DRAW); m_gl.BindBuffer(GL_ARRAY_BUFFER, 0); - m_quadVertexArray = GpGLVertexArray::Create(this); - if (!m_quadVertexBufferKeepalive) + m_res.m_quadVertexArray = GpGLVertexArray::Create(this); + if (!m_res.m_quadVertexBufferKeepalive) { if (logger) logger->Printf(IGpLogDriver::Category_Error, "GpDisplayDriver_SDL_GL2::InitResources: GpGLVertexArray::Create for draw quad vertex buffer failed"); @@ -2202,7 +2350,7 @@ bool GpDisplayDriver_SDL_GL2::InitResources(uint32_t virtualWidth, uint32_t virt GpGLVertexArraySpec specs[] = { - m_quadVertexBufferKeepalive, + m_res.m_quadVertexBufferKeepalive, 0, // index 2, // size GL_FLOAT, // type @@ -2211,7 +2359,7 @@ bool GpDisplayDriver_SDL_GL2::InitResources(uint32_t virtualWidth, uint32_t virt 0 }; - if (!m_quadVertexArray->InitWithSpecs(specs, sizeof(specs) / sizeof(specs[0]))) + if (!m_res.m_quadVertexArray->InitWithSpecs(specs, sizeof(specs) / sizeof(specs[0]))) { if (logger) logger->Printf(IGpLogDriver::Category_Error, "GpDisplayDriver_SDL_GL2::InitResources: InitWithSpecs for draw quad vertex buffer failed"); @@ -2232,31 +2380,22 @@ bool GpDisplayDriver_SDL_GL2::InitResources(uint32_t virtualWidth, uint32_t virt GpComPtr> scaleQuadPixelShader = CreateShader(GpBinarizedShaders::g_scaleQuadP_GL2); GpComPtr> copyQuadPixelShader = CreateShader(GpBinarizedShaders::g_copyQuadP_GL2); - if (!m_drawQuadPaletteFlickerProgram.Link(this, drawQuadVertexShader, drawQuadPaletteFlickerPixelShader) - || !m_drawQuadPaletteNoFlickerProgram.Link(this, drawQuadVertexShader, drawQuadPaletteFlickerPixelShader) + if (!m_res.m_drawQuadPaletteFlickerProgram.Link(this, drawQuadVertexShader, drawQuadPaletteFlickerPixelShader) + || !m_res.m_drawQuadPaletteNoFlickerProgram.Link(this, drawQuadVertexShader, drawQuadPaletteFlickerPixelShader) //|| !m_drawQuadRGBProgram.Link(this, drawQuadVertexShader, drawQuadRGBPixelShader) //|| !m_drawQuad15BitProgram.Link(this, drawQuadVertexShader, drawQuad15BitPixelShader) - || !m_drawQuadPaletteICCFlickerProgram.Link(this, drawQuadVertexShader, drawQuadPaletteICCFPixelShader) - || !m_drawQuadPaletteICCNoFlickerProgram.Link(this, drawQuadVertexShader, drawQuadPaletteICCNFPixelShader) + || !m_res.m_drawQuadPaletteICCFlickerProgram.Link(this, drawQuadVertexShader, drawQuadPaletteICCFPixelShader) + || !m_res.m_drawQuadPaletteICCNoFlickerProgram.Link(this, drawQuadVertexShader, drawQuadPaletteICCNFPixelShader) //|| !m_drawQuadRGBICCProgram.Link(this, drawQuadVertexShader, drawQuadRGBICCPixelShader) //|| !m_drawQuad15BitICCProgram.Link(this, drawQuadVertexShader, drawQuad15BitICCPixelShader) - || !m_scaleQuadProgram.Link(this, drawQuadVertexShader, scaleQuadPixelShader) - || !m_copyQuadProgram.Link(this, drawQuadVertexShader, copyQuadPixelShader)) + || !m_res.m_scaleQuadProgram.Link(this, drawQuadVertexShader, scaleQuadPixelShader) + || !m_res.m_copyQuadProgram.Link(this, drawQuadVertexShader, copyQuadPixelShader)) return false; - - // Palette texture { - uint8_t initialDataBytes[256][4]; - for (int i = 0; i < 256; i++) - { - for (int ch = 0; ch < 4; ch++) - initialDataBytes[i][ch] = 255; - } - - m_paletteTexture = GpGLTexture::Create(this); - if (!m_paletteTexture) + m_res.m_paletteTexture = GpGLTexture::Create(this); + if (!m_res.m_paletteTexture) { if (logger) logger->Printf(IGpLogDriver::Category_Error, "GpDisplayDriver_SDL_GL2::InitResources: GpGLTexture::Create failed"); @@ -2264,9 +2403,9 @@ bool GpDisplayDriver_SDL_GL2::InitResources(uint32_t virtualWidth, uint32_t virt return false; } - m_gl.BindTexture(GL_TEXTURE_2D, m_paletteTexture->GetID()); + m_gl.BindTexture(GL_TEXTURE_2D, m_res.m_paletteTexture->GetID()); m_gl.PixelStorei(GL_UNPACK_ALIGNMENT, 1); - m_gl.TexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 256, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, initialDataBytes); + m_gl.TexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 256, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, m_paletteData); m_gl.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); m_gl.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); m_gl.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); @@ -2387,14 +2526,10 @@ bool GpDisplayDriver_SDL_GL2::ResizeOpenGLWindow(uint32_t &windowWidth, uint32_t if (logger) logger->Printf(IGpLogDriver::Category_Information, "ResizeOpenGLWindow: %i x %i", static_cast(desiredWidth), static_cast(desiredHeight)); - if (desiredWidth < 640) - desiredWidth = 640; - else if (desiredWidth > 32768) + if (desiredWidth > 32768) desiredWidth = 32768; - if (desiredHeight < 480) - desiredHeight = 480; - else if (desiredHeight > 32768) + if (desiredHeight > 32768) desiredHeight = 32768; if (logger) @@ -2416,8 +2551,8 @@ bool GpDisplayDriver_SDL_GL2::InitBackBuffer(uint32_t width, uint32_t height) logger->Printf(IGpLogDriver::Category_Information, "GpDisplayDriver_SDL_GL2::InitBackBuffer"); { - m_virtualScreenTexture = GpGLTexture::Create(this); - if (!m_virtualScreenTexture) + m_res.m_virtualScreenTexture = GpGLTexture::Create(this); + if (!m_res.m_virtualScreenTexture) { if (logger) logger->Printf(IGpLogDriver::Category_Error, "GpDisplayDriver_SDL_GL2::InitBackBuffer: GpGLTexture::Create for virtual screen texture failed"); @@ -2425,7 +2560,7 @@ bool GpDisplayDriver_SDL_GL2::InitBackBuffer(uint32_t width, uint32_t height) return false; } - m_gl.BindTexture(GL_TEXTURE_2D, m_virtualScreenTexture->GetID()); + m_gl.BindTexture(GL_TEXTURE_2D, m_res.m_virtualScreenTexture->GetID()); m_gl.PixelStorei(GL_UNPACK_ALIGNMENT, 1); m_gl.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); m_gl.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); @@ -2436,9 +2571,9 @@ bool GpDisplayDriver_SDL_GL2::InitBackBuffer(uint32_t width, uint32_t height) } { - m_virtualScreenTextureRTV = GpGLRenderTargetView::Create(this); + m_res.m_virtualScreenTextureRTV = GpGLRenderTargetView::Create(this); - if (!m_virtualScreenTextureRTV) + if (!m_res.m_virtualScreenTextureRTV) { if (logger) logger->Printf(IGpLogDriver::Category_Error, "GpDisplayDriver_SDL_GL2::InitBackBuffer: GpGLRenderTargetView::Create for virtual screen texture failed"); @@ -2446,8 +2581,8 @@ bool GpDisplayDriver_SDL_GL2::InitBackBuffer(uint32_t width, uint32_t height) return false; } - m_gl.BindFramebuffer(GL_FRAMEBUFFER, m_virtualScreenTextureRTV->GetID()); - m_gl.FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_virtualScreenTexture->GetID(), 0); + m_gl.BindFramebuffer(GL_FRAMEBUFFER, m_res.m_virtualScreenTextureRTV->GetID()); + m_gl.FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_res.m_virtualScreenTexture->GetID(), 0); GLenum status = m_gl.CheckFramebufferStatus(GL_FRAMEBUFFER); if (status != GL_FRAMEBUFFER_COMPLETE) @@ -2471,7 +2606,7 @@ void GpDisplayDriver_SDL_GL2::ScaleVirtualScreen() const bool isIntegralScale = (m_pixelScaleX == floor(m_pixelScaleX) && m_pixelScaleY == floor(m_pixelScaleY)); - const BlitQuadProgram &program = isIntegralScale ? m_copyQuadProgram : m_scaleQuadProgram; + const BlitQuadProgram &program = isIntegralScale ? m_res.m_copyQuadProgram : m_res.m_scaleQuadProgram; { const float twoDivWidth = 2.0f / static_cast(m_windowWidthPhysical); @@ -2514,13 +2649,13 @@ void GpDisplayDriver_SDL_GL2::ScaleVirtualScreen() GLint attribLocations[] = { program.m_vertexPosUVLocation }; - m_quadVertexArray->Activate(attribLocations); + m_res.m_quadVertexArray->Activate(attribLocations); m_gl.ActiveTexture(GL_TEXTURE0 + 0); - m_gl.BindTexture(GL_TEXTURE_2D, m_virtualScreenTexture->GetID()); + m_gl.BindTexture(GL_TEXTURE_2D, m_res.m_virtualScreenTexture->GetID()); m_gl.Uniform1i(program.m_pixelSurfaceTextureLocation, 0); - m_gl.BindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_quadIndexBuffer->GetID()); + m_gl.BindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_res.m_quadIndexBuffer->GetID()); m_gl.DrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, nullptr); m_gl.UseProgram(0); @@ -2528,7 +2663,7 @@ void GpDisplayDriver_SDL_GL2::ScaleVirtualScreen() m_gl.ActiveTexture(GL_TEXTURE0 + 0); m_gl.BindTexture(GL_TEXTURE_2D, 0); - m_quadVertexArray->Deactivate(attribLocations); + m_res.m_quadVertexArray->Deactivate(attribLocations); m_gl.BindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); } @@ -2631,7 +2766,7 @@ GpDisplayDriverTickStatus_t GpDisplayDriver_SDL_GL2::PresentFrameAndSync() } //ID3D11RenderTargetView *const rtv = m_backBufferRTV; - GpGLRenderTargetView *const vsRTV = m_virtualScreenTextureRTV; + GpGLRenderTargetView *const vsRTV = m_res.m_virtualScreenTextureRTV; m_gl.BindFramebuffer(GL_FRAMEBUFFER, vsRTV->GetID()); diff --git a/GpApp/Environ.cpp b/GpApp/Environ.cpp index 70c01fe..e6fb291 100644 --- a/GpApp/Environ.cpp +++ b/GpApp/Environ.cpp @@ -326,25 +326,24 @@ public: void AdjustRequestedResolution(uint32_t &physicalWidth, uint32_t &physicalHeight, uint32_t &virtualWidth, uint32_t &virtualHeight, float &pixelScaleX, float &pixelScaleY) override { - if (physicalWidth < 640) - physicalWidth = 640; - - if (physicalHeight < 480) - physicalHeight = 480; - double minMul = 1.0; - if (isAutoScale) + if (isAutoScale || physicalWidth < 640 && physicalHeight < 480) { double xMul = static_cast(physicalWidth) / 640.0; double yMul = static_cast(physicalHeight) / 480.0; - double granularity = 2.0; + minMul = std::min(xMul, yMul); - xMul = floor(xMul * granularity) / granularity; - yMul = floor(yMul * granularity) / granularity; + if (minMul >= 1.0) + { + double granularity = 2.0; - minMul = std::max(1.0, std::min(xMul, yMul)); + xMul = floor(xMul * granularity) / granularity; + yMul = floor(yMul * granularity) / granularity; + + minMul = std::min(xMul, yMul); + } } virtualWidth = physicalWidth / minMul; diff --git a/GpApp/GpAppInterface.cpp b/GpApp/GpAppInterface.cpp index bed6391..73d8303 100644 --- a/GpApp/GpAppInterface.cpp +++ b/GpApp/GpAppInterface.cpp @@ -13,11 +13,14 @@ #include "WindowManager.h" int gpAppMain(); +void gpAppInit(); class GpAppInterfaceImpl final : public GpAppInterface { public: + void ApplicationInit() override; int ApplicationMain() override; + void PL_IncrementTickCounter(uint32_t count) override; void PL_Render(IGpDisplayDriver *displayDriver) override; void PL_HostFileSystem_SetInstance(PortabilityLayer::HostFileSystem *instance) override; @@ -32,6 +35,10 @@ public: bool PL_AdjustRequestedResolution(uint32_t &physicalWidth, uint32_t &physicalHeight, uint32_t &virtualWidth, uint32_t &virtualheight, float &pixelScaleX, float &pixelScaleY) override; }; +void GpAppInterfaceImpl::ApplicationInit() +{ + gpAppInit(); +} int GpAppInterfaceImpl::ApplicationMain() { diff --git a/GpApp/Main.cpp b/GpApp/Main.cpp index 7e5a4c9..de80256 100644 --- a/GpApp/Main.cpp +++ b/GpApp/Main.cpp @@ -19,6 +19,7 @@ #include "IGpDisplayDriver.h" #include "GpIOStream.h" #include "House.h" +#include "MenuManager.h" #include "RenderedFont.h" #include "ResolveCachingColor.h" #include "WindowManager.h" @@ -425,6 +426,12 @@ void PreloadFonts() StepLoadScreen(1); } +void gpAppInit() +{ + // This is called before the display driver is initialized + InstallResolutionHandler(); +} + //-------------------------------------------------------------- main // Here is main(). The first function called when Glider PRO comes up. @@ -439,7 +446,9 @@ int gpAppMain() ToolBoxInit(); CheckOurEnvirons(); - InstallResolutionHandler(); + + if (thisMac.isTouchscreen) + PortabilityLayer::MenuManager::GetInstance()->SetMenuTouchScreenStyle(true); if (!thisMac.hasColor) RedAlert(kErrNeedColorQD); diff --git a/GpApp/MainWindow.cpp b/GpApp/MainWindow.cpp index 81a71d3..daa7148 100644 --- a/GpApp/MainWindow.cpp +++ b/GpApp/MainWindow.cpp @@ -224,7 +224,10 @@ void OpenMainWindow (void) mainWindowRect.bottom - mainWindowRect.top, false); const short mainWindowLeft = (thisMac.fullScreen.left + thisMac.fullScreen.right + thisMac.constrainedScreen.left - thisMac.constrainedScreen.right) / 2; - const short mainWindowTop = (thisMac.fullScreen.top + thisMac.fullScreen.bottom + thisMac.constrainedScreen.top - thisMac.constrainedScreen.bottom) / 2 + kScoreboardTall; + short mainWindowTop = (thisMac.fullScreen.top + thisMac.fullScreen.bottom + thisMac.constrainedScreen.top - thisMac.constrainedScreen.bottom) / 2; + + if (!PortabilityLayer::MenuManager::GetInstance()->IsMenuTouchScreenStyle()) + mainWindowTop += kScoreboardTall; MoveWindow(boardWindow, mainWindowLeft, 0, true); MoveWindow(mainWindow, mainWindowLeft, mainWindowTop, true); // thisMac.menuHigh diff --git a/GpApp/SourceExport.cpp b/GpApp/SourceExport.cpp index 2a989c9..c8a01ba 100644 --- a/GpApp/SourceExport.cpp +++ b/GpApp/SourceExport.cpp @@ -711,7 +711,7 @@ bool ExportSourceToStream (GpIOStream *stream) void DoExportSourceCode (void) { - GpIOStream *stream = PortabilityLayer::HostFileSystem::GetInstance()->OpenFile(PortabilityLayer::VirtualDirectories::kPrefs, "SourceExport.zip", true, GpFileCreationDispositions::kCreateOrOverwrite); + GpIOStream *stream = PortabilityLayer::HostFileSystem::GetInstance()->OpenFile(PortabilityLayer::VirtualDirectories::kSourceExport, "SourceExport.zip", true, GpFileCreationDispositions::kCreateOrOverwrite); if (!stream) return; diff --git a/GpCommon/IGpDisplayDriver.h b/GpCommon/IGpDisplayDriver.h index a8cc3c2..b565b5b 100644 --- a/GpCommon/IGpDisplayDriver.h +++ b/GpCommon/IGpDisplayDriver.h @@ -26,13 +26,14 @@ struct GpDisplayDriverSurfaceEffects // Display drivers are responsible for timing and calling the game tick function. struct IGpDisplayDriver { -public: + typedef void (*SurfaceInvalidateCallback_t) (void *context); + virtual void Run() = 0; virtual void Shutdown() = 0; virtual void GetDisplayResolution(unsigned int *width, unsigned int *height) = 0; - virtual IGpDisplayDriverSurface *CreateSurface(size_t width, size_t height, size_t pitch, GpPixelFormat_t pixelFormat) = 0; + virtual IGpDisplayDriverSurface *CreateSurface(size_t width, size_t height, size_t pitch, GpPixelFormat_t pixelFormat, SurfaceInvalidateCallback_t invalidateCallback, void *invalidateContext) = 0; virtual void DrawSurface(IGpDisplayDriverSurface *surface, int32_t x, int32_t y, size_t width, size_t height, const GpDisplayDriverSurfaceEffects *effects) = 0; virtual IGpCursor *CreateBWCursor(size_t width, size_t height, const void *pixelData, const void *maskData, size_t hotSpotX, size_t hotSpotY) = 0; diff --git a/GpCommon/IGpThreadRelay.h b/GpCommon/IGpThreadRelay.h new file mode 100644 index 0000000..0a014ef --- /dev/null +++ b/GpCommon/IGpThreadRelay.h @@ -0,0 +1,8 @@ +#pragma once + +struct IGpThreadRelay +{ + typedef void (*Callback_t) (void *context); + + virtual void Invoke(Callback_t callback, void *context) const = 0; +}; diff --git a/GpDisplayDriver_D3D11/GpDisplayDriverD3D11.cpp b/GpDisplayDriver_D3D11/GpDisplayDriverD3D11.cpp index bcc71ba..bbb4482 100644 --- a/GpDisplayDriver_D3D11/GpDisplayDriverD3D11.cpp +++ b/GpDisplayDriver_D3D11/GpDisplayDriverD3D11.cpp @@ -1248,7 +1248,7 @@ void GpDisplayDriverD3D11::GetDisplayResolution(unsigned int *width, unsigned in *height = m_windowHeightVirtual; } -IGpDisplayDriverSurface *GpDisplayDriverD3D11::CreateSurface(size_t width, size_t height, size_t pitch, GpPixelFormat_t pixelFormat) +IGpDisplayDriverSurface *GpDisplayDriverD3D11::CreateSurface(size_t width, size_t height, size_t pitch, GpPixelFormat_t pixelFormat, IGpDisplayDriver::SurfaceInvalidateCallback_t invalidateCallback, void *invalidateContext) { return GpDisplayDriverSurfaceD3D11::Create(m_device, m_deviceContext, width, height, pixelFormat); } diff --git a/GpDisplayDriver_D3D11/GpDisplayDriverD3D11.h b/GpDisplayDriver_D3D11/GpDisplayDriverD3D11.h index 5305ed5..6ca540e 100644 --- a/GpDisplayDriver_D3D11/GpDisplayDriverD3D11.h +++ b/GpDisplayDriver_D3D11/GpDisplayDriverD3D11.h @@ -41,7 +41,7 @@ public: void GetDisplayResolution(unsigned int *width, unsigned int *height) override; - IGpDisplayDriverSurface *CreateSurface(size_t width, size_t height, size_t pitch, GpPixelFormat_t pixelFormat) override; + IGpDisplayDriverSurface *CreateSurface(size_t width, size_t height, size_t pitch, GpPixelFormat_t pixelFormat, IGpDisplayDriver::SurfaceInvalidateCallback_t invalidateCallback, void *invalidateContext) override; void DrawSurface(IGpDisplayDriverSurface *surface, int32_t x, int32_t y, size_t width, size_t height, const GpDisplayDriverSurfaceEffects *effects) override; IGpCursor *CreateColorCursor(size_t width, size_t height, const void *pixelDataRGBA, size_t hotSpotX, size_t hotSpotY) override; diff --git a/GpShell/GpAppEnvironment.cpp b/GpShell/GpAppEnvironment.cpp index 8c00ab8..3f0c115 100644 --- a/GpShell/GpAppEnvironment.cpp +++ b/GpShell/GpAppEnvironment.cpp @@ -34,6 +34,7 @@ GpAppEnvironment::~GpAppEnvironment() void GpAppEnvironment::Init() { + GpAppInterface_Get()->ApplicationInit(); } GpDisplayDriverTickStatus_t GpAppEnvironment::Tick(IGpFiber *vosFiber) @@ -196,7 +197,7 @@ void GpAppEnvironment::DispatchSystemCall(PortabilityLayer::HostSuspendCallID ca m_delaySuspendTicks = 1; break; case PortabilityLayer::HostSuspendCallID_CallOnVOSThread: - args[0].m_functionPtr(static_cast(args[1].m_constPointer), static_cast(args[2].m_pointer)); + args[0].m_functionPtr(args[1].m_pointer); m_applicationState = ApplicationState_Running; break; default: diff --git a/PortabilityLayer/BinHex4.h b/PortabilityLayer/BinHex4.h index 2aa8110..10aaebe 100644 --- a/PortabilityLayer/BinHex4.h +++ b/PortabilityLayer/BinHex4.h @@ -1,18 +1,18 @@ -#pragma once - -#ifndef __PL_BINHEX4_H__ +#pragma once + +#ifndef __PL_BINHEX4_H__ #define __PL_BINHEX4_H__ - -class GpIOStream; - -namespace PortabilityLayer -{ - class MacFileMem; - - namespace BinHex4 - { - MacFileMem *LoadHQX(GpIOStream *stream); - }; -} - -#endif + +class GpIOStream; + +namespace PortabilityLayer +{ + class MacFileMem; + + namespace BinHex4 + { + MacFileMem *LoadHQX(GpIOStream *stream); + }; +} + +#endif diff --git a/PortabilityLayer/GpAppInterface.h b/PortabilityLayer/GpAppInterface.h index e589e19..e907e5d 100644 --- a/PortabilityLayer/GpAppInterface.h +++ b/PortabilityLayer/GpAppInterface.h @@ -37,6 +37,7 @@ struct IGpDisplayDriver; class GpAppInterface { public: + virtual void ApplicationInit() = 0; virtual int ApplicationMain() = 0; virtual void PL_IncrementTickCounter(uint32_t count) = 0; virtual void PL_Render(IGpDisplayDriver *displayDriver) = 0; diff --git a/PortabilityLayer/HostFileSystem.h b/PortabilityLayer/HostFileSystem.h index 94b83d6..5a6ff4c 100644 --- a/PortabilityLayer/HostFileSystem.h +++ b/PortabilityLayer/HostFileSystem.h @@ -6,6 +6,7 @@ #include class GpIOStream; +struct IGpThreadRelay; namespace PortabilityLayer { @@ -31,6 +32,8 @@ namespace PortabilityLayer GpIOStream *OpenFile(VirtualDirectory_t virtualDirectory, const char *path, bool writeAccess, GpFileCreationDisposition_t createDisposition); + virtual void SetMainThreadRelay(IGpThreadRelay *relay) = 0; + private: static HostFileSystem *ms_instance; }; diff --git a/PortabilityLayer/HostSuspendCallArgument.h b/PortabilityLayer/HostSuspendCallArgument.h index 364700d..9c3432c 100644 --- a/PortabilityLayer/HostSuspendCallArgument.h +++ b/PortabilityLayer/HostSuspendCallArgument.h @@ -13,6 +13,6 @@ namespace PortabilityLayer size_t m_size; void *m_pointer; const void *m_constPointer; - void (*m_functionPtr)(const HostSuspendCallArgument *args, HostSuspendCallArgument *returnValue); + void (*m_functionPtr)(void *context); }; } diff --git a/PortabilityLayer/HostSuspendCallID.h b/PortabilityLayer/HostSuspendCallID.h index de203db..c524548 100644 --- a/PortabilityLayer/HostSuspendCallID.h +++ b/PortabilityLayer/HostSuspendCallID.h @@ -1,17 +1,17 @@ -#pragma once -#ifndef __PL_HOST_API_CALL_ID_H__ -#define __PL_HOST_API_CALL_ID_H__ - -namespace PortabilityLayer -{ - enum HostSuspendCallID - { - HostSuspendCallID_Unknown, - - HostSuspendCallID_Delay, +#pragma once +#ifndef __PL_HOST_API_CALL_ID_H__ +#define __PL_HOST_API_CALL_ID_H__ + +namespace PortabilityLayer +{ + enum HostSuspendCallID + { + HostSuspendCallID_Unknown, + + HostSuspendCallID_Delay, HostSuspendCallID_CallOnVOSThread, - HostSuspendCallID_ForceSyncFrame - }; -} - -#endif + HostSuspendCallID_ForceSyncFrame + }; +} + +#endif diff --git a/PortabilityLayer/MenuManager.cpp b/PortabilityLayer/MenuManager.cpp index 53790e0..61183ba 100644 --- a/PortabilityLayer/MenuManager.cpp +++ b/PortabilityLayer/MenuManager.cpp @@ -159,6 +159,9 @@ namespace PortabilityLayer void RenderFrame(IGpDisplayDriver *displayDriver) override; + void SetMenuTouchScreenStyle(bool isTouchScreen) override; + bool IsMenuTouchScreenStyle() const override; + static MenuManagerImpl *GetInstance(); private: @@ -199,13 +202,18 @@ namespace PortabilityLayer void ProcessMouseMoveToMenuBar(const Vec2i &point); void ProcessMouseMoveToMenu(const Vec2i &point); + bool IsYInMenuBarRange(int32_t y) const; + static bool ItemIsSeparator(const Menu &menu, const MenuItem &item); static const unsigned int kIconResID = 128; static const unsigned int kMenuFontSize = 12; + static const unsigned int kTouchScreenMenuFontSize = 24; static const unsigned int kMenuBarIconYOffset = 2; static const unsigned int kMenuBarTextYOffset = 14; + static const unsigned int kTouchScreenMenuBarTextYOffset = 26; static const unsigned int kMenuBarHeight = 20; + static const unsigned int kTouchscreenMenuBarHeight = 38; static const unsigned int kMenuBarItemPadding = 6; static const unsigned int kMenuBarInitialPadding = 16; @@ -223,6 +231,7 @@ namespace PortabilityLayer static const unsigned int kMenuItemLeftPadding = 16 + 2 + 2; // 2 for left border, 16 for icon, 2 for spacing static const int kMenuFontFlags = PortabilityLayer::FontFamilyFlag_Bold; + static const int kTouchScreenMenuFontFlags = PortabilityLayer::FontFamilyFlag_None; DrawSurface *m_menuBarGraf; @@ -231,6 +240,7 @@ namespace PortabilityLayer bool m_haveMenuBarLayout; bool m_haveIcon; bool m_menuBarVisible; + bool m_isTouchScreen; uint8_t m_iconColors[16 * 16]; uint8_t m_iconMask[32]; @@ -252,6 +262,7 @@ namespace PortabilityLayer , m_haveIcon(false) , m_iconGraphic(nullptr) , m_menuBarVisible(false) + , m_isTouchScreen(false) { } @@ -634,7 +645,7 @@ namespace PortabilityLayer bool MenuManagerImpl::IsPointInMenuBar(const Vec2i &point) const { - return point.m_y >= 0 && static_cast(point.m_y) < kMenuBarHeight; + return IsYInMenuBarRange(point.m_y); } uint16_t MenuManagerImpl::GetMenuBarHeight() const @@ -829,7 +840,9 @@ namespace PortabilityLayer PortabilityLayer::QDManager *qdManager = PortabilityLayer::QDManager::GetInstance(); - const Rect menuRect = Rect::Create(0, 0, kMenuBarHeight, width); + const int16_t menuHeight = m_isTouchScreen ? kTouchscreenMenuBarHeight : kMenuBarHeight; + + const Rect menuRect = Rect::Create(0, 0, menuHeight, width); if (m_menuBarGraf == nullptr) { @@ -863,7 +876,7 @@ namespace PortabilityLayer // Left stripe { - const Rect rect = Rect::Create(0, 0, kMenuBarHeight - 1, 1); + const Rect rect = Rect::Create(0, 0, menuHeight - 1, 1); m_menuBarGraf->FillRect(rect, barBrightColor); } @@ -871,13 +884,13 @@ namespace PortabilityLayer // Bottom stripe { - const Rect rect = Rect::Create(kMenuBarHeight - 2, 1, kMenuBarHeight - 1, width); + const Rect rect = Rect::Create(menuHeight - 2, 1, menuHeight - 1, width); m_menuBarGraf->FillRect(rect, barDarkColor); } // Right stripe { - const Rect rect = Rect::Create(0, width - 1, kMenuBarHeight - 1, width); + const Rect rect = Rect::Create(0, width - 1, menuHeight - 1, width); m_menuBarGraf->FillRect(rect, barDarkColor); } @@ -885,7 +898,7 @@ namespace PortabilityLayer // Bottom edge { - const Rect rect = Rect::Create(kMenuBarHeight - 1, 0, kMenuBarHeight, width); + const Rect rect = Rect::Create(menuHeight - 1, 0, menuHeight, width); m_menuBarGraf->FillRect(rect, barBottomEdgeColor); } @@ -917,20 +930,31 @@ namespace PortabilityLayer // Middle { ResolveCachingColor barHighlightMidColor = gs_barHighlightMidColor; - const Rect rect = Rect::Create(1, left, kMenuBarHeight - 2, right); + const Rect rect = Rect::Create(1, left, menuHeight - 2, right); m_menuBarGraf->FillRect(rect, barHighlightMidColor); } { ResolveCachingColor barHighlightDarkColor = gs_barHighlightDarkColor; - const Rect rect = Rect::Create(kMenuBarHeight - 2, left, kMenuBarHeight - 1, right); + const Rect rect = Rect::Create(menuHeight - 2, left, menuHeight - 1, right); m_menuBarGraf->FillRect(rect, barHighlightDarkColor); } } // Text items ResolveCachingColor barNormalTextColor = gs_barNormalTextColor; - PortabilityLayer::RenderedFont *sysFont = GetSystemFont(kMenuFontSize, PortabilityLayer::FontFamilyFlag_Bold, true); + PortabilityLayer::RenderedFont *sysFont = nullptr; + unsigned int textYOffset = 0; + if (m_isTouchScreen) + { + sysFont = GetApplicationFont(kTouchScreenMenuFontSize, kTouchScreenMenuFontFlags, true); + textYOffset = kTouchScreenMenuBarTextYOffset; + } + else + { + sysFont = GetSystemFont(kMenuFontSize, kMenuFontFlags, true); + textYOffset = kMenuBarTextYOffset; + } { Menu **menuHdl = m_firstMenu; @@ -951,7 +975,7 @@ namespace PortabilityLayer { if (menuHdl != selectedMenuHdl) { - const Point itemPos = Point::Create(static_cast(xCoordinate), kMenuBarTextYOffset); + const Point itemPos = Point::Create(static_cast(xCoordinate), textYOffset); graf->DrawString(itemPos, PLPasStr(static_cast(menu->stringBlobHandle->m_contents)), barNormalTextColor, sysFont); } } @@ -971,7 +995,7 @@ namespace PortabilityLayer size_t xCoordinate = menu->cumulativeOffset + (menu->menuIndex * 2) * kMenuBarItemPadding + kMenuBarInitialPadding; - const Point itemPos = Point::Create(static_cast(xCoordinate), kMenuBarTextYOffset); + const Point itemPos = Point::Create(static_cast(xCoordinate), textYOffset); graf->DrawString(itemPos, PLPasStr(static_cast(menu->stringBlobHandle->m_contents)), barHighlightTextColor, sysFont); } } @@ -1001,7 +1025,16 @@ namespace PortabilityLayer const PixMap *pixMap = *m_menuBarGraf->m_port.GetPixMap(); const size_t width = pixMap->m_rect.right - pixMap->m_rect.left; const size_t height = pixMap->m_rect.bottom - pixMap->m_rect.top; - displayDriver->DrawSurface(m_menuBarGraf->m_ddSurface, 0, 0, width, height, nullptr); + int32_t y = 0; + + if (m_isTouchScreen) + { + unsigned int displayHeight = 0; + displayDriver->GetDisplayResolution(nullptr, &displayHeight); + y = static_cast(displayHeight) - kTouchscreenMenuBarHeight; + } + + displayDriver->DrawSurface(m_menuBarGraf->m_ddSurface, 0, y, width, height, nullptr); } } @@ -1030,6 +1063,16 @@ namespace PortabilityLayer } } + void MenuManagerImpl::SetMenuTouchScreenStyle(bool isTouchScreenStyle) + { + m_isTouchScreen = isTouchScreenStyle; + } + + bool MenuManagerImpl::IsMenuTouchScreenStyle() const + { + return m_isTouchScreen; + } + void MenuManagerImpl::RefreshMenuBarLayout() { if (m_haveMenuBarLayout) @@ -1037,11 +1080,29 @@ namespace PortabilityLayer PortabilityLayer::FontManager *fontManager = PortabilityLayer::FontManager::GetInstance(); - PortabilityLayer::FontFamily *fontFamily = PortabilityLayer::FontManager::GetInstance()->GetSystemFont(kMenuFontSize, kMenuFontFlags); + PortabilityLayer::FontFamily *fontFamily = nullptr; + + unsigned int fontSize = 0; + unsigned int fontFlags = 0; + + if (m_isTouchScreen) + { + fontSize = kTouchScreenMenuFontSize; + fontFlags = PortabilityLayer::FontFamilyFlag_None; + fontFamily = PortabilityLayer::FontManager::GetInstance()->GetApplicationFont(kTouchScreenMenuFontSize, PortabilityLayer::FontFamilyFlag_None); + } + else + { + fontSize = kMenuFontSize; + fontFlags = kMenuFontFlags; + fontFamily = PortabilityLayer::FontManager::GetInstance()->GetSystemFont(kMenuFontSize, kMenuFontFlags); + } + + if (!fontFamily) return; - PortabilityLayer::RenderedFont *rfont = PortabilityLayer::FontManager::GetInstance()->GetRenderedFontFromFamily(fontFamily, kMenuFontSize, true, kMenuFontFlags); + PortabilityLayer::RenderedFont *rfont = PortabilityLayer::FontManager::GetInstance()->GetRenderedFontFromFamily(fontFamily, fontSize, true, fontFlags); if (!rfont) return; @@ -1137,7 +1198,7 @@ namespace PortabilityLayer if (point.m_y < 0) return; - if (!m_menuSelectionState.IsPopup() && point.m_y < static_cast(kMenuBarHeight)) + if (!m_menuSelectionState.IsPopup() && IsYInMenuBarRange(point.m_y)) { m_menuSelectionState.ClearSelection(); ProcessMouseMoveToMenuBar(point); @@ -1235,6 +1296,18 @@ namespace PortabilityLayer m_menuSelectionState.ClearSelection(); } + bool MenuManagerImpl::IsYInMenuBarRange(int32_t y) const + { + if (m_isTouchScreen) + { + unsigned int displayHeight = 0; + PortabilityLayer::HostDisplayDriver::GetInstance()->GetDisplayResolution(nullptr, &displayHeight); + return y >= (static_cast(displayHeight - kTouchscreenMenuBarHeight)) && y < static_cast(displayHeight); + } + else + return y >= 0 && y < static_cast(kMenuBarHeight); + } + bool MenuManagerImpl::ItemIsSeparator(const Menu &menu, const MenuItem &item) { const uint8_t *strBlob = static_cast(menu.stringBlobHandle->m_contents); diff --git a/PortabilityLayer/MenuManager.h b/PortabilityLayer/MenuManager.h index 6a36d9e..061e8c9 100644 --- a/PortabilityLayer/MenuManager.h +++ b/PortabilityLayer/MenuManager.h @@ -54,6 +54,9 @@ namespace PortabilityLayer virtual void RenderFrame(IGpDisplayDriver *displayDriver) = 0; + virtual void SetMenuTouchScreenStyle(bool isTouchScreenStyle) = 0; + virtual bool IsMenuTouchScreenStyle() const = 0; + static MenuManager *GetInstance(); }; } diff --git a/PortabilityLayer/PLCore.cpp b/PortabilityLayer/PLCore.cpp index b21ea99..66d9c2a 100644 --- a/PortabilityLayer/PLCore.cpp +++ b/PortabilityLayer/PLCore.cpp @@ -21,6 +21,7 @@ #include "HostVOSEventQueue.h" #include "IGpCursor.h" #include "IGpDisplayDriver.h" +#include "IGpThreadRelay.h" #include "InputManager.h" #include "ResourceManager.h" #include "MacFileInfo.h" @@ -47,6 +48,29 @@ #include #include +class PLMainThreadRelay final : public IGpThreadRelay +{ +public: + void Invoke(Callback_t callback, void *context) const override; + + static PLMainThreadRelay *GetInstance(); + +private: + static PLMainThreadRelay ms_instance; +}; + +void PLMainThreadRelay::Invoke(Callback_t callback, void *context) const +{ + PLSysCalls::RunOnVOSThread(callback, context); +} + +PLMainThreadRelay *PLMainThreadRelay::GetInstance() +{ + return &ms_instance; +} + +PLMainThreadRelay PLMainThreadRelay::ms_instance; + static bool ConvertFilenameToSafePStr(const char *str, uint8_t *pstr) { const char *strBase = str; @@ -650,6 +674,8 @@ void PL_Init() PortabilityLayer::DisplayDeviceManager::GetInstance()->Init(); PortabilityLayer::QDManager::GetInstance()->Init(); PortabilityLayer::MenuManager::GetInstance()->Init(); + + PortabilityLayer::HostFileSystem::GetInstance()->SetMainThreadRelay(PLMainThreadRelay::GetInstance()); } WindowPtr PL_GetPutInFrontWindowPtr() diff --git a/PortabilityLayer/PLSysCalls.cpp b/PortabilityLayer/PLSysCalls.cpp index 92ff313..a01cb6b 100644 --- a/PortabilityLayer/PLSysCalls.cpp +++ b/PortabilityLayer/PLSysCalls.cpp @@ -189,4 +189,13 @@ namespace PLSysCalls { PortabilityLayer::SuspendApplication(PortabilityLayer::HostSuspendCallID_ForceSyncFrame, nullptr, nullptr); } + + void RunOnVOSThread(void(*callback)(void *context), void *context) + { + PortabilityLayer::HostSuspendCallArgument args[2]; + args[0].m_functionPtr = callback; + args[1].m_pointer = context; + + PortabilityLayer::SuspendApplication(PortabilityLayer::HostSuspendCallID_CallOnVOSThread, args, nullptr); + } } diff --git a/PortabilityLayer/PLSysCalls.h b/PortabilityLayer/PLSysCalls.h index 98c6b53..c332bd6 100644 --- a/PortabilityLayer/PLSysCalls.h +++ b/PortabilityLayer/PLSysCalls.h @@ -8,4 +8,5 @@ namespace PLSysCalls { void Sleep(uint32_t ticks); void ForceSyncFrame(); + void RunOnVOSThread(void(*callback)(void *context), void *context); } diff --git a/PortabilityLayer/QDGraf.cpp b/PortabilityLayer/QDGraf.cpp index 8c48f0f..2e9c7ef 100644 --- a/PortabilityLayer/QDGraf.cpp +++ b/PortabilityLayer/QDGraf.cpp @@ -28,7 +28,7 @@ void DrawSurface::PushToDDSurface(IGpDisplayDriver *displayDriver) } if (m_ddSurface == nullptr) - m_ddSurface = displayDriver->CreateSurface(pixMap->m_rect.right - pixMap->m_rect.left, pixMap->m_rect.bottom - pixMap->m_rect.top, pixMap->m_pitch, pixMap->m_pixelFormat); + m_ddSurface = displayDriver->CreateSurface(pixMap->m_rect.right - pixMap->m_rect.left, pixMap->m_rect.bottom - pixMap->m_rect.top, pixMap->m_pitch, pixMap->m_pixelFormat, DrawSurface::StaticOnDriverInvalidate, this); if (m_port.IsDirty(PortabilityLayer::QDPortDirtyFlag_Contents) && m_ddSurface != nullptr) { @@ -36,3 +36,13 @@ void DrawSurface::PushToDDSurface(IGpDisplayDriver *displayDriver) m_port.ClearDirty(PortabilityLayer::QDPortDirtyFlag_Contents); } } + +void DrawSurface::StaticOnDriverInvalidate(void *context) +{ + static_cast(context)->OnDriverInvalidate(); +} + +void DrawSurface::OnDriverInvalidate() +{ + m_port.SetDirty(PortabilityLayer::QDPortDirtyFlag_Contents); +} diff --git a/PortabilityLayer/QDGraf.h b/PortabilityLayer/QDGraf.h index f3b419d..b9ebd53 100644 --- a/PortabilityLayer/QDGraf.h +++ b/PortabilityLayer/QDGraf.h @@ -89,4 +89,8 @@ struct DrawSurface PortabilityLayer::RGBAColor m_cachedAAColor; PortabilityLayer::QDPort m_port; + +private: + static void StaticOnDriverInvalidate(void *context); + void OnDriverInvalidate(); }; diff --git a/PortabilityLayer/VirtualDirectory.h b/PortabilityLayer/VirtualDirectory.h index 344b1cc..1f426ee 100644 --- a/PortabilityLayer/VirtualDirectory.h +++ b/PortabilityLayer/VirtualDirectory.h @@ -17,6 +17,8 @@ namespace PortabilityLayer kCursors, kHighScores, kLogs, + + kSourceExport, }; } diff --git a/PortabilityLayer/WindowManager.cpp b/PortabilityLayer/WindowManager.cpp index 4d26a76..e2e23af 100644 --- a/PortabilityLayer/WindowManager.cpp +++ b/PortabilityLayer/WindowManager.cpp @@ -1434,6 +1434,7 @@ namespace PortabilityLayer void WindowManagerImpl::HandleScreenResolutionChange(uint32_t prevWidth, uint32_t prevHeight, uint32_t newWidth, uint32_t newHeight) { const uint32_t menuBarHeight = PortabilityLayer::MenuManager::GetInstance()->GetMenuBarHeight(); + const bool menuIsTouchScreen = PortabilityLayer::MenuManager::GetInstance()->IsMenuTouchScreenStyle(); for (PortabilityLayer::WindowImpl *window = m_windowStackTop; window != nullptr; window = window->GetWindowBelow()) { @@ -1457,17 +1458,37 @@ namespace PortabilityLayer int64_t newY = 0; int32_t currentY = window->GetPosition().m_y; - if (currentY < static_cast(menuBarHeight)) - newY = currentY; - else + if (!menuIsTouchScreen) { - if (newHeight <= (paddedHeight + menuBarHeight) || prevHeight <= paddedHeight + menuBarHeight) - newY = (static_cast(newHeight) - paddedHeight - menuBarHeight) / 2 + menuBarHeight; + if (currentY < static_cast(menuBarHeight)) + newY = currentY; else { - uint32_t prevClearanceY = prevHeight - paddedHeight - menuBarHeight; - uint32_t newClearanceY = newHeight - paddedHeight - menuBarHeight; - newY = (static_cast(currentY) - static_cast(menuBarHeight) - chromePadding[WindowChromeSides::kTop]) * static_cast(newClearanceY) / static_cast(prevClearanceY) + menuBarHeight + chromePadding[WindowChromeSides::kTop]; + if (newHeight <= (paddedHeight + menuBarHeight) || prevHeight <= paddedHeight + menuBarHeight) + newY = (static_cast(newHeight) - paddedHeight - menuBarHeight) / 2 + menuBarHeight; + else + { + uint32_t prevClearanceY = prevHeight - paddedHeight - menuBarHeight; + uint32_t newClearanceY = newHeight - paddedHeight - menuBarHeight; + newY = (static_cast(currentY) - static_cast(menuBarHeight) - chromePadding[WindowChromeSides::kTop]) * static_cast(newClearanceY) / static_cast(prevClearanceY) + menuBarHeight + chromePadding[WindowChromeSides::kTop]; + } + } + } + else + { + uint32_t heightWithoutMenu = surfaceRect.Height() - menuBarHeight; + if (currentY + static_cast(paddedHeight) >= heightWithoutMenu) + newY = currentY; + else + { + if (newHeight <= (paddedHeight + menuBarHeight) || prevHeight <= paddedHeight + menuBarHeight) + newY = (static_cast(newHeight) - paddedHeight - menuBarHeight) / 2 + menuBarHeight; + else + { + uint32_t prevClearanceY = prevHeight - paddedHeight - menuBarHeight; + uint32_t newClearanceY = newHeight - paddedHeight - menuBarHeight; + newY = (static_cast(currentY) - static_cast(menuBarHeight) - chromePadding[WindowChromeSides::kTop]) * static_cast(newClearanceY) / static_cast(prevClearanceY) + chromePadding[WindowChromeSides::kTop]; + } } }