From f6eb86b9bb316357341b3597b1ebb555936e76d4 Mon Sep 17 00:00:00 2001 From: Christian Speckner Date: Mon, 9 Dec 2019 22:50:51 +0100 Subject: [PATCH] Add HQ blitter. --- src/common/FBSurfaceSDL2.cxx | 86 +------------- src/common/module.mk | 3 +- src/common/sdl_blitter/HqBlitter.cxx | 170 +++++++++++++++++++++++++++ src/common/sdl_blitter/HqBlitter.hxx | 77 ++++++++++++ 4 files changed, 253 insertions(+), 83 deletions(-) create mode 100644 src/common/sdl_blitter/HqBlitter.cxx create mode 100644 src/common/sdl_blitter/HqBlitter.hxx diff --git a/src/common/FBSurfaceSDL2.cxx b/src/common/FBSurfaceSDL2.cxx index 4988c9404..ae6e23bd7 100644 --- a/src/common/FBSurfaceSDL2.cxx +++ b/src/common/FBSurfaceSDL2.cxx @@ -19,6 +19,7 @@ #include "ThreadDebugging.hxx" #include "sdl_blitter/BilinearBlitter.hxx" +#include "sdl_blitter/HqBlitter.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - FBSurfaceSDL2::FBSurfaceSDL2(FrameBufferSDL2& buffer, @@ -28,7 +29,7 @@ FBSurfaceSDL2::FBSurfaceSDL2(FrameBufferSDL2& buffer, myIsVisible(true), myIsStatic(false) { - myBlitter = make_unique(buffer); + myBlitter = make_unique(buffer); createSurface(width, height, data); } @@ -136,23 +137,8 @@ void FBSurfaceSDL2::translateCoords(Int32& x, Int32& y) const // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool FBSurfaceSDL2::render() { - // ASSERT_MAIN_THREAD; - if(myIsVisible) { - /* - SDL_Texture* texture = myTexture; - - if(myTexAccess == SDL_TEXTUREACCESS_STREAMING) { - SDL_UpdateTexture(myTexture, &mySrcR, mySurface->pixels, mySurface->pitch); - myTexture = mySecondaryTexture; - mySecondaryTexture = texture; - } - - SDL_RenderCopy(myFB.myRenderer, texture, &mySrcR, &myDstR); - - */ - myBlitter->blit(*mySurface); return true; @@ -170,54 +156,14 @@ void FBSurfaceSDL2::invalidate() // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FBSurfaceSDL2::free() -{/* - ASSERT_MAIN_THREAD; - - SDL_Texture* textures[] = {myTexture, mySecondaryTexture}; - for (SDL_Texture* texture: textures) { - if (!texture) continue; - - SDL_DestroyTexture(myTexture); - myTexture = nullptr; - } - */ - +{ myBlitter->free(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FBSurfaceSDL2::reload() { - /* - ASSERT_MAIN_THREAD; - - // Re-create texture; the underlying SDL_Surface is fine as-is - SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, myInterpolate ? "1" : "0"); - myTexture = SDL_CreateTexture(myFB.myRenderer, myFB.myPixelFormat->format, - myTexAccess, mySurface->w, mySurface->h); - - if (myTexAccess == SDL_TEXTUREACCESS_STREAMING) - mySecondaryTexture = SDL_CreateTexture(myFB.myRenderer, myFB.myPixelFormat->format, - myTexAccess, mySurface->w, mySurface->h); - - // If the data is static, we only upload it once - if(myTexAccess == SDL_TEXTUREACCESS_STATIC) - SDL_UpdateTexture(myTexture, nullptr, myStaticData.get(), myStaticPitch); - - SDL_Texture* textures[] = {myTexture, mySecondaryTexture}; - for (SDL_Texture* texture: textures) { - if (!texture) continue; - - // Blending enabled? - if(myBlendEnabled) - { - SDL_SetTextureBlendMode(texture, SDL_BLENDMODE_BLEND); - SDL_SetTextureAlphaMod(texture, myBlendAlpha); - } - } - */ - - reinitializeBlitter(); + reinitializeBlitter(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -225,14 +171,6 @@ 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(); @@ -271,10 +209,6 @@ void FBSurfaceSDL2::createSurface(uInt32 width, uInt32 height, SDL_memcpy(mySurface->pixels, data, mySurface->w * mySurface->h * 4); } - // applyAttributes(false); - - // To generate texture - // reload(); reinitializeBlitter(); } @@ -288,16 +222,4 @@ void FBSurfaceSDL2::reinitializeBlitter() void FBSurfaceSDL2::applyAttributes(bool immediate) { reinitializeBlitter(); - /* - myInterpolate = myAttributes.smoothing; - myBlendEnabled = myAttributes.blending; - myBlendAlpha = uInt8(myAttributes.blendalpha * 2.55); - - if(immediate) - { - // Re-create the texture with the new settings - free(); - reload(); - } - */ } diff --git a/src/common/module.mk b/src/common/module.mk index d23dfcd04..caff547df 100644 --- a/src/common/module.mk +++ b/src/common/module.mk @@ -26,7 +26,8 @@ MODULE_OBJS := \ src/common/ThreadDebugging.o \ src/common/StaggeredLogger.o \ src/common/repository/KeyValueRepositoryConfigfile.o \ - src/common/sdl_blitter/BilinearBlitter.o + src/common/sdl_blitter/BilinearBlitter.o \ + src/common/sdl_blitter/HqBlitter.o MODULE_DIRS += \ src/common diff --git a/src/common/sdl_blitter/HqBlitter.cxx b/src/common/sdl_blitter/HqBlitter.cxx new file mode 100644 index 000000000..a47cd003b --- /dev/null +++ b/src/common/sdl_blitter/HqBlitter.cxx @@ -0,0 +1,170 @@ +//============================================================================ +// +// 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 "HqBlitter.hxx" + +#include "ThreadDebugging.hxx" + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +HqBlitter::HqBlitter(FrameBufferSDL2& fb) : + mySrcTexture(nullptr), + myIntermediateTexture(nullptr), + mySecondaryIntermedateTexture(nullptr), + myTexturesAreAllocated(false), + myRecreateTextures(false), + myStaticData(nullptr), + myFB(fb) +{} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +HqBlitter::~HqBlitter() +{ + free(); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void HqBlitter::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; + myAttributes = attributes; +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void HqBlitter::free() +{ + if (!myTexturesAreAllocated) { + return; + } + + ASSERT_MAIN_THREAD; + + SDL_Texture* textures[] = {mySrcTexture, myIntermediateTexture, mySecondaryIntermedateTexture}; + for (SDL_Texture* texture: textures) { + if (!texture) continue; + + SDL_DestroyTexture(texture); + } + + myTexturesAreAllocated = false; +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void HqBlitter::blit(SDL_Surface& surface) +{ + ASSERT_MAIN_THREAD; + + recreateTexturesIfNecessary(); + + SDL_Texture* texture = myIntermediateTexture; + + if(myStaticData == nullptr) { + SDL_UpdateTexture(mySrcTexture, &mySrcRect, surface.pixels, surface.pitch); + + blitToIntermediate(); + + myIntermediateTexture = mySecondaryIntermedateTexture; + mySecondaryIntermedateTexture = texture; + } + + SDL_RenderCopy(myFB.renderer(), texture, &myIntermediateRect, &myDstRect); +} + + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void HqBlitter::blitToIntermediate() +{ + SDL_Rect r = mySrcRect; + r.x = r.y = 0; + + SDL_SetRenderTarget(myFB.renderer(), myIntermediateTexture); + SDL_RenderCopy(myFB.renderer(), mySrcTexture, &r, &myIntermediateRect); + + SDL_SetRenderTarget(myFB.renderer(), nullptr); +} + + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void HqBlitter::recreateTexturesIfNecessary() +{ + if (myTexturesAreAllocated && !myRecreateTextures) { + return; + } + + ASSERT_MAIN_THREAD; + + if (myTexturesAreAllocated) { + free(); + } + + SDL_TextureAccess texAccess = myStaticData == nullptr ? SDL_TEXTUREACCESS_STREAMING : SDL_TEXTUREACCESS_STATIC; + + myIntermediateRect.w = (myDstRect.w / mySrcRect.w) * mySrcRect.w; + myIntermediateRect.h = (myDstRect.h / mySrcRect.h) * mySrcRect.h; + myIntermediateRect.x = 0; + myIntermediateRect.y = 0; + + SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "0"); + + mySrcTexture = SDL_CreateTexture(myFB.renderer(), myFB.pixelFormat().format, + texAccess, mySrcRect.w, mySrcRect.h); + + SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, myAttributes.smoothing ? "1" : "0"); + + myIntermediateTexture = SDL_CreateTexture(myFB.renderer(), myFB.pixelFormat().format, + SDL_TEXTUREACCESS_TARGET, myIntermediateRect.w, myIntermediateRect.h); + + if (myStaticData == nullptr) { + mySecondaryIntermedateTexture = SDL_CreateTexture(myFB.renderer(), myFB.pixelFormat().format, + SDL_TEXTUREACCESS_TARGET, myIntermediateRect.w, myIntermediateRect.h); + } else { + mySecondaryIntermedateTexture = nullptr; + SDL_UpdateTexture(mySrcTexture, nullptr, myStaticData->pixels, myStaticData->pitch); + + blitToIntermediate(); + } + + if (myAttributes.blending) { + uInt8 blendAlpha = uInt8(myAttributes.blendalpha * 2.55); + + SDL_Texture* textures[] = {mySrcTexture, myIntermediateTexture, mySecondaryIntermedateTexture}; + 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/HqBlitter.hxx b/src/common/sdl_blitter/HqBlitter.hxx new file mode 100644 index 000000000..745f869b1 --- /dev/null +++ b/src/common/sdl_blitter/HqBlitter.hxx @@ -0,0 +1,77 @@ +//============================================================================ +// +// 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 HQ_BLITTER_HXX +#define HQ_BLITTER_HXX + +#include "Blitter.hxx" +#include "FrameBufferSDL2.hxx" +#include "SDL_lib.hxx" + +class HqBlitter : public Blitter { + + public: + + HqBlitter(FrameBufferSDL2& fb); + + virtual ~HqBlitter(); + + 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* mySrcTexture; + SDL_Texture* myIntermediateTexture; + SDL_Texture* mySecondaryIntermedateTexture; + + SDL_Rect mySrcRect, myIntermediateRect, myDstRect; + FBSurface::Attributes myAttributes; + + bool myTexturesAreAllocated; + bool myRecreateTextures; + + SDL_Surface* myStaticData; + + FrameBufferSDL2& myFB; + + private: + + void recreateTexturesIfNecessary(); + + void blitToIntermediate(); + + private: + + HqBlitter(const HqBlitter&) = delete; + + HqBlitter(HqBlitter&&) = delete; + + HqBlitter& operator=(const HqBlitter&) = delete; + + HqBlitter& operator=(HqBlitter&&) = delete; +}; + +#endif // HQ_BLITTER_CXX