From bd01e11f56159142b9c2090de76fd2f1092ffed7 Mon Sep 17 00:00:00 2001 From: Wayward Heart <91356680+WaywardHeart@users.noreply.github.com> Date: Mon, 23 Oct 2023 01:53:03 -0500 Subject: [PATCH 1/7] Fix blitting from megatextures Code mostly taken from the implementation in Bitmap::drawText --- src/display/bitmap.cpp | 260 +++++++++++++++++++++++------------------ 1 file changed, 148 insertions(+), 112 deletions(-) diff --git a/src/display/bitmap.cpp b/src/display/bitmap.cpp index 95eef5d..3459e5b 100644 --- a/src/display/bitmap.cpp +++ b/src/display/bitmap.cpp @@ -1058,129 +1058,165 @@ void Bitmap::stretchBlt(IntRect destRect, return; SDL_Surface *srcSurf = source.megaSurface(); + SDL_Surface *blitTemp = 0; + bool touchesTaintedArea = p->touchesTaintedArea(destRect); - if (srcSurf && shState->config().subImageFix) - { - /* Blit from software surface, for broken GL drivers */ - Vec2i gpTexSize; - shState->ensureTexSize(sourceRect.w, sourceRect.h, gpTexSize); - shState->bindTex(); - - GLMeta::subRectImageUpload(srcSurf->w, sourceRect.x, sourceRect.y, 0, 0, - sourceRect.w, sourceRect.h, srcSurf, GL_RGBA); - GLMeta::subRectImageEnd(); - - SimpleShader &shader = shState->shaders().simple; - shader.bind(); - shader.setTranslation(Vec2i()); - shader.setTexSize(gpTexSize); - - p->pushSetViewport(shader); - p->bindFBO(); - - Quad &quad = shState->gpQuad(); - quad.setTexRect(FloatRect(0, 0, sourceRect.w, sourceRect.h)); - quad.setPosRect(destRect); - - p->blitQuad(quad); - p->popViewport(); - - p->addTaintedArea(destRect); - p->onModified(); - - return; - } - else if (srcSurf) - { - /* Blit from software surface */ - /* Don't do transparent blits for now */ - if (opacity < 255) - source.ensureNonMega(); - - SDL_Rect srcRect = sourceRect; - SDL_Rect dstRect = destRect; - SDL_Rect btmRect = { 0, 0, width(), height() }; - SDL_Rect bltRect; - - if (SDL_IntersectRect(&btmRect, &dstRect, &bltRect) != SDL_TRUE) - return; - - int bpp; - Uint32 rMask, gMask, bMask, aMask; - SDL_PixelFormatEnumToMasks(SDL_PIXELFORMAT_ABGR8888, - &bpp, &rMask, &gMask, &bMask, &aMask); - SDL_Surface *blitTemp = - SDL_CreateRGBSurface(0, destRect.w, destRect.h, bpp, rMask, gMask, bMask, aMask); - - SDL_BlitScaled(srcSurf, &srcRect, blitTemp, 0); - - TEX::bind(getGLTypes().tex); - - if (bltRect.w == dstRect.w && bltRect.h == dstRect.h) - { - /* Dest rectangle lies within bounding box */ - TEX::uploadSubImage(destRect.x, destRect.y, - destRect.w, destRect.h, - blitTemp->pixels, GL_RGBA); - } - else - { - /* Clipped blit */ - GLMeta::subRectImageUpload(blitTemp->w, bltRect.x - dstRect.x, bltRect.y - dstRect.y, - bltRect.x, bltRect.y, bltRect.w, bltRect.h, blitTemp, GL_RGBA); - GLMeta::subRectImageEnd(); - } - - SDL_FreeSurface(blitTemp); - - p->onModified(); - return; - } - - if (opacity == 255 && !p->touchesTaintedArea(destRect)) + if (!srcSurf && opacity == 255 && !touchesTaintedArea) { /* Fast blit */ GLMeta::blitBegin(getGLTypes()); GLMeta::blitSource(source.getGLTypes()); - GLMeta::blitRectangle(sourceRect, destRect); + GLMeta::blitRectangle(sourceRect, destRect, false); GLMeta::blitEnd(); } else { - /* Fragment pipeline */ - float normOpacity = (float) opacity / 255.0f; - - TEXFBO &gpTex = shState->gpTexFBO(destRect.w, destRect.h); - - GLMeta::blitBegin(gpTex); - GLMeta::blitSource(getGLTypes()); - GLMeta::blitRectangle(destRect, Vec2i()); - GLMeta::blitEnd(); - - FloatRect bltSubRect((float) sourceRect.x / source.width(), - (float) sourceRect.y / source.height(), - ((float) source.width() / sourceRect.w) * ((float) destRect.w / gpTex.width), - ((float) source.height() / sourceRect.h) * ((float) destRect.h / gpTex.height)); - - BltShader &shader = shState->shaders().blt; - shader.bind(); - shader.setDestination(gpTex.tex); - shader.setSubRect(bltSubRect); - shader.setOpacity(normOpacity); - - Quad &quad = shState->gpQuad(); - quad.setTexPosRect(sourceRect, destRect); - quad.setColor(Vec4(1, 1, 1, normOpacity)); - - source.p->bindTexture(shader, false); - p->bindFBO(); - p->pushSetViewport(shader); - - p->blitQuad(quad); - - p->popViewport(); + if (srcSurf) + { + SDL_Rect srcRect = sourceRect; + bool subImageFix = shState->config().subImageFix; + bool srcRectTooBig = srcRect.w > glState.caps.maxTexSize || + srcRect.h > glState.caps.maxTexSize; + bool srcSurfTooBig = srcSurf->w > glState.caps.maxTexSize || + srcSurf->h > glState.caps.maxTexSize; + + if (srcRectTooBig || srcSurfTooBig) + { + int error; + if (srcRectTooBig) + { + /* We have to resize it here anyway, so use software resizing */ + blitTemp = + SDL_CreateRGBSurface(0, abs(destRect.w), abs(destRect.h), p->format->BitsPerPixel, + p->format->Rmask, p->format->Gmask, + p->format->Bmask, p->format->Amask); + if (!blitTemp) + throw Exception(Exception::SDLError, "Error creating temporary surface for blitting: %s", + SDL_GetError()); + + error = SDL_BlitScaled(srcSurf, &srcRect, blitTemp, 0); + } + else + { + /* Just crop it, let the shader resize it later */ + blitTemp = + SDL_CreateRGBSurface(0, sourceRect.w, sourceRect.h, p->format->BitsPerPixel, + p->format->Rmask, p->format->Gmask, + p->format->Bmask, p->format->Amask); + if (!blitTemp) + throw Exception(Exception::SDLError, "Error creating temporary surface for blitting: %s", + SDL_GetError()); + + error = SDL_BlitSurface(srcSurf, &srcRect, blitTemp, 0); + } + + if (error) + { + SDL_FreeSurface(blitTemp); + throw Exception(Exception::SDLError, "Failed to blit surface: %s", SDL_GetError()); + } + + srcSurf = blitTemp; + + sourceRect.w = srcSurf->w; + sourceRect.h = srcSurf->h; + sourceRect.x = 0; + sourceRect.y = 0; + } + + if (opacity == 255 && !touchesTaintedArea) + { + if (!subImageFix && + sourceRect.w == destRect.w && sourceRect.h == destRect.h && + srcSurf->w == sourceRect.w && srcSurf->h == sourceRect.h) + { + /* No scaling needed */ + TEX::bind(getGLTypes().tex); + TEX::uploadSubImage(destRect.x, destRect.y, + destRect.w, destRect.h, + srcSurf->pixels, GL_RGBA); + } + else + { + /* Resizing or subImageFix involved: need to use intermediary TexFBO */ + TEXFBO &gpTF = shState->gpTexFBO(srcSurf->w, srcSurf->h); + + TEX::bind(gpTF.tex); + TEX::uploadSubImage(0, 0, srcSurf->w, srcSurf->h, srcSurf->pixels, GL_RGBA); + + GLMeta::blitBegin(getGLTypes()); + GLMeta::blitSource(gpTF); + GLMeta::blitRectangle(sourceRect, destRect, false); + GLMeta::blitEnd(); + } + } + } + if (opacity < 255 || touchesTaintedArea) + { + /* We're touching a tainted area or still need to reduce opacity */ + + /* Fragment pipeline */ + float normOpacity = (float) opacity / 255.0f; + + TEXFBO &gpTex = shState->gpTexFBO(abs(destRect.w), abs(destRect.h)); + Vec2i gpTexSize; + + GLMeta::blitBegin(gpTex); + GLMeta::blitSource(getGLTypes()); + GLMeta::blitRectangle(destRect, IntRect(0, 0, abs(destRect.w), abs(destRect.h))); + GLMeta::blitEnd(); + + int sourceWidth, sourceHeight; + FloatRect bltSubRect; + if (srcSurf) + { + shState->ensureTexSize(srcSurf->w, srcSurf->h, gpTexSize); + sourceWidth = gpTexSize.x; + sourceHeight = gpTexSize.y; + } + else + { + sourceWidth = source.width(); + sourceHeight = source.height(); + } + bltSubRect = FloatRect((float) sourceRect.x / sourceWidth, + (float) sourceRect.y / sourceHeight, + ((float) sourceWidth / sourceRect.w) * ((float) abs(destRect.w) / gpTex.width), + ((float) sourceHeight / sourceRect.h) * ((float) abs(destRect.h) / gpTex.height)); + + BltShader &shader = shState->shaders().blt; + shader.bind(); + if (srcSurf) + { + shState->bindTex(); + TEX::uploadSubImage(0, 0, srcSurf->w, srcSurf->h, srcSurf->pixels, GL_RGBA); + shader.setTexSize(gpTexSize); + } + else + { + source.p->bindTexture(shader, false); + } + shader.setSource(); + shader.setDestination(gpTex.tex); + shader.setSubRect(bltSubRect); + shader.setOpacity(normOpacity); + + Quad &quad = shState->gpQuad(); + quad.setTexPosRect(sourceRect, destRect); + quad.setColor(Vec4(1, 1, 1, normOpacity)); + + p->bindFBO(); + p->pushSetViewport(shader); + + p->blitQuad(quad); + + p->popViewport(); + } } + if (blitTemp) + SDL_FreeSurface(blitTemp); + p->addTaintedArea(destRect); p->onModified(); } From c89f3d5bd7be432cca12c0629516bc2c18da79a6 Mon Sep 17 00:00:00 2001 From: Wayward Heart <91356680+WaywardHeart@users.noreply.github.com> Date: Sat, 16 Dec 2023 16:22:48 -0600 Subject: [PATCH 2/7] Change the create Bitmap from surface constructor to always take ownership of the surface, and provide an option to leave it as a mega surface --- src/display/bitmap.cpp | 18 +++++------------- src/display/bitmap.h | 4 ++-- 2 files changed, 7 insertions(+), 15 deletions(-) diff --git a/src/display/bitmap.cpp b/src/display/bitmap.cpp index 3459e5b..31ab3a6 100644 --- a/src/display/bitmap.cpp +++ b/src/display/bitmap.cpp @@ -621,7 +621,7 @@ Bitmap::Bitmap(const char *filename) SDL_Surface *imgSurf = handler.surface; - initFromSurface(imgSurf, hiresBitmap, true); + initFromSurface(imgSurf, hiresBitmap, false); } Bitmap::Bitmap(int width, int height, bool isHires) @@ -789,7 +789,7 @@ Bitmap::Bitmap(TEXFBO &other) p->addTaintedArea(rect()); } -Bitmap::Bitmap(SDL_Surface *imgSurf, SDL_Surface *imgSurfHires) +Bitmap::Bitmap(SDL_Surface *imgSurf, SDL_Surface *imgSurfHires, bool forceMega) { Bitmap *hiresBitmap = nullptr; @@ -799,7 +799,7 @@ Bitmap::Bitmap(SDL_Surface *imgSurf, SDL_Surface *imgSurfHires) hiresBitmap->setLores(this); } - initFromSurface(imgSurf, hiresBitmap, false); + initFromSurface(imgSurf, hiresBitmap, forceMega); } Bitmap::~Bitmap() @@ -807,18 +807,14 @@ Bitmap::~Bitmap() dispose(); } -void Bitmap::initFromSurface(SDL_Surface *imgSurf, Bitmap *hiresBitmap, bool freeSurface) +void Bitmap::initFromSurface(SDL_Surface *imgSurf, Bitmap *hiresBitmap, bool forceMega) { p->ensureFormat(imgSurf, SDL_PIXELFORMAT_ABGR8888); - if (imgSurf->w > glState.caps.maxTexSize || imgSurf->h > glState.caps.maxTexSize) + if (imgSurf->w > glState.caps.maxTexSize || imgSurf->h > glState.caps.maxTexSize || forceMega) { /* Mega surface */ - if(!freeSurface) { - throw Exception(Exception::RGSSError, "Cloning Mega Bitmap from Surface not supported"); - } - p = new BitmapPrivate(this); p->selfHires = hiresBitmap; p->megaSurface = imgSurf; @@ -848,10 +844,6 @@ void Bitmap::initFromSurface(SDL_Surface *imgSurf, Bitmap *hiresBitmap, bool fre TEX::bind(p->gl.tex); TEX::uploadImage(p->gl.width, p->gl.height, imgSurf->pixels, GL_RGBA); - - if (freeSurface) { - SDL_FreeSurface(imgSurf); - } } p->addTaintedArea(rect()); diff --git a/src/display/bitmap.h b/src/display/bitmap.h index 9a1bbdd..dbf9a82 100644 --- a/src/display/bitmap.h +++ b/src/display/bitmap.h @@ -42,7 +42,7 @@ public: Bitmap(int width, int height, bool isHires = false); Bitmap(void *pixeldata, int width, int height); Bitmap(TEXFBO &other); - Bitmap(SDL_Surface *imgSurf, SDL_Surface *imgSurfHires); + Bitmap(SDL_Surface *imgSurf, SDL_Surface *imgSurfHires, bool forceMega = false); /* Clone constructor */ @@ -50,7 +50,7 @@ public: Bitmap(const Bitmap &other, int frame = -2); ~Bitmap(); - void initFromSurface(SDL_Surface *imgSurf, Bitmap *hiresBitmap, bool freeSurface); + void initFromSurface(SDL_Surface *imgSurf, Bitmap *hiresBitmap, bool forceMega = false); int width() const; int height() const; From e4770070618b94b32959a61043346f12cbd73544 Mon Sep 17 00:00:00 2001 From: Wayward Heart <91356680+WaywardHeart@users.noreply.github.com> Date: Tue, 31 Oct 2023 16:30:25 -0500 Subject: [PATCH 3/7] Use stretchBlt in drawText --- src/display/bitmap.cpp | 147 ++++++----------------------------------- src/display/bitmap.h | 2 +- 2 files changed, 21 insertions(+), 128 deletions(-) diff --git a/src/display/bitmap.cpp b/src/display/bitmap.cpp index 31ab3a6..5e50f58 100644 --- a/src/display/bitmap.cpp +++ b/src/display/bitmap.cpp @@ -1007,7 +1007,7 @@ static bool shrinkRects(int &sourcePos, int &sourceLen, const int &sBitmapLen, void Bitmap::stretchBlt(IntRect destRect, const Bitmap &source, IntRect sourceRect, - int opacity) + int opacity, bool smooth) { guardDisposed(); @@ -1058,7 +1058,7 @@ void Bitmap::stretchBlt(IntRect destRect, /* Fast blit */ GLMeta::blitBegin(getGLTypes()); GLMeta::blitSource(source.getGLTypes()); - GLMeta::blitRectangle(sourceRect, destRect, false); + GLMeta::blitRectangle(sourceRect, destRect, smooth); GLMeta::blitEnd(); } else @@ -1138,7 +1138,7 @@ void Bitmap::stretchBlt(IntRect destRect, GLMeta::blitBegin(getGLTypes()); GLMeta::blitSource(gpTF); - GLMeta::blitRectangle(sourceRect, destRect, false); + GLMeta::blitRectangle(sourceRect, destRect, smooth); GLMeta::blitEnd(); } } @@ -1200,9 +1200,15 @@ void Bitmap::stretchBlt(IntRect destRect, p->bindFBO(); p->pushSetViewport(shader); + if (smooth) + TEX::setSmooth(true); + p->blitQuad(quad); p->popViewport(); + + if (smooth) + TEX::setSmooth(false); } } @@ -1948,8 +1954,6 @@ void Bitmap::drawText(const IntRect &rect, const char *str, int align) SDL_Color c = fontColor.toSDLColor(); c.a = 255; - float txtAlpha = fontColor.norm.w; - SDL_Surface *txtSurf; if (p->font->isSolid()) @@ -2021,131 +2025,20 @@ void Bitmap::drawText(const IntRect &rect, const char *str, int align) if (squeeze > 1) squeeze = 1; - FloatRect posRect(alignX, alignY, txtSurf->w * squeeze, txtSurf->h); + IntRect destRect(alignX, alignY, 0, 0); + destRect.w = std::min(rect.w, (int)(txtSurf->w * squeeze)); + destRect.h = std::min(rect.h, txtSurf->h); - Vec2i gpTexSize; - shState->ensureTexSize(txtSurf->w, txtSurf->h, gpTexSize); + destRect.w = std::min(destRect.w, width() - destRect.x); + destRect.h = std::min(destRect.h, height() - destRect.y); - bool fastBlit = !p->touchesTaintedArea(posRect) && txtAlpha == 1.0f; + IntRect sourceRect; + sourceRect.w = destRect.w / squeeze; + sourceRect.h = destRect.h; - if (fastBlit) - { - if (squeeze == 1.0f && !shState->config().subImageFix) - { - /* Even faster: upload directly to bitmap texture. - * We have to make sure the posRect lies within the texture - * boundaries or texSubImage will generate errors. - * If it partly lies outside bounds we have to upload - * the clipped visible part of it. */ - SDL_Rect btmRect; - btmRect.x = btmRect.y = 0; - btmRect.w = width(); - btmRect.h = height(); - - SDL_Rect txtRect; - txtRect.x = posRect.x; - txtRect.y = posRect.y; - txtRect.w = posRect.w; - txtRect.h = posRect.h; - - SDL_Rect inters; - - /* If we have no intersection at all, - * there's nothing to upload to begin with */ - if (SDL_IntersectRect(&btmRect, &txtRect, &inters)) - { - bool subImage = false; - int subSrcX = 0, subSrcY = 0; - - if (inters.w != txtRect.w || inters.h != txtRect.h) - { - /* Clip the text surface */ - subSrcX = inters.x - txtRect.x; - subSrcY = inters.y - txtRect.y; - subImage = true; - - posRect.x = inters.x; - posRect.y = inters.y; - posRect.w = inters.w; - posRect.h = inters.h; - } - - TEX::bind(p->gl.tex); - - if (!subImage) - { - TEX::uploadSubImage(posRect.x, posRect.y, - posRect.w, posRect.h, - txtSurf->pixels, GL_RGBA); - } - else - { - GLMeta::subRectImageUpload(txtSurf->w, subSrcX, subSrcY, - posRect.x, posRect.y, - posRect.w, posRect.h, - txtSurf, GL_RGBA); - GLMeta::subRectImageEnd(); - } - } - } - else - { - /* Squeezing involved: need to use intermediary TexFBO */ - TEXFBO &gpTF = shState->gpTexFBO(txtSurf->w, txtSurf->h); - - TEX::bind(gpTF.tex); - TEX::uploadSubImage(0, 0, txtSurf->w, txtSurf->h, txtSurf->pixels, GL_RGBA); - - GLMeta::blitBegin(p->gl); - GLMeta::blitSource(gpTF); - GLMeta::blitRectangle(IntRect(0, 0, txtSurf->w, txtSurf->h), - posRect, true); - GLMeta::blitEnd(); - } - } - else - { - /* Aquire a partial copy of the destination - * buffer we're about to render to */ - TEXFBO &gpTex2 = shState->gpTexFBO(posRect.w, posRect.h); - - GLMeta::blitBegin(gpTex2); - GLMeta::blitSource(p->gl); - GLMeta::blitRectangle(posRect, Vec2i()); - GLMeta::blitEnd(); - - FloatRect bltRect(0, 0, - (float) (gpTexSize.x * squeeze) / gpTex2.width, - (float) gpTexSize.y / gpTex2.height); - - BltShader &shader = shState->shaders().blt; - shader.bind(); - shader.setTexSize(gpTexSize); - shader.setSource(); - shader.setDestination(gpTex2.tex); - shader.setSubRect(bltRect); - shader.setOpacity(txtAlpha); - - shState->bindTex(); - TEX::uploadSubImage(0, 0, txtSurf->w, txtSurf->h, txtSurf->pixels, GL_RGBA); - TEX::setSmooth(true); - - Quad &quad = shState->gpQuad(); - quad.setTexRect(FloatRect(0, 0, txtSurf->w, txtSurf->h)); - quad.setPosRect(posRect); - - p->bindFBO(); - p->pushSetViewport(shader); - - p->blitQuad(quad); - - p->popViewport(); - } - - SDL_FreeSurface(txtSurf); - p->addTaintedArea(posRect); - - p->onModified(); + Bitmap txtBitmap(txtSurf, nullptr, true); + bool smooth = squeeze != 1.0f; + stretchBlt(destRect, txtBitmap, sourceRect, fontColor.alpha, smooth); } /* http://www.lemoda.net/c/utf8-to-ucs2/index.html */ diff --git a/src/display/bitmap.h b/src/display/bitmap.h index dbf9a82..30e2828 100644 --- a/src/display/bitmap.h +++ b/src/display/bitmap.h @@ -68,7 +68,7 @@ public: void stretchBlt(IntRect destRect, const Bitmap &source, IntRect sourceRect, - int opacity = 255); + int opacity = 255, bool smooth = false); void fillRect(int x, int y, int width, int height, From 7539a2f34b4254da641b3a20c4e066f878c026bb Mon Sep 17 00:00:00 2001 From: Wayward Heart <91356680+WaywardHeart@users.noreply.github.com> Date: Mon, 18 Mar 2024 03:42:22 -0500 Subject: [PATCH 4/7] Use SDL_LowerBlitScaled/SDL_SoftStretchLinear instead of SDL_BlitScaled --- src/display/bitmap.cpp | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/display/bitmap.cpp b/src/display/bitmap.cpp index 5e50f58..127c1d4 100644 --- a/src/display/bitmap.cpp +++ b/src/display/bitmap.cpp @@ -1086,7 +1086,16 @@ void Bitmap::stretchBlt(IntRect destRect, throw Exception(Exception::SDLError, "Error creating temporary surface for blitting: %s", SDL_GetError()); - error = SDL_BlitScaled(srcSurf, &srcRect, blitTemp, 0); + if (smooth) + { + error = SDL_SoftStretchLinear(srcSurf, &srcRect, blitTemp, 0); + smooth = false; + } + else + { + SDL_Rect tmpRect = {0, 0, blitTemp->w, blitTemp->h}; + error = SDL_LowerBlitScaled(srcSurf, &srcRect, blitTemp, &tmpRect); + } } else { @@ -1099,7 +1108,8 @@ void Bitmap::stretchBlt(IntRect destRect, throw Exception(Exception::SDLError, "Error creating temporary surface for blitting: %s", SDL_GetError()); - error = SDL_BlitSurface(srcSurf, &srcRect, blitTemp, 0); + SDL_Rect tmpRect = {0, 0, blitTemp->w, blitTemp->h}; + error = SDL_LowerBlit(srcSurf, &srcRect, blitTemp, &tmpRect); } if (error) From 46d9095129e561aea0e8e1bb6432f84c308824b7 Mon Sep 17 00:00:00 2001 From: Wayward Heart <91356680+WaywardHeart@users.noreply.github.com> Date: Sun, 24 Mar 2024 02:41:39 -0500 Subject: [PATCH 5/7] Use gl.unpack_subimage when blitting megasurfaces to textures when available --- src/display/bitmap.cpp | 74 ++++++++++++++++++++++++++++++++++++------ 1 file changed, 64 insertions(+), 10 deletions(-) diff --git a/src/display/bitmap.cpp b/src/display/bitmap.cpp index 127c1d4..9c0ec66 100644 --- a/src/display/bitmap.cpp +++ b/src/display/bitmap.cpp @@ -1052,6 +1052,7 @@ void Bitmap::stretchBlt(IntRect destRect, SDL_Surface *srcSurf = source.megaSurface(); SDL_Surface *blitTemp = 0; bool touchesTaintedArea = p->touchesTaintedArea(destRect); + bool unpack_subimage = srcSurf && gl.unpack_subimage; if (!srcSurf && opacity == 255 && !touchesTaintedArea) { @@ -1069,8 +1070,10 @@ void Bitmap::stretchBlt(IntRect destRect, bool subImageFix = shState->config().subImageFix; bool srcRectTooBig = srcRect.w > glState.caps.maxTexSize || srcRect.h > glState.caps.maxTexSize; - bool srcSurfTooBig = srcSurf->w > glState.caps.maxTexSize || - srcSurf->h > glState.caps.maxTexSize; + bool srcSurfTooBig = !unpack_subimage && ( + srcSurf->w > glState.caps.maxTexSize || + srcSurf->h > glState.caps.maxTexSize + ); if (srcRectTooBig || srcSurfTooBig) { @@ -1096,6 +1099,7 @@ void Bitmap::stretchBlt(IntRect destRect, SDL_Rect tmpRect = {0, 0, blitTemp->w, blitTemp->h}; error = SDL_LowerBlitScaled(srcSurf, &srcRect, blitTemp, &tmpRect); } + unpack_subimage = false; } else { @@ -1130,24 +1134,51 @@ void Bitmap::stretchBlt(IntRect destRect, { if (!subImageFix && sourceRect.w == destRect.w && sourceRect.h == destRect.h && - srcSurf->w == sourceRect.w && srcSurf->h == sourceRect.h) + (unpack_subimage || (srcSurf->w == sourceRect.w && srcSurf->h == sourceRect.h)) + ) { /* No scaling needed */ TEX::bind(getGLTypes().tex); + if (unpack_subimage) + { + gl.PixelStorei(GL_UNPACK_ROW_LENGTH, srcSurf->w); + gl.PixelStorei(GL_UNPACK_SKIP_PIXELS, sourceRect.x); + gl.PixelStorei(GL_UNPACK_SKIP_ROWS, sourceRect.y); + } TEX::uploadSubImage(destRect.x, destRect.y, destRect.w, destRect.h, srcSurf->pixels, GL_RGBA); + + if (unpack_subimage) + GLMeta::subRectImageEnd(); } else { /* Resizing or subImageFix involved: need to use intermediary TexFBO */ - TEXFBO &gpTF = shState->gpTexFBO(srcSurf->w, srcSurf->h); + TEXFBO *gpTF; + if (unpack_subimage) + gpTF = &shState->gpTexFBO(sourceRect.w, sourceRect.h); + else + gpTF = &shState->gpTexFBO(srcSurf->w, srcSurf->h); + TEX::bind(gpTF->tex); - TEX::bind(gpTF.tex); - TEX::uploadSubImage(0, 0, srcSurf->w, srcSurf->h, srcSurf->pixels, GL_RGBA); + if (unpack_subimage) + { + gl.PixelStorei(GL_UNPACK_ROW_LENGTH, srcSurf->w); + gl.PixelStorei(GL_UNPACK_SKIP_PIXELS, sourceRect.x); + gl.PixelStorei(GL_UNPACK_SKIP_ROWS, sourceRect.y); + sourceRect.x = 0; + sourceRect.y = 0; + TEX::uploadSubImage(0, 0, sourceRect.w, sourceRect.h, srcSurf->pixels, GL_RGBA); + GLMeta::subRectImageEnd(); + } + else + { + TEX::uploadSubImage(0, 0, srcSurf->w, srcSurf->h, srcSurf->pixels, GL_RGBA); + } GLMeta::blitBegin(getGLTypes()); - GLMeta::blitSource(gpTF); + GLMeta::blitSource(*gpTF); GLMeta::blitRectangle(sourceRect, destRect, smooth); GLMeta::blitEnd(); } @@ -1172,9 +1203,34 @@ void Bitmap::stretchBlt(IntRect destRect, FloatRect bltSubRect; if (srcSurf) { - shState->ensureTexSize(srcSurf->w, srcSurf->h, gpTexSize); + if (unpack_subimage) + { + shState->ensureTexSize(sourceRect.w, sourceRect.h, gpTexSize); + } + else + { + shState->ensureTexSize(srcSurf->w, srcSurf->h, gpTexSize); + } sourceWidth = gpTexSize.x; sourceHeight = gpTexSize.y; + + shState->bindTex(); + + if (unpack_subimage) + { + gl.PixelStorei(GL_UNPACK_ROW_LENGTH, srcSurf->w); + gl.PixelStorei(GL_UNPACK_SKIP_PIXELS, sourceRect.x); + gl.PixelStorei(GL_UNPACK_SKIP_ROWS, sourceRect.y); + sourceRect.x = 0; + sourceRect.y = 0; + + TEX::uploadSubImage(0, 0, sourceRect.w, sourceRect.h, srcSurf->pixels, GL_RGBA); + GLMeta::subRectImageEnd(); + } + else + { + TEX::uploadSubImage(0, 0, srcSurf->w, srcSurf->h, srcSurf->pixels, GL_RGBA); + } } else { @@ -1190,8 +1246,6 @@ void Bitmap::stretchBlt(IntRect destRect, shader.bind(); if (srcSurf) { - shState->bindTex(); - TEX::uploadSubImage(0, 0, srcSurf->w, srcSurf->h, srcSurf->pixels, GL_RGBA); shader.setTexSize(gpTexSize); } else From cf762c77f1633da3184ea631fed1d065eb3231b9 Mon Sep 17 00:00:00 2001 From: Wayward Heart <91356680+WaywardHeart@users.noreply.github.com> Date: Mon, 18 Mar 2024 11:45:08 -0500 Subject: [PATCH 6/7] Only draw text to the hires bitmap when Hires mode is enabled --- src/display/bitmap.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/display/bitmap.cpp b/src/display/bitmap.cpp index 9c0ec66..9f7baf1 100644 --- a/src/display/bitmap.cpp +++ b/src/display/bitmap.cpp @@ -2000,6 +2000,8 @@ void Bitmap::drawText(const IntRect &rect, const char *str, int align) int rectHeight = rect.h * p->selfHires->height() / height(); p->selfHires->drawText(IntRect(rectX, rectY, rectWidth, rectHeight), str, align); + + return; } std::string fixed = fixupString(str); From 8b14894b6f4ce54acf4cba74bcb214b659226c0e Mon Sep 17 00:00:00 2001 From: Wayward Heart <91356680+WaywardHeart@users.noreply.github.com> Date: Sun, 24 Mar 2024 07:38:42 -0500 Subject: [PATCH 7/7] Fix blitting with negative dimensions --- src/display/bitmap.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/display/bitmap.cpp b/src/display/bitmap.cpp index 9f7baf1..95768f1 100644 --- a/src/display/bitmap.cpp +++ b/src/display/bitmap.cpp @@ -925,7 +925,7 @@ void Bitmap::blt(int x, int y, if (source.isDisposed()) return; - stretchBlt(IntRect(x, y, rect.w, rect.h), + stretchBlt(IntRect(x, y, abs(rect.w), abs(rect.h)), source, rect, opacity); }