From 1c798bd567856ac3cbee49ac4d6867f0b77d8bfa Mon Sep 17 00:00:00 2001 From: Christian Speckner Date: Sun, 8 Dec 2019 20:58:58 +0100 Subject: [PATCH] Factor out rendering / texture juggling from surface handling. Defuct. --- .vscode/settings.json | 55 +------- src/common/FBSurfaceSDL2.cxx | 57 ++++++--- src/common/FBSurfaceSDL2.hxx | 19 ++- src/common/FrameBufferSDL2.cxx | 12 ++ src/common/FrameBufferSDL2.hxx | 4 + src/common/module.mk | 3 +- src/common/sdl_blitter/BilinearBlitter.cxx | 140 +++++++++++++++++++++ src/common/sdl_blitter/BilinearBlitter.hxx | 73 +++++++++++ src/common/sdl_blitter/Blitter.hxx | 57 +++++++++ src/emucore/FBSurface.cxx | 6 + src/emucore/FBSurface.hxx | 2 + 11 files changed, 350 insertions(+), 78 deletions(-) create mode 100644 src/common/sdl_blitter/BilinearBlitter.cxx create mode 100644 src/common/sdl_blitter/BilinearBlitter.hxx create mode 100644 src/common/sdl_blitter/Blitter.hxx diff --git a/.vscode/settings.json b/.vscode/settings.json index 9108568ea..f355019cf 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -14,60 +14,15 @@ "C_Cpp.intelliSenseEngine": "Default", "files.insertFinalNewline": true, "files.associations": { - "__split_buffer": "cpp", - "__tree": "cpp", - "atomic": "cpp", - "deque": "cpp", - "ios": "cpp", - "list": "cpp", - "map": "cpp", - "set": "cpp", - "string": "cpp", - "string_view": "cpp", - "system_error": "cpp", - "vector": "cpp", - "sstream": "cpp", - "__bit_reference": "cpp", "__functional_base": "cpp", - "algorithm": "cpp", - "bitset": "cpp", - "chrono": "cpp", - "functional": "cpp", - "iterator": "cpp", - "limits": "cpp", + "array": "cpp", + "istream": "cpp", "locale": "cpp", "memory": "cpp", - "ratio": "cpp", - "tuple": "cpp", - "type_traits": "cpp", - "stdexcept": "cpp", - "fstream": "cpp", - "__locale": "cpp", - "__string": "cpp", - "__config": "cpp", - "__nullptr": "cpp", - "cstddef": "cpp", - "exception": "cpp", - "initializer_list": "cpp", - "new": "cpp", - "typeinfo": "cpp", - "__mutex_base": "cpp", - "mutex": "cpp", - "condition_variable": "cpp", - "*.ins": "cpp", - "cstring": "cpp", - "iostream": "cpp", - "cstdint": "cpp", - "ostream": "cpp", - "__memory": "cpp", - "iosfwd": "cpp", - "__hash_table": "cpp", - "array": "cpp", - "queue": "cpp", - "unordered_map": "cpp", - "istream": "cpp", "thread": "cpp", + "tuple": "cpp", "utility": "cpp", - "streambuf": "cpp" + "*.tcc": "cpp", + "functional": "cpp" } } diff --git a/src/common/FBSurfaceSDL2.cxx b/src/common/FBSurfaceSDL2.cxx index 0bb63c2f4..4988c9404 100644 --- a/src/common/FBSurfaceSDL2.cxx +++ b/src/common/FBSurfaceSDL2.cxx @@ -18,21 +18,17 @@ #include "FBSurfaceSDL2.hxx" #include "ThreadDebugging.hxx" +#include "sdl_blitter/BilinearBlitter.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - FBSurfaceSDL2::FBSurfaceSDL2(FrameBufferSDL2& buffer, uInt32 width, uInt32 height, const uInt32* data) : myFB(buffer), mySurface(nullptr), - myTexture(nullptr), - mySecondaryTexture(nullptr), - mySurfaceIsDirty(true), myIsVisible(true), - myTexAccess(SDL_TEXTUREACCESS_STREAMING), - myInterpolate(false), - myBlendEnabled(false), - myBlendAlpha(255) + myIsStatic(false) { + myBlitter = make_unique(buffer); createSurface(width, height, data); } @@ -93,6 +89,8 @@ void FBSurfaceSDL2::setSrcPos(uInt32 x, uInt32 y) { mySrcR.x = x; mySrcR.y = y; mySrcGUIR.moveTo(x, y); + + reinitializeBlitter(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -100,6 +98,8 @@ void FBSurfaceSDL2::setSrcSize(uInt32 w, uInt32 h) { mySrcR.w = w; mySrcR.h = h; mySrcGUIR.setWidth(w); mySrcGUIR.setHeight(h); + + reinitializeBlitter(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -107,6 +107,8 @@ void FBSurfaceSDL2::setDstPos(uInt32 x, uInt32 y) { myDstR.x = x; myDstR.y = y; myDstGUIR.moveTo(x, y); + + reinitializeBlitter(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -114,6 +116,8 @@ void FBSurfaceSDL2::setDstSize(uInt32 w, uInt32 h) { myDstR.w = w; myDstR.h = h; myDstGUIR.setWidth(w); myDstGUIR.setHeight(h); + + reinitializeBlitter(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -132,10 +136,11 @@ void FBSurfaceSDL2::translateCoords(Int32& x, Int32& y) const // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool FBSurfaceSDL2::render() { - ASSERT_MAIN_THREAD; + // ASSERT_MAIN_THREAD; if(myIsVisible) { + /* SDL_Texture* texture = myTexture; if(myTexAccess == SDL_TEXTUREACCESS_STREAMING) { @@ -146,6 +151,10 @@ bool FBSurfaceSDL2::render() SDL_RenderCopy(myFB.myRenderer, texture, &mySrcR, &myDstR); + */ + + myBlitter->blit(*mySurface); + return true; } return false; @@ -161,7 +170,7 @@ void FBSurfaceSDL2::invalidate() // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FBSurfaceSDL2::free() -{ +{/* ASSERT_MAIN_THREAD; SDL_Texture* textures[] = {myTexture, mySecondaryTexture}; @@ -171,11 +180,15 @@ void FBSurfaceSDL2::free() SDL_DestroyTexture(myTexture); myTexture = nullptr; } + */ + + myBlitter->free(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FBSurfaceSDL2::reload() { + /* ASSERT_MAIN_THREAD; // Re-create texture; the underlying SDL_Surface is fine as-is @@ -202,6 +215,9 @@ void FBSurfaceSDL2::reload() SDL_SetTextureAlphaMod(texture, myBlendAlpha); } } + */ + + reinitializeBlitter(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -209,11 +225,14 @@ void FBSurfaceSDL2::resize(uInt32 width, uInt32 height) { ASSERT_MAIN_THREAD; + /* // We will only resize when necessary, and not using static textures if((myTexAccess == SDL_TEXTUREACCESS_STATIC) || (mySurface && int(width) <= mySurface->w && int(height) <= mySurface->h)) return; // don't need to resize at all + */ + if(mySurface) SDL_FreeSurface(mySurface); free(); @@ -248,21 +267,28 @@ void FBSurfaceSDL2::createSurface(uInt32 width, uInt32 height, if(data) { - myTexAccess = SDL_TEXTUREACCESS_STATIC; - myStaticPitch = mySurface->w * 4; // we need pitch in 'bytes' - myStaticData = make_unique(mySurface->w * mySurface->h); - SDL_memcpy(myStaticData.get(), data, mySurface->w * mySurface->h * 4); + myIsStatic = true; + SDL_memcpy(mySurface->pixels, data, mySurface->w * mySurface->h * 4); } - applyAttributes(false); + // applyAttributes(false); // To generate texture - reload(); + // reload(); + reinitializeBlitter(); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void FBSurfaceSDL2::reinitializeBlitter() +{ + myBlitter->reinitialize(mySrcR, myDstR, myAttributes, myIsStatic ? mySurface : nullptr); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FBSurfaceSDL2::applyAttributes(bool immediate) { + reinitializeBlitter(); + /* myInterpolate = myAttributes.smoothing; myBlendEnabled = myAttributes.blending; myBlendAlpha = uInt8(myAttributes.blendalpha * 2.55); @@ -273,4 +299,5 @@ void FBSurfaceSDL2::applyAttributes(bool immediate) free(); reload(); } + */ } diff --git a/src/common/FBSurfaceSDL2.hxx b/src/common/FBSurfaceSDL2.hxx index 4c83c3d0f..34006003c 100644 --- a/src/common/FBSurfaceSDL2.hxx +++ b/src/common/FBSurfaceSDL2.hxx @@ -21,6 +21,7 @@ #include "bspf.hxx" #include "FBSurface.hxx" #include "FrameBufferSDL2.hxx" +#include "sdl_blitter/Blitter.hxx" /** An FBSurface suitable for the SDL2 Render2D API, making use of hardware @@ -40,7 +41,7 @@ class FBSurfaceSDL2 : public FBSurface // void fillRect(uInt32 x, uInt32 y, uInt32 w, uInt32 h, ColorId color) override; // With hardware surfaces, it's faster to just update the entire surface - void setDirty() override { mySurfaceIsDirty = true; } + void setDirty() override {} uInt32 width() const override; uInt32 height() const override; @@ -66,6 +67,8 @@ class FBSurfaceSDL2 : public FBSurface private: void createSurface(uInt32 width, uInt32 height, const uInt32* data); + void reinitializeBlitter(); + // Following constructors and assignment operators not supported FBSurfaceSDL2() = delete; FBSurfaceSDL2(const FBSurfaceSDL2&) = delete; @@ -76,21 +79,13 @@ class FBSurfaceSDL2 : public FBSurface private: FrameBufferSDL2& myFB; + unique_ptr myBlitter; + SDL_Surface* mySurface; - SDL_Texture* myTexture; - SDL_Texture* mySecondaryTexture; SDL_Rect mySrcR, myDstR; - bool mySurfaceIsDirty; bool myIsVisible; - - SDL_TextureAccess myTexAccess; // Is pixel data constant or can it change? - bool myInterpolate; // Scaling is smoothed or blocky - bool myBlendEnabled; // Blending is enabled - uInt8 myBlendAlpha; // Alpha to use in blending mode - - unique_ptr myStaticData; // The data to use when the buffer contents are static - uInt32 myStaticPitch; // The number of bytes in a row of static data + bool myIsStatic; Common::Rect mySrcGUIR, myDstGUIR; }; diff --git a/src/common/FrameBufferSDL2.cxx b/src/common/FrameBufferSDL2.cxx index 2c9fb88ce..13bba00e5 100644 --- a/src/common/FrameBufferSDL2.cxx +++ b/src/common/FrameBufferSDL2.cxx @@ -427,3 +427,15 @@ void FrameBufferSDL2::clear() SDL_RenderClear(myRenderer); } + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +SDL_Renderer* FrameBufferSDL2::renderer() +{ + return myRenderer; +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +const SDL_PixelFormat& FrameBufferSDL2::pixelFormat() +{ + return *myPixelFormat; +} diff --git a/src/common/FrameBufferSDL2.hxx b/src/common/FrameBufferSDL2.hxx index b3b8da615..216738529 100644 --- a/src/common/FrameBufferSDL2.hxx +++ b/src/common/FrameBufferSDL2.hxx @@ -116,6 +116,10 @@ class FrameBufferSDL2 : public FrameBuffer */ void clear() override; + SDL_Renderer* renderer(); + + const SDL_PixelFormat& pixelFormat(); + protected: ////////////////////////////////////////////////////////////////////// // The following are derived from protected methods in FrameBuffer.hxx diff --git a/src/common/module.mk b/src/common/module.mk index eec33213e..d23dfcd04 100644 --- a/src/common/module.mk +++ b/src/common/module.mk @@ -25,7 +25,8 @@ MODULE_OBJS := \ src/common/FpsMeter.o \ src/common/ThreadDebugging.o \ src/common/StaggeredLogger.o \ - src/common/repository/KeyValueRepositoryConfigfile.o + src/common/repository/KeyValueRepositoryConfigfile.o \ + src/common/sdl_blitter/BilinearBlitter.o MODULE_DIRS += \ src/common diff --git a/src/common/sdl_blitter/BilinearBlitter.cxx b/src/common/sdl_blitter/BilinearBlitter.cxx new file mode 100644 index 000000000..7cc2a5685 --- /dev/null +++ b/src/common/sdl_blitter/BilinearBlitter.cxx @@ -0,0 +1,140 @@ +//============================================================================ +// +// SSSS tt lll lll +// SS SS tt ll ll +// SS tttttt eeee ll ll aaaa +// SSSS tt ee ee ll ll aa +// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" +// SS SS tt ee ll ll aa aa +// SSSS ttt eeeee llll llll aaaaa +// +// Copyright (c) 1995-2019 by Bradford W. Mott, Stephen Anthony +// and the Stella Team +// +// See the file "License.txt" for information on usage and redistribution of +// this file, and for a DISCLAIMER OF ALL WARRANTIES. +//============================================================================ + +#include "BilinearBlitter.hxx" + +#include "ThreadDebugging.hxx" + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +BilinearBlitter::BilinearBlitter(FrameBufferSDL2& fb) : + myTexture(nullptr), + mySecondaryTexture(nullptr), + myTexturesAreAllocated(false), + myRecreateTextures(false), + myStaticData(nullptr), + myFB(fb) +{} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +BilinearBlitter::~BilinearBlitter() +{ + free(); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void BilinearBlitter::reinitialize( + SDL_Rect srcRect, + SDL_Rect destRect, + FBSurface::Attributes attributes, + SDL_Surface* staticData +) +{ + myRecreateTextures = !( + mySrcRect.w == srcRect.w && + mySrcRect.h == srcRect.h && + myDstRect.w == destRect.w && + myDstRect.h == destRect.h && + attributes == myAttributes && + myStaticData == staticData + ); + + myStaticData = staticData; + mySrcRect = srcRect; + myDstRect = destRect; +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void BilinearBlitter::free() +{ + if (!myTexturesAreAllocated) { + return; + } + + ASSERT_MAIN_THREAD; + + SDL_Texture* textures[] = {myTexture, mySecondaryTexture}; + for (SDL_Texture* texture: textures) { + if (!texture) continue; + + SDL_DestroyTexture(texture); + } + + myTexturesAreAllocated = false; +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void BilinearBlitter::blit(SDL_Surface& surface) +{ + ASSERT_MAIN_THREAD; + + recreateTexturesIfNecessary(); + + SDL_Texture* texture = myTexture; + + if(myStaticData == nullptr) { + SDL_UpdateTexture(myTexture, &mySrcRect, surface.pixels, surface.pitch); + myTexture = mySecondaryTexture; + mySecondaryTexture = texture; + } + + SDL_RenderCopy(myFB.renderer(), texture, &mySrcRect, &myDstRect); +} + + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void BilinearBlitter::recreateTexturesIfNecessary() +{ + if (myTexturesAreAllocated && !myRecreateTextures) { + return; + } + + ASSERT_MAIN_THREAD; + + if (myTexturesAreAllocated) { + free(); + } + + SDL_TextureAccess texAccess = myStaticData == nullptr ? SDL_TEXTUREACCESS_STREAMING : SDL_TEXTUREACCESS_STATIC; + + SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, myAttributes.smoothing ? "1" : "0"); + + myTexture = SDL_CreateTexture(myFB.renderer(), myFB.pixelFormat().format, + texAccess, mySrcRect.w, mySrcRect.h); + + if (myStaticData == nullptr) { + mySecondaryTexture = SDL_CreateTexture(myFB.renderer(), myFB.pixelFormat().format, + texAccess, mySrcRect.w, mySrcRect.h); + } else { + mySecondaryTexture = nullptr; + SDL_UpdateTexture(myTexture, nullptr, myStaticData->pixels, myStaticData->pitch); + } + + if (myAttributes.blending) { + uInt8 blendAlpha = uInt8(myAttributes.blendalpha * 2.55); + + SDL_Texture* textures[] = {myTexture, mySecondaryTexture}; + for (SDL_Texture* texture: textures) { + if (!texture) continue; + + SDL_SetTextureBlendMode(texture, SDL_BLENDMODE_BLEND); + SDL_SetTextureAlphaMod(texture, blendAlpha); + } + } + + myRecreateTextures = false; + myTexturesAreAllocated = true; +} diff --git a/src/common/sdl_blitter/BilinearBlitter.hxx b/src/common/sdl_blitter/BilinearBlitter.hxx new file mode 100644 index 000000000..1fd4151d7 --- /dev/null +++ b/src/common/sdl_blitter/BilinearBlitter.hxx @@ -0,0 +1,73 @@ +//============================================================================ +// +// SSSS tt lll lll +// SS SS tt ll ll +// SS tttttt eeee ll ll aaaa +// SSSS tt ee ee ll ll aa +// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" +// SS SS tt ee ll ll aa aa +// SSSS ttt eeeee llll llll aaaaa +// +// Copyright (c) 1995-2019 by Bradford W. Mott, Stephen Anthony +// and the Stella Team +// +// See the file "License.txt" for information on usage and redistribution of +// this file, and for a DISCLAIMER OF ALL WARRANTIES. +//============================================================================ + +#ifndef BILINEAR_BLITTER_HXX +#define BILINEAR_BLITTER_HXX + +#include "Blitter.hxx" +#include "FrameBufferSDL2.hxx" +#include "SDL_lib.hxx" + +class BilinearBlitter : public Blitter { + + public: + + BilinearBlitter(FrameBufferSDL2& fb); + + virtual ~BilinearBlitter(); + + virtual void reinitialize( + SDL_Rect srcRect, + SDL_Rect destRect, + FBSurface::Attributes attributes, + SDL_Surface* staticData = nullptr + ) override; + + virtual void blit(SDL_Surface& surface) override; + + virtual void free() override; + + private: + + SDL_Texture* myTexture; + SDL_Texture* mySecondaryTexture; + SDL_Rect mySrcRect, myDstRect; + FBSurface::Attributes myAttributes; + + bool myTexturesAreAllocated; + bool myRecreateTextures; + + SDL_Surface* myStaticData; + + FrameBufferSDL2& myFB; + + private: + + void recreateTexturesIfNecessary(); + + private: + + BilinearBlitter(const BilinearBlitter&) = delete; + + BilinearBlitter(BilinearBlitter&&) = delete; + + BilinearBlitter& operator=(const BilinearBlitter&) = delete; + + BilinearBlitter& operator=(BilinearBlitter&&) = delete; +}; + +#endif // BILINEAR_BLITTER_HXX diff --git a/src/common/sdl_blitter/Blitter.hxx b/src/common/sdl_blitter/Blitter.hxx new file mode 100644 index 000000000..825967848 --- /dev/null +++ b/src/common/sdl_blitter/Blitter.hxx @@ -0,0 +1,57 @@ +//============================================================================ +// +// SSSS tt lll lll +// SS SS tt ll ll +// SS tttttt eeee ll ll aaaa +// SSSS tt ee ee ll ll aa +// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" +// SS SS tt ee ll ll aa aa +// SSSS ttt eeeee llll llll aaaaa +// +// Copyright (c) 1995-2019 by Bradford W. Mott, Stephen Anthony +// and the Stella Team +// +// See the file "License.txt" for information on usage and redistribution of +// this file, and for a DISCLAIMER OF ALL WARRANTIES. +//============================================================================ + +#ifndef BLITTER_HXX +#define BLITTER_HXX + +#include "bspf.hxx" +#include "SDL_lib.hxx" +#include "FBSurface.hxx" + +class Blitter { + + public: + + virtual ~Blitter() = default; + + virtual void reinitialize( + SDL_Rect srcRect, + SDL_Rect destRect, + FBSurface::Attributes attributes, + SDL_Surface* staticData = nullptr + ) = 0; + + virtual void blit(SDL_Surface& surface) = 0; + + virtual void free() = 0; + + protected: + + Blitter() = default; + + private: + + Blitter(const Blitter&) = delete; + + Blitter(Blitter&&) = delete; + + Blitter& operator=(const Blitter&) = delete; + + Blitter& operator=(Blitter&&) = delete; +}; + +#endif // BLITTER_HXX diff --git a/src/emucore/FBSurface.cxx b/src/emucore/FBSurface.cxx index 988953f26..f38965344 100644 --- a/src/emucore/FBSurface.cxx +++ b/src/emucore/FBSurface.cxx @@ -451,3 +451,9 @@ bool FBSurface::checkBounds(const uInt32 x, const uInt32 y) const // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const uInt32* FBSurface::myPalette = nullptr; + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +bool operator==(const FBSurface::Attributes& a1, const FBSurface::Attributes& a2) +{ + return a1.blendalpha == a2.blendalpha && a1.blending == a2.blending && a1.smoothing && a2.smoothing; +} diff --git a/src/emucore/FBSurface.hxx b/src/emucore/FBSurface.hxx index d77d6e553..b990d9738 100644 --- a/src/emucore/FBSurface.hxx +++ b/src/emucore/FBSurface.hxx @@ -389,4 +389,6 @@ class FBSurface FBSurface& operator=(FBSurface&&) = delete; }; +bool operator==(const FBSurface::Attributes& a1, const FBSurface::Attributes& a2); + #endif