diff --git a/mkxp.conf.sample b/mkxp.conf.sample index 256b44c..589ae1e 100644 --- a/mkxp.conf.sample +++ b/mkxp.conf.sample @@ -94,6 +94,15 @@ # solidFonts=false +# Work around buggy graphics drivers which don't +# properly synchronize texture access, most +# apparent when text doesn't show up or the map +# tileset doesn't render at all +# (default: disabled) +# +# subImageFix=false + + # Set the base path of the game to '/path/to/game' # (default: executable directory) # diff --git a/src/bitmap.cpp b/src/bitmap.cpp index 37b3984..8fdf118 100644 --- a/src/bitmap.cpp +++ b/src/bitmap.cpp @@ -374,14 +374,46 @@ void Bitmap::stretchBlt(const IntRect &destRect, if (opacity == 0) return; - if (source.megaSurface()) + SDL_Surface *srcSurf = source.megaSurface(); + + 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_Surface *srcSurf = source.megaSurface(); - SDL_Rect srcRect = sourceRect; SDL_Rect dstRect = destRect; SDL_Rect btmRect = { 0, 0, width(), height() }; @@ -405,18 +437,19 @@ void Bitmap::stretchBlt(const IntRect &destRect, 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(); @@ -468,7 +501,6 @@ void Bitmap::stretchBlt(const IntRect &destRect, } p->addTaintedArea(destRect); - p->onModified(); } @@ -1023,7 +1055,7 @@ void Bitmap::drawText(const IntRect &rect, const char *str, int align) if (fastBlit) { - if (squeeze == 1.0) + if (squeeze == 1.0 && !shState->config().subImageFix) { /* Even faster: upload directly to bitmap texture. * We have to make sure the posRect lies within the texture diff --git a/src/config.cpp b/src/config.cpp index 909204d..fb2e676 100644 --- a/src/config.cpp +++ b/src/config.cpp @@ -153,6 +153,7 @@ Config::Config() fixedFramerate(0), frameSkip(true), solidFonts(false), + subImageFix(false), gameFolder("."), anyAltToggleFS(false), enableReset(true), @@ -181,6 +182,7 @@ void Config::read(int argc, char *argv[]) PO_DESC(fixedFramerate, int) \ PO_DESC(frameSkip, bool) \ PO_DESC(solidFonts, bool) \ + PO_DESC(subImageFix, bool) \ PO_DESC(gameFolder, std::string) \ PO_DESC(anyAltToggleFS, bool) \ PO_DESC(enableReset, bool) \ diff --git a/src/config.h b/src/config.h index 9563bb1..71cfb42 100644 --- a/src/config.h +++ b/src/config.h @@ -89,6 +89,8 @@ struct Config bool solidFonts; + bool subImageFix; + std::string gameFolder; bool anyAltToggleFS; bool enableReset; diff --git a/src/tilemap.cpp b/src/tilemap.cpp index 3d1ab58..dd944f5 100644 --- a/src/tilemap.cpp +++ b/src/tilemap.cpp @@ -26,6 +26,7 @@ #include "table.h" #include "sharedstate.h" +#include "config.h" #include "glstate.h" #include "gl-util.h" #include "gl-meta.h" @@ -542,19 +543,59 @@ struct TilemapPrivate if (tileset->megaSurface()) { /* Mega surface tileset */ - TEX::bind(atlas.gl.tex); - SDL_Surface *tsSurf = tileset->megaSurface(); - for (size_t i = 0; i < blits.size(); ++i) + if (shState->config().subImageFix) { - const TileAtlas::Blit &blitOp = blits[i]; + /* Implementation for broken GL drivers */ + FBO::bind(atlas.gl.fbo); + glState.blend.pushSet(false); + glState.viewport.pushSet(IntRect(0, 0, atlas.size.x, atlas.size.y)); - GLMeta::subRectImageUpload(tsSurf->w, blitOp.src.x, blitOp.src.y, - blitOp.dst.x, blitOp.dst.y, tsLaneW, blitOp.h, tsSurf, GL_RGBA); + SimpleShader &shader = shState->shaders().simple; + shader.bind(); + shader.applyViewportProj(); + shader.setTranslation(Vec2i()); + + Quad &quad = shState->gpQuad(); + + for (size_t i = 0; i < blits.size(); ++i) + { + const TileAtlas::Blit &blitOp = blits[i]; + + Vec2i texSize; + shState->ensureTexSize(tsLaneW, blitOp.h, texSize); + shState->bindTex(); + GLMeta::subRectImageUpload(tsSurf->w, blitOp.src.x, blitOp.src.y, + 0, 0, tsLaneW, blitOp.h, tsSurf, GL_RGBA); + + shader.setTexSize(texSize); + quad.setTexRect(FloatRect(0, 0, tsLaneW, blitOp.h)); + quad.setPosRect(FloatRect(blitOp.dst.x, blitOp.dst.y, tsLaneW, blitOp.h)); + + quad.draw(); + } + + GLMeta::subRectImageEnd(); + glState.viewport.pop(); + glState.blend.pop(); + } + else + { + /* Clean implementation */ + TEX::bind(atlas.gl.tex); + + for (size_t i = 0; i < blits.size(); ++i) + { + const TileAtlas::Blit &blitOp = blits[i]; + + GLMeta::subRectImageUpload(tsSurf->w, blitOp.src.x, blitOp.src.y, + blitOp.dst.x, blitOp.dst.y, tsLaneW, blitOp.h, tsSurf, GL_RGBA); + } + + GLMeta::subRectImageEnd(); } - GLMeta::subRectImageEnd(); } else {