diff --git a/src/common/FBBackendSDL2.cxx b/src/common/FBBackendSDL2.cxx index b0b710ca4..c1204065e 100644 --- a/src/common/FBBackendSDL2.cxx +++ b/src/common/FBBackendSDL2.cxx @@ -71,6 +71,8 @@ FBBackendSDL2::~FBBackendSDL2() myWindow = nullptr; } SDL_QuitSubSystem(SDL_INIT_VIDEO | SDL_INIT_TIMER); + +cerr << "~FBBackendSDL2()" << endl; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/common/FBSurfaceSDL2.cxx b/src/common/FBSurfaceSDL2.cxx index cfb5d17b2..15923a099 100644 --- a/src/common/FBSurfaceSDL2.cxx +++ b/src/common/FBSurfaceSDL2.cxx @@ -40,6 +40,8 @@ namespace { } } +static int REF_COUNT = 0; + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - FBSurfaceSDL2::FBSurfaceSDL2(FBBackendSDL2& backend, uInt32 width, uInt32 height, @@ -48,6 +50,7 @@ FBSurfaceSDL2::FBSurfaceSDL2(FBBackendSDL2& backend, : myBackend{backend}, myInterpolationMode{inter} { +REF_COUNT++; createSurface(width, height, staticData); } @@ -58,6 +61,8 @@ FBSurfaceSDL2::~FBSurfaceSDL2() if(mySurface) { +REF_COUNT--; +cerr << " ~FBSurfaceSDL2(): " << this << " " << REF_COUNT << endl; SDL_FreeSurface(mySurface); mySurface = nullptr; } @@ -200,17 +205,10 @@ void FBSurfaceSDL2::invalidateRect(uInt32 x, uInt32 y, uInt32 w, uInt32 h) SDL_FillRect(mySurface, &tmp, 0); } -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void FBSurfaceSDL2::free() -{ - myBlitter.reset(); -} - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FBSurfaceSDL2::reload() { - free(); - reinitializeBlitter(); + reinitializeBlitter(true); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -221,8 +219,6 @@ void FBSurfaceSDL2::resize(uInt32 width, uInt32 height) if(mySurface) SDL_FreeSurface(mySurface); - free(); - // NOTE: Currently, a resize changes a 'static' surface to 'streaming' // No code currently does this, but we should at least check for it if(myIsStatic) @@ -260,12 +256,15 @@ void FBSurfaceSDL2::createSurface(uInt32 width, uInt32 height, if(myIsStatic) SDL_memcpy(mySurface->pixels, data, mySurface->w * mySurface->h * 4); - reinitializeBlitter(); + reload(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void FBSurfaceSDL2::reinitializeBlitter() +void FBSurfaceSDL2::reinitializeBlitter(bool force) { + if (force) + myBlitter.reset(); + if (!myBlitter && myBackend.isInitialized()) myBlitter = BlitterFactory::createBlitter( myBackend, scalingAlgorithm(myInterpolationMode)); diff --git a/src/common/FBSurfaceSDL2.hxx b/src/common/FBSurfaceSDL2.hxx index ae29c57f1..b0f5d792a 100644 --- a/src/common/FBSurfaceSDL2.hxx +++ b/src/common/FBSurfaceSDL2.hxx @@ -60,7 +60,6 @@ class FBSurfaceSDL2 : public FBSurface void invalidate() override; void invalidateRect(uInt32 x, uInt32 y, uInt32 w, uInt32 h) override; - void free() override; void reload() override; void resize(uInt32 width, uInt32 height) override; @@ -109,7 +108,7 @@ class FBSurfaceSDL2 : public FBSurface void createSurface(uInt32 width, uInt32 height, const uInt32* data); - void reinitializeBlitter(); + void reinitializeBlitter(bool force = false); // Following constructors and assignment operators not supported FBSurfaceSDL2() = delete; diff --git a/src/emucore/FBSurface.hxx b/src/emucore/FBSurface.hxx index 458349a1b..2e8bf383d 100644 --- a/src/emucore/FBSurface.hxx +++ b/src/emucore/FBSurface.hxx @@ -350,16 +350,8 @@ class FBSurface */ virtual void invalidateRect(uInt32 x, uInt32 y, uInt32 w, uInt32 h) = 0; - - /** - This method should be called to free any resources being used by - the surface. - */ - virtual void free() = 0; - /** This method should be called to reload the surface data/state. - It will normally be called after free(). */ virtual void reload() = 0; diff --git a/src/emucore/FrameBuffer.cxx b/src/emucore/FrameBuffer.cxx index dbb287220..47fd02d4b 100644 --- a/src/emucore/FrameBuffer.cxx +++ b/src/emucore/FrameBuffer.cxx @@ -71,7 +71,7 @@ FrameBuffer::~FrameBuffer() // Most platforms are fine with doing this in either order, but it seems // that OpenBSD in particular crashes when attempting to destroy textures // *after* the renderer is already destroyed - freeSurfaces(); +cerr << "~FrameBuffer()" << endl << endl; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -551,6 +551,7 @@ void FrameBuffer::updateInEmulationMode(float framesPerSecond) } #ifdef GUI_SUPPORT +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FrameBuffer::createMessage(const string& message, MessagePosition position, bool force) { // Only show messages if they've been enabled @@ -864,42 +865,61 @@ void FrameBuffer::setPauseDelay() } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -shared_ptr FrameBuffer::allocateSurface( - int w, int h, ScalingInterpolation inter, const uInt32* data -) +unique_ptr FrameBuffer::allocateSurface( + int w, int h, ScalingInterpolation inter, const uInt32* data) { - // Add new surface to the list - mySurfaceList.push_back(myBackend->createSurface(w, h, inter, data)); - - // And return a pointer to it (pointer should be treated read-only) - return mySurfaceList.at(mySurfaceList.size() - 1); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void FrameBuffer::freeSurfaces() -{ - for(auto& s: mySurfaceList) - s->free(); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void FrameBuffer::reloadSurfaces() -{ - for(auto& s: mySurfaceList) - s->reload(); + return myBackend->createSurface(w, h, inter, data); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FrameBuffer::resetSurfaces() { - // Free all resources for each surface, then reload them - // Due to possible timing and/or synchronization issues, all free()'s - // are done first, then all reload()'s - // Any derived FrameBuffer classes that call this method should be - // aware of these restrictions, and act accordingly + switch(myOSystem.eventHandler().state()) + { + case EventHandlerState::NONE: + case EventHandlerState::EMULATION: + case EventHandlerState::PAUSE: + case EventHandlerState::PLAYBACK: + myMsg.surface->reload(); + myStatsMsg.surface->reload(); + myTIASurface->resetSurfaces(); + break; - freeSurfaces(); - reloadSurfaces(); + #ifdef GUI_SUPPORT + case EventHandlerState::OPTIONSMENU: + myOSystem.menu().resetSurfaces(); + break; + + case EventHandlerState::CMDMENU: + myOSystem.commandMenu().resetSurfaces(); + break; + + case EventHandlerState::HIGHSCORESMENU: + myOSystem.highscoresMenu().resetSurfaces(); + break; + + case EventHandlerState::MESSAGEMENU: + myOSystem.messageMenu().resetSurfaces(); + break; + + case EventHandlerState::TIMEMACHINE: + myOSystem.timeMachine().resetSurfaces(); + break; + + case EventHandlerState::LAUNCHER: + myOSystem.launcher().resetSurfaces(); + break; + #endif + + #ifdef DEBUGGER_SUPPORT + case EventHandlerState::DEBUGGER: + myOSystem.debugger().resetSurfaces(); + break; + #endif + + default: + break; + } update(UpdateMode::REDRAW); // force full update } diff --git a/src/emucore/FrameBuffer.hxx b/src/emucore/FrameBuffer.hxx index 43cba7a2b..90dfafe22 100644 --- a/src/emucore/FrameBuffer.hxx +++ b/src/emucore/FrameBuffer.hxx @@ -158,7 +158,7 @@ class FrameBuffer @return A pointer to a valid surface object, or nullptr */ - shared_ptr allocateSurface( + unique_ptr allocateSurface( int w, int h, ScalingInterpolation inter = ScalingInterpolation::none, @@ -384,16 +384,6 @@ class FrameBuffer string getDisplayKey() const; void saveCurrentWindowPosition() const; - /** - Calls 'free()' on all surfaces that the framebuffer knows about. - */ - void freeSurfaces(); - - /** - Calls 'reload()' on all surfaces that the framebuffer knows about. - */ - void reloadSurfaces(); - /** Frees and reloads all surfaces that the framebuffer knows about. */ @@ -520,7 +510,7 @@ class FrameBuffer int x{0}, y{0}, w{0}, h{0}; MessagePosition position{MessagePosition::BottomCenter}; ColorId color{kNone}; - shared_ptr surface; + unique_ptr surface; bool enabled{false}; bool dirty{false}; bool showGauge{false}; @@ -541,9 +531,6 @@ class FrameBuffer // Maximum TIA zoom level that can be used for this framebuffer float myTIAMaxZoom{1.F}; - // Holds a reference to all the surfaces that have been created - vector> mySurfaceList; - // Maximum message width [chars] static constexpr int MESSAGE_WIDTH = 56; // Maximum gauge bar width [chars] diff --git a/src/emucore/TIASurface.cxx b/src/emucore/TIASurface.cxx index 4b2ba4952..bd5f1c94b 100644 --- a/src/emucore/TIASurface.cxx +++ b/src/emucore/TIASurface.cxx @@ -541,3 +541,12 @@ bool TIASurface::correctAspect() const { return myOSystem.settings().getBool("tia.correct_aspect"); } + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void TIASurface::resetSurfaces() +{ + myTiaSurface->reload(); + mySLineSurface->reload(); + myBaseTiaSurface->reload(); + myShadeSurface->reload(); +} diff --git a/src/emucore/TIASurface.hxx b/src/emucore/TIASurface.hxx index e309ddda9..771eb989d 100644 --- a/src/emucore/TIASurface.hxx +++ b/src/emucore/TIASurface.hxx @@ -183,6 +183,11 @@ class TIASurface */ void updateSurfaceSettings(); + /** + Issue a 'reload' to each surface. + */ + void resetSurfaces(); + private: /** Average current calculated buffer's pixel with previous calculated buffer's pixel (50:50). @@ -208,7 +213,7 @@ class TIASurface FrameBuffer& myFB; TIA* myTIA{nullptr}; - shared_ptr myTiaSurface, mySLineSurface, myBaseTiaSurface, myShadeSurface; + unique_ptr myTiaSurface, mySLineSurface, myBaseTiaSurface, myShadeSurface; // NTSC object to use in TIA rendering mode NTSCFilter myNTSCFilter; diff --git a/src/gui/ContextMenu.cxx b/src/gui/ContextMenu.cxx index 994909dbd..4785270f0 100644 --- a/src/gui/ContextMenu.cxx +++ b/src/gui/ContextMenu.cxx @@ -583,7 +583,6 @@ void ContextMenu::setArrows() // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void ContextMenu::drawDialog() { - // Normally we add widgets and let Dialog::draw() take care of this // logic. But for some reason, this Dialog was written differently // by the ScummVM guys, so I'm not going to mess with it. diff --git a/src/gui/Dialog.cxx b/src/gui/Dialog.cxx index d7cc32ace..c1a1aba51 100644 --- a/src/gui/Dialog.cxx +++ b/src/gui/Dialog.cxx @@ -87,6 +87,8 @@ Dialog::~Dialog() _firstWidget = nullptr; _buttonGroup.clear(); + +cerr << "\n~Dialog(): " << this << endl; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -252,7 +254,7 @@ void Dialog::render() // Extra surfaces must be rendered afterwards, so they are drawn on top if(_surface->render()) { - mySurfaceStack.applyAll([](shared_ptr& surface) { + mySurfaceStack.applyAll([](unique_ptr& surface) { surface->render(); }); } @@ -418,9 +420,10 @@ void Dialog::buildCurrentFocusList(int tabID) } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void Dialog::addSurface(const shared_ptr& surface) +void Dialog::addSurface(const unique_ptr& surface) { - mySurfaceStack.push(surface); +// FIXME : add this to the stack somehow +// mySurfaceStack.push(surface); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/gui/Dialog.hxx b/src/gui/Dialog.hxx index 027fbe5cb..31421988e 100644 --- a/src/gui/Dialog.hxx +++ b/src/gui/Dialog.hxx @@ -90,7 +90,7 @@ class Dialog : public GuiObject the surface render() call will always occur in such a case, the surface should call setVisible() to enable/disable its output. */ - void addSurface(const shared_ptr& surface); + void addSurface(const unique_ptr& surface); void setTitle(const string& title); bool hasTitle() { return !_title.empty(); } @@ -220,8 +220,6 @@ class Dialog : public GuiObject int _layer{0}; unique_ptr _toolTip; - Common::FixedStack> mySurfaceStack; - private: struct Focus { Widget* widget{nullptr}; @@ -248,13 +246,15 @@ class Dialog : public GuiObject TabFocusList _myTabList; // focus for each tab (if any) WidgetArray _buttonGroup; - shared_ptr _surface; - shared_ptr _shadeSurface; + unique_ptr _surface; + unique_ptr _shadeSurface; int _tabID{0}; uInt32 _max_w{0}; // maximum wanted width uInt32 _max_h{0}; // maximum wanted height + Common::FixedStack> mySurfaceStack; + private: // Following constructors and assignment operators not supported Dialog() = delete; diff --git a/src/gui/DialogContainer.cxx b/src/gui/DialogContainer.cxx index 97b555e8c..4784acac5 100644 --- a/src/gui/DialogContainer.cxx +++ b/src/gui/DialogContainer.cxx @@ -199,6 +199,14 @@ void DialogContainer::reStack() reset(); } +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void DialogContainer::resetSurfaces() +{ + myDialogStack.applyAll([&](Dialog*& d) { + d->surface().reload(); + }); +} + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void DialogContainer::handleTextEvent(char text) { diff --git a/src/gui/DialogContainer.hxx b/src/gui/DialogContainer.hxx index 8dbc438f8..647d9eb67 100644 --- a/src/gui/DialogContainer.hxx +++ b/src/gui/DialogContainer.hxx @@ -150,6 +150,13 @@ class DialogContainer */ void reStack(); + /** + Issue a 'reload' event to each dialog surface in the stack. This + is typically used when interpolation or attributes for a dialog + have changed. + */ + void resetSurfaces(); + /** Inform the container that it should resize according to the current screen dimensions. We make this virtual, since the container may or diff --git a/src/gui/RomInfoWidget.hxx b/src/gui/RomInfoWidget.hxx index 4aa03d11e..a5c73ee28 100644 --- a/src/gui/RomInfoWidget.hxx +++ b/src/gui/RomInfoWidget.hxx @@ -50,7 +50,7 @@ class RomInfoWidget : public Widget private: // Surface pointer holding the PNG image - shared_ptr mySurface; + unique_ptr mySurface; // Whether the surface should be redrawn by drawWidget() bool mySurfaceIsValid{false}; diff --git a/src/gui/ToolTip.cxx b/src/gui/ToolTip.cxx index a51633be6..4546a2285 100644 --- a/src/gui/ToolTip.cxx +++ b/src/gui/ToolTip.cxx @@ -47,15 +47,13 @@ void ToolTip::setFont(const GUI::Font& font) myWidth = fontWidth * MAX_COLUMNS + myTextXOfs * 2; myHeight = fontHeight * MAX_ROWS + myTextYOfs * 2; + // unallocate if(mySurface != nullptr) - { - // TODO: unallocate - mySurface = nullptr; - } + mySurface.reset(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -shared_ptr ToolTip::surface() +const unique_ptr& ToolTip::surface() { if(mySurface == nullptr) mySurface = myDialog.instance().frameBuffer().allocateSurface(myWidth, myHeight); diff --git a/src/gui/ToolTip.hxx b/src/gui/ToolTip.hxx index fd4557eaf..3938aad06 100644 --- a/src/gui/ToolTip.hxx +++ b/src/gui/ToolTip.hxx @@ -76,7 +76,7 @@ class ToolTip /** Allocate surface if required and return it */ - shared_ptr surface(); + const unique_ptr& surface(); void show(const string& tip); @@ -100,7 +100,7 @@ class ToolTip uInt32 myTextYOfs{0}; bool myTipShown{false}; uInt32 myScale{1}; - shared_ptr mySurface; + unique_ptr mySurface; }; #endif diff --git a/src/libretro/FBSurfaceLIBRETRO.hxx b/src/libretro/FBSurfaceLIBRETRO.hxx index 4dcf349ed..099df7977 100644 --- a/src/libretro/FBSurfaceLIBRETRO.hxx +++ b/src/libretro/FBSurfaceLIBRETRO.hxx @@ -55,7 +55,6 @@ class FBSurfaceLIBRETRO : public FBSurface bool render() override { return true; } void invalidate() override { } void invalidateRect(uInt32, uInt32, uInt32, uInt32) override { } - void free() override { } void reload() override { } void resize(uInt32 width, uInt32 height) override { } void setScalingInterpolation(ScalingInterpolation) override { }