diff --git a/src/common/FBSurfaceSDL2.cxx b/src/common/FBSurfaceSDL2.cxx index d72c55314..f68b06b4b 100644 --- a/src/common/FBSurfaceSDL2.cxx +++ b/src/common/FBSurfaceSDL2.cxx @@ -25,7 +25,12 @@ FBSurfaceSDL2::FBSurfaceSDL2(FrameBufferSDL2& buffer, uInt32 width, uInt32 heigh myFB(buffer), mySurface(NULL), myTexture(NULL), - mySurfaceIsDirty(true) + mySurfaceIsDirty(true), + myDataIsStatic(false), + myInterpolate(false), + myBlendEnabled(false), + myBlendAlpha(255), + myStaticData(NULL) { // Create a surface in the same format as the parent GL class const SDL_PixelFormat* pf = myFB.myPixelFormat; @@ -56,6 +61,12 @@ FBSurfaceSDL2::~FBSurfaceSDL2() SDL_FreeSurface(mySurface); free(); + + if(myStaticData) + { + delete[] myStaticData; + myStaticData = NULL; + } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -92,8 +103,31 @@ void FBSurfaceSDL2::addDirtyRect(uInt32 x, uInt32 y, uInt32 w, uInt32 h) } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void FBSurfaceSDL2::basePtr(uInt32*& pixels, uInt32& pitch) +void FBSurfaceSDL2::setStaticContents(const uInt32* pixels, uInt32 pitch) { + myDataIsStatic = true; + myStaticPitch = pitch * 4; // we need pitch in 'bytes' + + if(!myStaticData) + myStaticData = new uInt32[mySurface->w * mySurface->h]; + SDL_memcpy(myStaticData, pixels, mySurface->w * mySurface->h); + + // Re-create the texture with the new settings + free(); + reload(); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void FBSurfaceSDL2::setInterpolationAndBlending( + bool smoothScale, bool useBlend, uInt32 blendAlpha) +{ + myInterpolate = smoothScale; + myBlendEnabled = useBlend; + myBlendAlpha = blendAlpha * 2.55; + + // Re-create the texture with the new settings + free(); + reload(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -147,7 +181,8 @@ void FBSurfaceSDL2::render() //cerr << "src: x=" << mySrcR.x << ", y=" << mySrcR.y << ", w=" << mySrcR.w << ", h=" << mySrcR.h << endl; //cerr << "dst: x=" << myDstR.x << ", y=" << myDstR.y << ", w=" << myDstR.w << ", h=" << myDstR.h << endl; - SDL_UpdateTexture(myTexture, &mySrcR, mySurface->pixels, mySurface->pitch); + if(!myDataIsStatic) + SDL_UpdateTexture(myTexture, &mySrcR, mySurface->pixels, mySurface->pitch); SDL_RenderCopy(myFB.myRenderer, myTexture, &mySrcR, &myDstR); mySurfaceIsDirty = false; @@ -177,7 +212,19 @@ void FBSurfaceSDL2::free() void FBSurfaceSDL2::reload() { // Re-create texture; the underlying SDL_Surface is fine as-is - myTexture = SDL_CreateTexture(myFB.myRenderer, - SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, + SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, myInterpolate ? "1" : "0"); + myTexture = SDL_CreateTexture(myFB.myRenderer, myFB.myPixelFormat->format, + myDataIsStatic ? SDL_TEXTUREACCESS_STATIC : SDL_TEXTUREACCESS_STREAMING, mySurface->w, mySurface->h); + + // If the data is static, we only upload it once + if(myDataIsStatic) + SDL_UpdateTexture(myTexture, NULL, myStaticData, myStaticPitch); + + // Blending enabled? + if(myBlendEnabled) + { + SDL_SetTextureBlendMode(myTexture, SDL_BLENDMODE_BLEND); + SDL_SetTextureAlphaMod(myTexture, myBlendAlpha); + } } diff --git a/src/common/FBSurfaceSDL2.hxx b/src/common/FBSurfaceSDL2.hxx index fb25a6151..84ba163b1 100644 --- a/src/common/FBSurfaceSDL2.hxx +++ b/src/common/FBSurfaceSDL2.hxx @@ -33,6 +33,7 @@ class FBSurfaceSDL2 : public FBSurface { public: FBSurfaceSDL2(FrameBufferSDL2& buffer, uInt32 width, uInt32 height); + virtual ~FBSurfaceSDL2(); // Most of the surface drawing primitives are implemented in FBSurface; @@ -42,7 +43,9 @@ class FBSurfaceSDL2 : public FBSurface void drawSurface(const FBSurface* surface, uInt32 x, uInt32 y); void addDirtyRect(uInt32 x, uInt32 y, uInt32 w, uInt32 h); - void basePtr(uInt32*& pixels, uInt32& pitch); + void setStaticContents(const uInt32* pixels, uInt32 pitch); + void setInterpolationAndBlending(bool smoothScale, bool useBlend, + uInt32 blendAlpha); GUI::Rect srcRect(); GUI::Rect dstRect(); @@ -65,6 +68,14 @@ class FBSurfaceSDL2 : public FBSurface SDL_Rect mySrcR, myDstR; bool mySurfaceIsDirty; + + bool myDataIsStatic; // 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 + + uInt32* myStaticData; // The data to use when the buffer contents are static + uInt32 myStaticPitch; // The number of bytes in a row of static data }; #endif diff --git a/src/common/FBSurfaceTIA.hxx b/src/common/FBSurfaceTIA.hxx index 0d4c7f61e..3c018f4c6 100644 --- a/src/common/FBSurfaceTIA.hxx +++ b/src/common/FBSurfaceTIA.hxx @@ -48,7 +48,9 @@ class FBSurfaceTIA : public FBSurface void free(); void reload(); - void basePtr(uInt32*& pixels, uInt32& pitch) { } + void setStaticContents(const uInt32* pixels, uInt32 pitch) { } + void setInterpolationAndBlending(bool smoothScale, bool useBlend, + uInt32 blendAlpha) { } GUI::Rect srcRect() { return GUI::Rect(); } GUI::Rect dstRect() { return GUI::Rect(); } diff --git a/src/common/FrameBufferSDL2.cxx b/src/common/FrameBufferSDL2.cxx index ec7d4a829..8e4f62fb6 100644 --- a/src/common/FrameBufferSDL2.cxx +++ b/src/common/FrameBufferSDL2.cxx @@ -336,7 +336,7 @@ void FrameBufferSDL2::setTIAPalette(const uInt32* palette) } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -FBSurface* FrameBufferSDL2::createSurface(int w, int h) const +FBSurface* FrameBufferSDL2::createSurface(uInt32 w, uInt32 h) const { return new FBSurfaceSDL2((FrameBufferSDL2&)*this, w, h); } diff --git a/src/common/FrameBufferSDL2.hxx b/src/common/FrameBufferSDL2.hxx index f3d183154..f4184efca 100644 --- a/src/common/FrameBufferSDL2.hxx +++ b/src/common/FrameBufferSDL2.hxx @@ -165,13 +165,12 @@ class FrameBufferSDL2 : public FrameBuffer void invalidate(); /** - This method is called to create a surface compatible with the one - currently in use, but having the given dimensions. + This method is called to create a surface with the given attributes. @param w The requested width of the new surface. @param h The requested height of the new surface. */ - FBSurface* createSurface(int w, int h) const; + FBSurface* createSurface(uInt32 w, uInt32 h) const; /** Grabs or ungrabs the mouse based on the given boolean value. diff --git a/src/emucore/FBSurface.hxx b/src/emucore/FBSurface.hxx index f98cc2e05..9fac81818 100644 --- a/src/emucore/FBSurface.hxx +++ b/src/emucore/FBSurface.hxx @@ -219,7 +219,7 @@ class FBSurface // implemented in child classes. // // For the following, 'src' indicates the actual data buffer area - // (non-scaled) and 'dst' indicates the rendered area (possibly scaled). + // (non-scaled) and 'dst' indicates the rendered area (possibly scaled). ////////////////////////////////////////////////////////////////////////// /** @@ -238,6 +238,30 @@ class FBSurface virtual void setDstPos(uInt32 x, uInt32 y) = 0; virtual void setDstSize(uInt32 w, uInt32 h) = 0; + /** + This method should be called to indicate that the surface contains + static data that will never change. Some rendering toolkits can + use this information to optimize how the data is rendered. + + Note that once this method is called, all other drawing primitives + will not work. + + @param pixels The static data to use + @param pitch The number of pixels in a row + */ + virtual void setStaticContents(const uInt32* pixels, uInt32 pitch) = 0; + + /** + This method should be called to modify the interpolation and + blending effects to be applied to this surface. + + @param smoothScale Whether to use interpolation during scaling + @param useBlend Whether the surface should use alpha blending + @param blendAlpha The alpha to use during blending (if used) + */ + virtual void setInterpolationAndBlending(bool smoothScale, + bool useBlend, uInt32 blendAlpha) = 0; + /** This method should be called to translate the given coordinates to the (destination) surface coordinates. diff --git a/src/emucore/FrameBuffer.hxx b/src/emucore/FrameBuffer.hxx index 679e3976f..d9e257c89 100644 --- a/src/emucore/FrameBuffer.hxx +++ b/src/emucore/FrameBuffer.hxx @@ -437,13 +437,12 @@ class FrameBuffer virtual void invalidate() = 0; /** - This method is called to create a surface compatible with the one - currently in use, but having the given dimensions. + This method is called to create a surface with the given attributes. @param w The requested width of the new surface. @param h The requested height of the new surface. */ - virtual FBSurface* createSurface(int w, int h) const = 0; + virtual FBSurface* createSurface(uInt32 w, uInt32 h) const = 0; /** Change scanline intensity and interpolation.