From d753e48ca156ad92af45a1f00cd4fa7c0048575f Mon Sep 17 00:00:00 2001 From: Logan McNaughton Date: Mon, 19 Apr 2021 16:21:50 -0600 Subject: [PATCH] update gliden64 --- .../src/BufferCopy/ColorBufferToRDRAM.cpp | 195 ++++-------------- GLideN64/src/BufferCopy/ColorBufferToRDRAM.h | 14 -- .../src/BufferCopy/RDRAMtoColorBuffer.cpp | 1 - GLideN64/src/Config.cpp | 5 + GLideN64/src/Config.h | 3 + .../src/DepthBufferRender/ClipPolygon.cpp | 80 ++++--- GLideN64/src/DisplayWindow.h | 6 +- GLideN64/src/FrameBuffer.cpp | 109 ++++++++++ GLideN64/src/FrameBuffer.h | 15 ++ GLideN64/src/GLideNUI/ConfigDialog.cpp | 6 + GLideN64/src/GLideNUI/Settings.cpp | 3 + GLideN64/src/GLideNUI/configDialog.ui | 24 ++- .../GLSL/glsl_CombinerProgramBuilder.cpp | 86 +++++--- .../GLSL/glsl_CombinerProgramBuilder.h | 1 + .../glsl_CombinerProgramUniformFactory.cpp | 165 +++++++++++++-- .../OpenGLContext/GLSL/glsl_ShaderStorage.h | 2 +- .../GraphicBuffer/GraphicBufferWrapper.cpp | 14 +- .../GraphicBuffer/GraphicBufferWrapper.h | 2 + .../opengl_ColorBufferReaderWithEGLImage.cpp | 2 +- GLideN64/src/GraphicsDrawer.cpp | 160 ++++---------- GLideN64/src/GraphicsDrawer.h | 3 +- GLideN64/src/TexrectDrawer.cpp | 36 ++-- GLideN64/src/TexrectDrawer.h | 2 - GLideN64/src/VI.cpp | 21 ++ GLideN64/src/gDP.cpp | 9 + GLideN64/src/gDP.h | 10 +- GLideN64/src/gSP.cpp | 48 +---- GLideN64/src/mupenplus/Config_mupenplus.cpp | 9 + 28 files changed, 590 insertions(+), 441 deletions(-) diff --git a/GLideN64/src/BufferCopy/ColorBufferToRDRAM.cpp b/GLideN64/src/BufferCopy/ColorBufferToRDRAM.cpp index bfe0e1f..b1d1a61 100644 --- a/GLideN64/src/BufferCopy/ColorBufferToRDRAM.cpp +++ b/GLideN64/src/BufferCopy/ColorBufferToRDRAM.cpp @@ -12,17 +12,6 @@ #include "Log.h" #include "MemoryStatus.h" -/* -#include "ColorBufferToRDRAM_GL.h" -#include "ColorBufferToRDRAM_BufferStorageExt.h" -#elif defined(OS_ANDROID) && defined (GLES2) -#include "ColorBufferToRDRAM_GL.h" -#include "ColorBufferToRDRAM_GLES.h" -#else -#include "ColorBufferToRDRAMStub.h" -#endif -*/ - #include #include #include @@ -32,16 +21,10 @@ using namespace graphics; ColorBufferToRDRAM::ColorBufferToRDRAM() - : m_FBO(0) - , m_pTexture(nullptr) - , m_pCurFrameBuffer(nullptr) + : m_pCurFrameBuffer(nullptr) , m_frameCount(-1) , m_startAddress(-1) - , m_lastBufferWidth(-1) { - m_allowedRealWidths[0] = 320; - m_allowedRealWidths[1] = 480; - m_allowedRealWidths[2] = 640; } u32 ColorBufferToRDRAM::m_blueNoiseIdx = 0; @@ -52,88 +35,10 @@ ColorBufferToRDRAM::~ColorBufferToRDRAM() void ColorBufferToRDRAM::init() { - m_FBO = gfxContext.createFramebuffer(); } void ColorBufferToRDRAM::destroy() { - _destroyFBTexure(); - if (m_FBO.isNotNull()) { - gfxContext.deleteFramebuffer(m_FBO); - m_FBO.reset(); - } -} - -void ColorBufferToRDRAM::_initFBTexture(void) -{ - const FramebufferTextureFormats & fbTexFormat = gfxContext.getFramebufferTextureFormats(); - - m_pTexture = textureCache().addFrameBufferTexture(Context::EglImage ? textureTarget::TEXTURE_EXTERNAL : textureTarget::TEXTURE_2D); - m_pTexture->format = G_IM_FMT_RGBA; - m_pTexture->size = 2; - m_pTexture->clampS = 1; - m_pTexture->clampT = 1; - m_pTexture->frameBufferTexture = CachedTexture::fbOneSample; - m_pTexture->maskS = 0; - m_pTexture->maskT = 0; - m_pTexture->mirrorS = 0; - m_pTexture->mirrorT = 0; - //The actual VI width is not used for texture width because most texture widths - //cause slowdowns in the glReadPixels call, at least on Android - m_pTexture->width = m_lastBufferWidth; - m_pTexture->height = VI_GetMaxBufferHeight(m_lastBufferWidth); - m_pTexture->textureBytes = m_pTexture->width * m_pTexture->height * fbTexFormat.colorFormatBytes; - - - m_bufferReader.reset(gfxContext.createColorBufferReader(m_pTexture)); - - // Skip this since texture is initialized in the EGL color buffer reader - if (!Context::EglImage) - { - Context::InitTextureParams params; - params.handle = m_pTexture->name; - params.target = textureTarget::TEXTURE_2D; - params.width = m_pTexture->width; - params.height = m_pTexture->height; - params.internalFormat = fbTexFormat.colorInternalFormat; - params.format = fbTexFormat.colorFormat; - params.dataType = fbTexFormat.colorType; - gfxContext.init2DTexture(params); - } - - { - Context::TexParameters params; - params.handle = m_pTexture->name; - params.target = Context::EglImage ? textureTarget::TEXTURE_EXTERNAL : textureTarget::TEXTURE_2D; - params.textureUnitIndex = textureIndices::Tex[0]; - params.minFilter = textureParameters::FILTER_LINEAR; - params.magFilter = textureParameters::FILTER_LINEAR; - gfxContext.setTextureParameters(params); - } - { - Context::FrameBufferRenderTarget bufTarget; - bufTarget.bufferHandle = ObjectHandle(m_FBO); - bufTarget.bufferTarget = bufferTarget::DRAW_FRAMEBUFFER; - bufTarget.attachment = bufferAttachment::COLOR_ATTACHMENT0; - bufTarget.textureTarget = Context::EglImageFramebuffer ? textureTarget::TEXTURE_EXTERNAL : textureTarget::TEXTURE_2D; - bufTarget.textureHandle = m_pTexture->name; - gfxContext.addFrameBufferRenderTarget(bufTarget); - } - - // check if everything is OK - assert(!gfxContext.isFramebufferError()); - - gfxContext.bindFramebuffer(graphics::bufferTarget::DRAW_FRAMEBUFFER, graphics::ObjectHandle::defaultFramebuffer); -} - -void ColorBufferToRDRAM::_destroyFBTexure(void) -{ - m_bufferReader.reset(); - - if (m_pTexture != nullptr) { - textureCache().removeFrameBufferTexture(m_pTexture); - m_pTexture = nullptr; - } } bool ColorBufferToRDRAM::_prepareCopy(u32& _startAddress) @@ -164,15 +69,7 @@ bool ColorBufferToRDRAM::_prepareCopy(u32& _startAddress) if (bufferHeight == 0) return false; - if(m_pTexture == nullptr || - m_pTexture->width != _getRealWidth(pBuffer->m_width) || - m_pTexture->height != VI_GetMaxBufferHeight(_getRealWidth(pBuffer->m_width))) - { - _destroyFBTexure(); - - m_lastBufferWidth = _getRealWidth(pBuffer->m_width); - _initFBTexture(); - } + CachedTexture* colorBufferTexture = pBuffer->getColorFbTexture(); m_pCurFrameBuffer = pBuffer; @@ -190,47 +87,43 @@ bool ColorBufferToRDRAM::_prepareCopy(u32& _startAddress) readBuffer = m_pCurFrameBuffer->m_FBO; } - if (m_pCurFrameBuffer->m_scale != 1.0f) { - u32 x0 = 0; - u32 width; - if (config.frameBufferEmulation.nativeResFactor == 0) { - const u32 screenWidth = wnd.getWidth(); - width = screenWidth; - if (wnd.isAdjustScreen()) { - width = static_cast(screenWidth*wnd.getAdjustScale()); - x0 = (screenWidth - width) / 2; - } - } else { - width = m_pCurFrameBuffer->m_pTexture->width; + u32 x0 = 0; + u32 width; + if (config.frameBufferEmulation.nativeResFactor == 0) { + const u32 screenWidth = wnd.getWidth(); + width = screenWidth; + if (wnd.isAdjustScreen()) { + width = static_cast(screenWidth*wnd.getAdjustScale()); + x0 = (screenWidth - width) / 2; } - u32 height = (u32)(bufferHeight * m_pCurFrameBuffer->m_scale); - - CachedTexture * pInputTexture = m_pCurFrameBuffer->m_pTexture; - GraphicsDrawer::BlitOrCopyRectParams blitParams; - blitParams.srcX0 = x0; - blitParams.srcY0 = 0; - blitParams.srcX1 = x0 + width; - blitParams.srcY1 = height; - blitParams.srcWidth = pInputTexture->width; - blitParams.srcHeight = pInputTexture->height; - blitParams.dstX0 = 0; - blitParams.dstY0 = 0; - blitParams.dstX1 = m_pCurFrameBuffer->m_width; - blitParams.dstY1 = bufferHeight; - blitParams.dstWidth = m_pTexture->width; - blitParams.dstHeight = m_pTexture->height; - blitParams.filter = textureParameters::FILTER_LINEAR; - blitParams.tex[0] = pInputTexture; - blitParams.combiner = CombinerInfo::get().getTexrectDownscaleCopyProgram(); - blitParams.readBuffer = readBuffer; - blitParams.drawBuffer = m_FBO; - blitParams.mask = blitMask::COLOR_BUFFER; - wnd.getDrawer().blitOrCopyTexturedRect(blitParams); - - gfxContext.bindFramebuffer(bufferTarget::READ_FRAMEBUFFER, m_FBO); } else { - gfxContext.bindFramebuffer(bufferTarget::READ_FRAMEBUFFER, readBuffer); + width = m_pCurFrameBuffer->m_pTexture->width; } + u32 height = (u32)(bufferHeight * m_pCurFrameBuffer->m_scale); + + CachedTexture * pInputTexture = m_pCurFrameBuffer->m_pTexture; + GraphicsDrawer::BlitOrCopyRectParams blitParams; + blitParams.srcX0 = x0; + blitParams.srcY0 = 0; + blitParams.srcX1 = x0 + width; + blitParams.srcY1 = height; + blitParams.srcWidth = pInputTexture->width; + blitParams.srcHeight = pInputTexture->height; + blitParams.dstX0 = 0; + blitParams.dstY0 = 0; + blitParams.dstX1 = m_pCurFrameBuffer->m_width; + blitParams.dstY1 = bufferHeight; + blitParams.dstWidth = colorBufferTexture->width; + blitParams.dstHeight = colorBufferTexture->height; + blitParams.filter = m_pCurFrameBuffer->m_scale == 1.0f ? textureParameters::FILTER_NEAREST : textureParameters::FILTER_LINEAR; + blitParams.tex[0] = pInputTexture; + blitParams.combiner = CombinerInfo::get().getTexrectDownscaleCopyProgram(); + blitParams.readBuffer = readBuffer; + blitParams.drawBuffer = pBuffer->getColorFbFbo(); + blitParams.mask = blitMask::COLOR_BUFFER; + wnd.getDrawer().blitOrCopyTexturedRect(blitParams); + + gfxContext.bindFramebuffer(bufferTarget::READ_FRAMEBUFFER, pBuffer->getColorFbFbo()); m_frameCount = curFrame; m_startAddress = _startAddress; @@ -312,7 +205,7 @@ void ColorBufferToRDRAM::_copy(u32 _startAddress, u32 _endAddress, bool _sync) const u32 y1 = (_endAddress - m_pCurFrameBuffer->m_startAddress) / stride; const u32 height = std::min(max_height, 1u + y1 - y0); - const u8* pPixels = m_bufferReader->readPixels(x0, y0, width, height, m_pCurFrameBuffer->m_size, _sync); + const u8* pPixels = m_pCurFrameBuffer->readPixels(x0, y0, width, height, m_pCurFrameBuffer->m_size, _sync); frameBufferList().setCurrentDrawBuffer(); if (pPixels == nullptr) return; @@ -336,23 +229,11 @@ void ColorBufferToRDRAM::_copy(u32 _startAddress, u32 _endAddress, bool _sync) m_pCurFrameBuffer->copyRdram(); m_pCurFrameBuffer->m_cleared = false; - m_bufferReader->cleanUp(); + m_pCurFrameBuffer->cleanUp(); gDP.changed |= CHANGED_SCISSOR; } -u32 ColorBufferToRDRAM::_getRealWidth(u32 _viWidth) -{ - u32 index = 0; - const u32 maxIndex = static_cast(m_allowedRealWidths.size()) - 1; - while (index < maxIndex && _viWidth > m_allowedRealWidths[index]) - { - ++index; - } - - return m_allowedRealWidths[index]; -} - void ColorBufferToRDRAM::copyToRDRAM(u32 _address, bool _sync) { if (!isMemoryWritable(RDRAM + _address, gDP.colorImage.width << gDP.colorImage.size >> 1)) diff --git a/GLideN64/src/BufferCopy/ColorBufferToRDRAM.h b/GLideN64/src/BufferCopy/ColorBufferToRDRAM.h index 084c9e7..7248c6a 100644 --- a/GLideN64/src/BufferCopy/ColorBufferToRDRAM.h +++ b/GLideN64/src/BufferCopy/ColorBufferToRDRAM.h @@ -29,8 +29,6 @@ private: ColorBufferToRDRAM(const ColorBufferToRDRAM &) = delete; virtual ~ColorBufferToRDRAM(); - CachedTexture * m_pTexture; - union RGBA { struct { u8 r, g, b, a; @@ -38,32 +36,20 @@ private: u32 raw; }; - void _initFBTexture(void); - - void _destroyFBTexure(void); - bool _prepareCopy(u32& _startAddress); void _copy(u32 _startAddress, u32 _endAddress, bool _sync); - u32 _getRealWidth(u32 _viWidth); - // Convert pixel from video memory to N64 buffer format. static u8 _RGBAtoR8(u8 _c, u32 x, u32 y); static u16 _RGBAtoRGBA16(u32 _c, u32 x, u32 y); static u32 _RGBAtoRGBA32(u32 _c, u32 x, u32 y); - graphics::ObjectHandle m_FBO; FrameBuffer * m_pCurFrameBuffer; u32 m_frameCount; u32 m_startAddress; - u32 m_lastBufferWidth; - static u32 m_blueNoiseIdx; - - std::array m_allowedRealWidths; - std::unique_ptr m_bufferReader; }; void copyWhiteToRDRAM(FrameBuffer * _pBuffer); diff --git a/GLideN64/src/BufferCopy/RDRAMtoColorBuffer.cpp b/GLideN64/src/BufferCopy/RDRAMtoColorBuffer.cpp index d65eb74..bb4fe0e 100644 --- a/GLideN64/src/BufferCopy/RDRAMtoColorBuffer.cpp +++ b/GLideN64/src/BufferCopy/RDRAMtoColorBuffer.cpp @@ -179,7 +179,6 @@ u32 RGBA32ToABGR32(u32 col, bool _fullAlpha) void RDRAMtoColorBuffer::_copyFromRDRAM(u32 _height, bool _fullAlpha) { Cleaner cleaner(this); - ValueKeeper otherMode(gSP.clipRatio, 1U); const u32 address = m_pCurBuffer->m_startAddress; const u32 width = m_pCurBuffer->m_width; const u32 height = _height; diff --git a/GLideN64/src/Config.cpp b/GLideN64/src/Config.cpp index 3ccb5a8..efbe398 100644 --- a/GLideN64/src/Config.cpp +++ b/GLideN64/src/Config.cpp @@ -64,6 +64,7 @@ void Config::resetToDefaults() graphics2D.correctTexrectCoords = tcDisable; graphics2D.enableNativeResTexrects = NativeResTexrectsMode::ntDisable; graphics2D.bgMode = BGMode::bgStripped; + graphics2D.enableTexCoordBounds = 0; frameBufferEmulation.enable = 1; frameBufferEmulation.copyDepthToRDRAM = cdSoftwareRender; @@ -173,6 +174,10 @@ const char* Config::hotkeyIniName(u32 _idx) return "hkHdTexReload"; case Config::HotKey::hkHdTexToggle: return "hkHdTexToggle"; + case Config::HotKey::hkTexCoordBounds: + return "hkTexCoordBounds"; + case Config::HotKey::hkNativeResTexrects: + return "hkNativeResTexrects"; case Config::HotKey::hkVsync: return "hkVsync"; case Config::HotKey::hkFBEmulation: diff --git a/GLideN64/src/Config.h b/GLideN64/src/Config.h index 4922924..41d5866 100644 --- a/GLideN64/src/Config.h +++ b/GLideN64/src/Config.h @@ -92,6 +92,7 @@ struct Config u32 correctTexrectCoords; u32 enableNativeResTexrects; u32 bgMode; + u32 enableTexCoordBounds; } graphics2D; enum Aspect { @@ -221,6 +222,8 @@ struct Config hkTexDump = 0, hkHdTexReload, hkHdTexToggle, + hkTexCoordBounds, + hkNativeResTexrects, hkVsync, hkFBEmulation, hkN64DepthCompare, diff --git a/GLideN64/src/DepthBufferRender/ClipPolygon.cpp b/GLideN64/src/DepthBufferRender/ClipPolygon.cpp index b45a3cc..5183f39 100644 --- a/GLideN64/src/DepthBufferRender/ClipPolygon.cpp +++ b/GLideN64/src/DepthBufferRender/ClipPolygon.cpp @@ -28,6 +28,7 @@ #include "gSP.h" #include "Combiner.h" #include "ClipPolygon.h" +#include "DisplayWindow.h" /* * vbp is a pointer to a vertex array. The first 3 vertices in that @@ -289,6 +290,7 @@ void clipInHomogeneousSpace(SPVertex * _pVertices, std::vector & _vRes const bool usesColor = pCurrCmb->usesShade(); const bool usesTexture = pCurrCmb->usesTexture(); const float wScale = static_cast(gSP.clipRatio); + const float xScale = dwnd().getAdjustScale(); auto clipVertex = [usesColor, usesTexture](SPVertex const* src, SPVertex * dst, float t) { @@ -363,10 +365,10 @@ void clipInHomogeneousSpace(SPVertex * _pVertices, std::vector & _vRes switch (_clipPlane) { case 1: - visible = -pVertex->w * wScale <= pVertex->x; + visible = -pVertex->w * wScale <= pVertex->x * xScale; break; case 2: - visible = pVertex->x <= pVertex->w * wScale; + visible = pVertex->x * xScale <= pVertex->w * wScale; break; case 3: visible = -pVertex->w * wScale <= pVertex->y; @@ -402,36 +404,49 @@ void clipInHomogeneousSpace(SPVertex * _pVertices, std::vector & _vRes SPVertex *Vertex3 = _pVertices + fifocp; float t1, t2; + const float scaledW1 = Vertex1->w * wScale; + const float scaledW2 = Vertex2->w * wScale; + const float scaledW3 = Vertex3->w * wScale; switch (_clipPlane) { case 1: - t1 = (Vertex1->x + Vertex1->w * wScale) / (Vertex1->x - Vertex3->x + Vertex1->w * wScale - Vertex3->w * wScale); - t2 = (Vertex2->x + Vertex2->w * wScale) / (Vertex2->x - Vertex3->x + Vertex2->w * wScale - Vertex3->w * wScale); + { + const float scaledX1 = Vertex1->x * xScale; + const float scaledX2 = Vertex2->x * xScale; + const float scaledX3 = Vertex3->x * xScale; + t1 = (scaledX1 + scaledW1) / (scaledX1 - scaledX3 + scaledW1 - scaledW3); + t2 = (scaledX2 + scaledW2) / (scaledX2 - scaledX3 + scaledW2 - scaledW3); + } break; case 2: - t1 = (Vertex1->x - Vertex1->w * wScale) / (Vertex1->x - Vertex3->x - Vertex1->w * wScale + Vertex3->w * wScale); - t2 = (Vertex2->x - Vertex2->w * wScale) / (Vertex2->x - Vertex3->x - Vertex2->w * wScale + Vertex3->w * wScale); + { + const float scaledX1 = Vertex1->x * xScale; + const float scaledX2 = Vertex2->x * xScale; + const float scaledX3 = Vertex3->x * xScale; + t1 = (scaledX1 - scaledW1) / (scaledX1 - scaledX3 - scaledW1 + scaledW3); + t2 = (scaledX2 - scaledW2) / (scaledX2 - scaledX3 - scaledW2 + scaledW3); + } break; case 3: - t1 = (Vertex1->y + Vertex1->w * wScale) / (Vertex1->y - Vertex3->y + Vertex1->w * wScale - Vertex3->w * wScale); - t2 = (Vertex2->y + Vertex2->w * wScale) / (Vertex2->y - Vertex3->y + Vertex2->w * wScale - Vertex3->w * wScale); + t1 = (Vertex1->y + scaledW1) / (Vertex1->y - Vertex3->y + scaledW1 - scaledW3); + t2 = (Vertex2->y + scaledW2) / (Vertex2->y - Vertex3->y + scaledW2 - scaledW3); break; case 4: - t1 = (Vertex1->y - Vertex1->w * wScale) / (Vertex1->y - Vertex3->y - Vertex1->w * wScale + Vertex3->w * wScale); - t2 = (Vertex2->y - Vertex2->w * wScale) / (Vertex2->y - Vertex3->y - Vertex2->w * wScale + Vertex3->w * wScale); + t1 = (Vertex1->y - scaledW1) / (Vertex1->y - Vertex3->y - scaledW1 + scaledW3); + t2 = (Vertex2->y - scaledW2) / (Vertex2->y - Vertex3->y - scaledW2 + scaledW3); break; case 5: - t1 = (Vertex1->z + Vertex1->w * wScale) / (Vertex1->z - Vertex3->z + Vertex1->w * wScale - Vertex3->w * wScale); - t2 = (Vertex2->z + Vertex2->w * wScale) / (Vertex2->z - Vertex3->z + Vertex2->w * wScale - Vertex3->w * wScale); + t1 = (Vertex1->z + scaledW1) / (Vertex1->z - Vertex3->z + scaledW1 - scaledW3); + t2 = (Vertex2->z + scaledW2) / (Vertex2->z - Vertex3->z + scaledW2 - scaledW3); break; case 6: - t1 = (Vertex1->z - Vertex1->w * wScale) / (Vertex1->z - Vertex3->z - Vertex1->w * wScale + Vertex3->w * wScale); - t2 = (Vertex2->z - Vertex2->w * wScale) / (Vertex2->z - Vertex3->z - Vertex2->w * wScale + Vertex3->w * wScale); + t1 = (Vertex1->z - scaledW1) / (Vertex1->z - Vertex3->z - scaledW1 + scaledW3); + t2 = (Vertex2->z - scaledW2) / (Vertex2->z - Vertex3->z - scaledW2 + scaledW3); break; } @@ -453,36 +468,49 @@ void clipInHomogeneousSpace(SPVertex * _pVertices, std::vector & _vRes SPVertex *NewVertex3 = NewVertices + fbcp; float t1, t2; + const float scaledW1 = Vertex1->w * wScale; + const float scaledW2 = Vertex2->w * wScale; + const float scaledW3 = Vertex3->w * wScale; switch (_clipPlane) { case 1: - t1 = (Vertex3->x + Vertex3->w * wScale) / (Vertex3->x - Vertex1->x + Vertex3->w * wScale - Vertex1->w * wScale); - t2 = (Vertex3->x + Vertex3->w * wScale) / (Vertex3->x - Vertex2->x + Vertex3->w * wScale - Vertex2->w * wScale); + { + const float scaledX1 = Vertex1->x * xScale; + const float scaledX2 = Vertex2->x * xScale; + const float scaledX3 = Vertex3->x * xScale; + t1 = (scaledX3 + scaledW3) / (scaledX3 - scaledX1 + scaledW3 - scaledW1); + t2 = (scaledX3 + scaledW3) / (scaledX3 - scaledX2 + scaledW3 - scaledW2); + } break; case 2: - t1 = (Vertex3->x - Vertex3->w * wScale) / (Vertex3->x - Vertex1->x - Vertex3->w * wScale + Vertex1->w * wScale); - t2 = (Vertex3->x - Vertex3->w * wScale) / (Vertex3->x - Vertex2->x - Vertex3->w * wScale + Vertex2->w * wScale); + { + const float scaledX1 = Vertex1->x * xScale; + const float scaledX2 = Vertex2->x * xScale; + const float scaledX3 = Vertex3->x * xScale; + t1 = (scaledX3 - scaledW3) / (scaledX3 - scaledX1 - scaledW3 + scaledW1); + t2 = (scaledX3 - scaledW3) / (scaledX3 - scaledX2 - scaledW3 + scaledW2); + } break; case 3: - t1 = (Vertex3->y + Vertex3->w * wScale) / (Vertex3->y - Vertex1->y + Vertex3->w * wScale - Vertex1->w * wScale); - t2 = (Vertex3->y + Vertex3->w * wScale) / (Vertex3->y - Vertex2->y + Vertex3->w * wScale - Vertex2->w * wScale); + t1 = (Vertex3->y + scaledW3) / (Vertex3->y - Vertex1->y + scaledW3 - scaledW1); + t2 = (Vertex3->y + scaledW3) / (Vertex3->y - Vertex2->y + scaledW3 - scaledW2); break; case 4: - t1 = (Vertex3->y - Vertex3->w * wScale) / (Vertex3->y - Vertex1->y - Vertex3->w * wScale + Vertex1->w * wScale); - t2 = (Vertex3->y - Vertex3->w * wScale) / (Vertex3->y - Vertex2->y - Vertex3->w * wScale + Vertex2->w * wScale); + t1 = (Vertex3->y - scaledW3) / (Vertex3->y - Vertex1->y - scaledW3 + scaledW1); + t2 = (Vertex3->y - scaledW3) / (Vertex3->y - Vertex2->y - scaledW3 + scaledW2); break; case 5: - t1 = (Vertex3->z + Vertex3->w * wScale) / (Vertex3->z - Vertex1->z + Vertex3->w * wScale - Vertex1->w * wScale); - t2 = (Vertex3->z + Vertex3->w * wScale) / (Vertex3->z - Vertex2->z + Vertex3->w * wScale - Vertex2->w * wScale); + t1 = (Vertex3->z + scaledW3) / (Vertex3->z - Vertex1->z + scaledW3 - scaledW1); + t2 = (Vertex3->z + scaledW3) / (Vertex3->z - Vertex2->z + scaledW3 - scaledW2); break; case 6: - t1 = (Vertex3->z - Vertex3->w * wScale) / (Vertex3->z - Vertex1->z - Vertex3->w * wScale + Vertex1->w * wScale); - t2 = (Vertex3->z - Vertex3->w * wScale) / (Vertex3->z - Vertex2->z - Vertex3->w * wScale + Vertex2->w * wScale); + t1 = (Vertex3->z - scaledW3) / (Vertex3->z - Vertex1->z - scaledW3 + scaledW1); + t2 = (Vertex3->z - scaledW3) / (Vertex3->z - Vertex2->z - scaledW3 + scaledW2); break; } diff --git a/GLideN64/src/DisplayWindow.h b/GLideN64/src/DisplayWindow.h index 046339a..6b7851f 100644 --- a/GLideN64/src/DisplayWindow.h +++ b/GLideN64/src/DisplayWindow.h @@ -63,9 +63,9 @@ protected: u32 m_resizeWidth = 0; u32 m_resizeHeight = 0; u32 m_maxMsaa = 0; - f32 m_scaleX = 0; - f32 m_scaleY = 0; - f32 m_adjustScale = 0; + f32 m_scaleX = 0.0f; + f32 m_scaleY = 0.0f; + f32 m_adjustScale = 1.0f; wchar_t m_strScreenDirectory[PLUGIN_PATH_SIZE]; diff --git a/GLideN64/src/FrameBuffer.cpp b/GLideN64/src/FrameBuffer.cpp index 48543dc..3e39fc2 100644 --- a/GLideN64/src/FrameBuffer.cpp +++ b/GLideN64/src/FrameBuffer.cpp @@ -25,6 +25,7 @@ #include #include +#include #include "DisplayWindow.h" using namespace std; @@ -32,6 +33,8 @@ using namespace graphics; FrameBuffer::FrameBuffer() : m_copyFBO(ObjectHandle::defaultFramebuffer) + , m_ColorBufferFBO(0) + , m_pColorBufferTexture(nullptr) { m_pTexture = textureCache().addFrameBufferTexture(config.video.multisampling != 0 ? textureTarget::TEXTURE_2D_MULTISAMPLE : textureTarget::TEXTURE_2D); @@ -54,6 +57,8 @@ FrameBuffer::~FrameBuffer() textureCache().removeFrameBufferTexture(m_pResolveTexture); textureCache().removeFrameBufferTexture(m_pSubTexture); textureCache().removeFrameBufferTexture(m_pFrameBufferCopyTexture); + + _destroyColorFBTexure(); } static @@ -529,6 +534,110 @@ CachedTexture * FrameBuffer::getTextureBG() return pTexture; } +CachedTexture * FrameBuffer::getColorFbTexture() +{ + if(m_pColorBufferTexture == nullptr || + m_pColorBufferTexture->width != m_width || + m_pColorBufferTexture->height != VI_GetMaxBufferHeight(m_width)) + { + _destroyColorFBTexure(); + _initColorFBTexture(m_width); + } + + return m_pColorBufferTexture; +} + +graphics::ObjectHandle FrameBuffer::getColorFbFbo() +{ + return m_ColorBufferFBO; +} + +const u8 * FrameBuffer::readPixels(s32 _x0, s32 _y0, u32 _width, u32 _height, u32 _size, bool _sync) +{ + return m_bufferReader->readPixels(_x0, _y0, _width, _height, _size, _sync); +} + +void FrameBuffer::cleanUp() +{ + m_bufferReader->cleanUp(); +} + +void FrameBuffer::_initColorFBTexture(int _width) +{ + m_ColorBufferFBO = gfxContext.createFramebuffer(); + + const FramebufferTextureFormats & fbTexFormat = gfxContext.getFramebufferTextureFormats(); + + m_pColorBufferTexture = textureCache().addFrameBufferTexture(Context::EglImage ? textureTarget::TEXTURE_EXTERNAL : textureTarget::TEXTURE_2D); + m_pColorBufferTexture->format = G_IM_FMT_RGBA; + m_pColorBufferTexture->size = 2; + m_pColorBufferTexture->clampS = 1; + m_pColorBufferTexture->clampT = 1; + m_pColorBufferTexture->frameBufferTexture = CachedTexture::fbOneSample; + m_pColorBufferTexture->maskS = 0; + m_pColorBufferTexture->maskT = 0; + m_pColorBufferTexture->mirrorS = 0; + m_pColorBufferTexture->mirrorT = 0; + m_pColorBufferTexture->width = _width; + m_pColorBufferTexture->height = VI_GetMaxBufferHeight(_width); + m_pColorBufferTexture->textureBytes = m_pColorBufferTexture->width * m_pColorBufferTexture->height * fbTexFormat.colorFormatBytes; + + m_bufferReader.reset(gfxContext.createColorBufferReader(m_pColorBufferTexture)); + + // Skip this since texture is initialized in the EGL color buffer reader + if (!Context::EglImage) + { + Context::InitTextureParams params; + params.handle = m_pColorBufferTexture->name; + params.target = textureTarget::TEXTURE_2D; + params.width = m_pColorBufferTexture->width; + params.height = m_pColorBufferTexture->height; + params.internalFormat = fbTexFormat.colorInternalFormat; + params.format = fbTexFormat.colorFormat; + params.dataType = fbTexFormat.colorType; + gfxContext.init2DTexture(params); + } + + { + Context::TexParameters params; + params.handle = m_pColorBufferTexture->name; + params.target = Context::EglImage ? textureTarget::TEXTURE_EXTERNAL : textureTarget::TEXTURE_2D; + params.textureUnitIndex = textureIndices::Tex[0]; + params.minFilter = textureParameters::FILTER_LINEAR; + params.magFilter = textureParameters::FILTER_LINEAR; + gfxContext.setTextureParameters(params); + } + { + Context::FrameBufferRenderTarget bufTarget; + bufTarget.bufferHandle = ObjectHandle(m_ColorBufferFBO); + bufTarget.bufferTarget = bufferTarget::DRAW_FRAMEBUFFER; + bufTarget.attachment = bufferAttachment::COLOR_ATTACHMENT0; + bufTarget.textureTarget = Context::EglImageFramebuffer ? textureTarget::TEXTURE_EXTERNAL : textureTarget::TEXTURE_2D; + bufTarget.textureHandle = m_pColorBufferTexture->name; + gfxContext.addFrameBufferRenderTarget(bufTarget); + } + + // check if everything is OK + assert(!gfxContext.isFramebufferError()); + + gfxContext.bindFramebuffer(graphics::bufferTarget::DRAW_FRAMEBUFFER, graphics::ObjectHandle::defaultFramebuffer); +} + +void FrameBuffer::_destroyColorFBTexure() +{ + m_bufferReader.reset(); + + if (m_pColorBufferTexture != nullptr) { + textureCache().removeFrameBufferTexture(m_pColorBufferTexture); + m_pColorBufferTexture = nullptr; + } + + if (m_ColorBufferFBO.isNotNull()) { + gfxContext.deleteFramebuffer(m_ColorBufferFBO); + m_ColorBufferFBO.reset(); + } +} + FrameBufferList & FrameBufferList::get() { static FrameBufferList frameBufferList; diff --git a/GLideN64/src/FrameBuffer.h b/GLideN64/src/FrameBuffer.h index 46ac363..6e06dae 100644 --- a/GLideN64/src/FrameBuffer.h +++ b/GLideN64/src/FrameBuffer.h @@ -3,6 +3,7 @@ #include #include +#include #include "gDP.h" #include "Textures.h" @@ -13,6 +14,10 @@ struct DepthBuffer; const u32 fingerprint[4] = { 2, 6, 4, 3 }; +namespace graphics { + class ColorBufferReader; +} + struct FrameBuffer { FrameBuffer(); @@ -28,6 +33,10 @@ struct FrameBuffer void setDirty(); bool isValid(bool _forceCheck) const; bool isAuxiliary() const; + CachedTexture * getColorFbTexture(); + graphics::ObjectHandle getColorFbFbo(); + const u8 * readPixels(s32 _x0, s32 _y0, u32 _width, u32 _height, u32 _size, bool _sync); + void cleanUp(); u32 m_startAddress = 0; u32 m_endAddress = 0; @@ -62,6 +71,10 @@ struct FrameBuffer graphics::ObjectHandle m_depthFBO; CachedTexture *m_pDepthTexture = nullptr; + std::unique_ptr m_bufferReader; + graphics::ObjectHandle m_ColorBufferFBO; + CachedTexture *m_pColorBufferTexture = nullptr; + DepthBuffer *m_pDepthBuffer = nullptr; // multisampling @@ -94,6 +107,8 @@ private: void _initCopyTexture(); CachedTexture * _copyFrameBufferTexture(); CachedTexture * _getSubTexture(u32 _t); + void _initColorFBTexture(int _width); + void _destroyColorFBTexure(); mutable u32 m_validityChecked = false; }; diff --git a/GLideN64/src/GLideNUI/ConfigDialog.cpp b/GLideN64/src/GLideNUI/ConfigDialog.cpp index d91a09d..6f3d4e4 100644 --- a/GLideN64/src/GLideNUI/ConfigDialog.cpp +++ b/GLideN64/src/GLideNUI/ConfigDialog.cpp @@ -80,6 +80,10 @@ QString ConfigDialog::_hotkeyDescription(quint32 _idx) const return tr("Reload HD textures"); case Config::HotKey::hkHdTexToggle: return tr("Toggle HD textures"); + case Config::HotKey::hkTexCoordBounds: + return tr("Toggle texcoords bounds"); + case Config::HotKey::hkNativeResTexrects: + return tr("Toggle 2D texrects in native resolution"); case Config::HotKey::hkVsync: return tr("Toggle VSync"); case Config::HotKey::hkFBEmulation: @@ -241,6 +245,7 @@ void ConfigDialog::_init(bool reInit, bool blockCustomSettings) } ui->halosRemovalCheckBox->setChecked(config.texture.enableHalosRemoval != 0); + ui->texCoordBoundsCheckBox->setChecked(config.graphics2D.enableTexCoordBounds != 0); ui->nativeRes2DComboBox->setCurrentIndex(config.graphics2D.enableNativeResTexrects); @@ -574,6 +579,7 @@ void ConfigDialog::accept(bool justSave) { config.graphics2D.bgMode = Config::BGMode::bgStripped; config.texture.enableHalosRemoval = ui->halosRemovalCheckBox->isChecked() ? 1 : 0; + config.graphics2D.enableTexCoordBounds = ui->texCoordBoundsCheckBox->isChecked() ? 1 : 0; config.graphics2D.enableNativeResTexrects = ui->nativeRes2DComboBox->currentIndex(); config.frameBufferEmulation.enable = ui->frameBufferCheckBox->isChecked() ? 1 : 0; diff --git a/GLideN64/src/GLideNUI/Settings.cpp b/GLideN64/src/GLideNUI/Settings.cpp index d1c3bfe..89f904d 100644 --- a/GLideN64/src/GLideNUI/Settings.cpp +++ b/GLideN64/src/GLideNUI/Settings.cpp @@ -57,6 +57,7 @@ void _loadSettings(QSettings & settings) config.graphics2D.correctTexrectCoords = settings.value("correctTexrectCoords", config.graphics2D.correctTexrectCoords).toInt(); config.graphics2D.enableNativeResTexrects = settings.value("enableNativeResTexrects", config.graphics2D.enableNativeResTexrects).toInt(); config.graphics2D.bgMode = settings.value("bgMode", config.graphics2D.bgMode).toInt(); + config.graphics2D.enableTexCoordBounds = settings.value("enableTexCoordBounds", config.graphics2D.enableTexCoordBounds).toInt(); settings.endGroup(); settings.beginGroup("frameBufferEmulation"); @@ -240,6 +241,7 @@ void writeSettings(const QString & _strIniFolder) settings.setValue("correctTexrectCoords", config.graphics2D.correctTexrectCoords); settings.setValue("enableNativeResTexrects", config.graphics2D.enableNativeResTexrects); settings.setValue("bgMode", config.graphics2D.bgMode); + settings.setValue("enableTexCoordBounds", config.graphics2D.enableTexCoordBounds); settings.endGroup(); settings.beginGroup("frameBufferEmulation"); @@ -437,6 +439,7 @@ void saveCustomRomSettings(const QString & _strIniFolder, const char * _strRomNa WriteCustomSetting(graphics2D, correctTexrectCoords); WriteCustomSetting(graphics2D, enableNativeResTexrects); WriteCustomSetting(graphics2D, bgMode); + WriteCustomSetting(graphics2D, enableTexCoordBounds); settings.endGroup(); settings.beginGroup("frameBufferEmulation"); diff --git a/GLideN64/src/GLideNUI/configDialog.ui b/GLideN64/src/GLideNUI/configDialog.ui index c237f0e..d8ddac8 100644 --- a/GLideN64/src/GLideNUI/configDialog.ui +++ b/GLideN64/src/GLideNUI/configDialog.ui @@ -1502,11 +1502,25 @@ - - - Try to remove colored halos around transparent objects - - + + + + + Remove colored halos around transparent objects + + + + + + + <html><head/><body><p>Bound texture rectangle texture coordinates to the values they take in native resolutions. It prevents garbage due to fetching out of texture bounds, but can result in hard edges.</p></body></html> + + + Enable native-res bounds for texture coordinates + + + + diff --git a/GLideN64/src/Graphics/OpenGLContext/GLSL/glsl_CombinerProgramBuilder.cpp b/GLideN64/src/Graphics/OpenGLContext/GLSL/glsl_CombinerProgramBuilder.cpp index 1ce273b..5d1c886 100644 --- a/GLideN64/src/Graphics/OpenGLContext/GLSL/glsl_CombinerProgramBuilder.cpp +++ b/GLideN64/src/Graphics/OpenGLContext/GLSL/glsl_CombinerProgramBuilder.cpp @@ -267,7 +267,7 @@ public: ss << "# define IN in" << std::endl << "# define OUT out" << std::endl; m_part = ss.str(); } - m_part += "uniform lowp float uClipRatio; \n"; + m_part += "uniform lowp vec2 uVertexOffset; \n"; } }; @@ -296,6 +296,10 @@ public: "uniform mediump vec2 uCacheScale[2]; \n" "uniform mediump vec2 uCacheOffset[2]; \n" "uniform mediump vec2 uCacheShiftScale[2]; \n" + "uniform mediump vec2 uVTrans; \n" + "uniform mediump vec2 uVScale; \n" + "uniform mediump vec2 uAdjustTrans; \n" + "uniform mediump vec2 uAdjustScale; \n" "uniform lowp ivec2 uCacheFrameBuffer; \n" "OUT highp vec2 vTexCoord0; \n" "OUT highp vec2 vTexCoord1; \n" @@ -314,8 +318,8 @@ public: " vec2 texCoordOut = texCoord*uCacheShiftScale[idx]; \n" " texCoordOut -= uTexOffset[idx]; \n" " texCoordOut += uCacheOffset[idx]; \n" - " if (uTextureFilterMode != 0 && uCacheFrameBuffer[idx] != 0) \n" - " texCoordOut -= vec2(0.5); \n" + " if (uTextureFilterMode != 0 && uCacheFrameBuffer[idx] != 0) \n" /* Workaround for framebuffer textures. */ + " texCoordOut -= vec2(0.0,1.0); \n" /* They contain garbage at the bottom. */ " return texCoordOut * uCacheScale[idx]; \n" "} \n" " \n" @@ -330,17 +334,18 @@ public: " vTexCoord1 = calcTexCoord(texCoord, 1); \n" " vLodTexCoord = texCoord; \n" " vNumLights = aNumLights; \n" - " if (aModify != vec4(0.0)) { \n" - " if ((aModify[0]) != 0.0) { \n" - " gl_Position.xy = gl_Position.xy * uScreenCoordsScale + vec2(-1.0, 1.0); \n" - " gl_Position.xy *= gl_Position.w; \n" - " } \n" - " if ((aModify[1]) != 0.0) \n" - " gl_Position.z *= gl_Position.w; \n" - " if ((aModify[3]) != 0.0) \n" - " vNumLights = 0.0; \n" + " if ((aModify[0]) != 0.0) { \n" + " gl_Position.xy *= gl_Position.w; \n" " } \n" - " gl_Position.y = -gl_Position.y; \n" + " else { \n" + " gl_Position.xy = gl_Position.xy * uVScale.xy + uVTrans.xy * gl_Position.ww; \n" + " gl_Position.xy = floor(gl_Position.xy * vec2(4.0)) * vec2(0.25); \n" + " gl_Position.xy = gl_Position.xy * uAdjustScale + gl_Position.ww * uAdjustTrans; \n" + " } \n" + " if ((aModify[1]) != 0.0) \n" + " gl_Position.z *= gl_Position.w; \n" + " if ((aModify[3]) != 0.0) \n" + " vNumLights = 0.0; \n" " if (uFogUsage > 0) { \n" " lowp float fp; \n" " if (aPosition.z < -aPosition.w && aModify[1] == 0.0) \n" @@ -374,6 +379,10 @@ public: "uniform lowp int uFogUsage; \n" "uniform mediump vec2 uFogScale; \n" "uniform mediump vec2 uScreenCoordsScale; \n" + "uniform mediump vec2 uVTrans; \n" + "uniform mediump vec2 uVScale; \n" + "uniform mediump vec2 uAdjustTrans; \n" + "uniform mediump vec2 uAdjustScale; \n" " \n" "OUT lowp float vNumLights; \n" "OUT lowp vec4 vShadeColor; \n" @@ -390,17 +399,18 @@ public: " gl_Position = aPosition; \n" " vShadeColor = aColor; \n" " vNumLights = aNumLights; \n" - " if (aModify != vec4(0.0)) { \n" - " if ((aModify[0]) != 0.0) { \n" - " gl_Position.xy = gl_Position.xy * uScreenCoordsScale + vec2(-1.0, 1.0); \n" - " gl_Position.xy *= gl_Position.w; \n" - " } \n" - " if ((aModify[1]) != 0.0) \n" - " gl_Position.z *= gl_Position.w; \n" - " if ((aModify[3]) != 0.0) \n" - " vNumLights = 0.0; \n" + " if ((aModify[0]) != 0.0) { \n" + " gl_Position.xy *= gl_Position.w; \n" " } \n" - " gl_Position.y = -gl_Position.y; \n" + " else { \n" + " gl_Position.xy = gl_Position.xy * uVScale.xy + uVTrans.xy * gl_Position.ww; \n" + " gl_Position.xy = floor(gl_Position.xy * vec2(4.0)) * vec2(0.25); \n" + " gl_Position.xy = gl_Position.xy * uAdjustScale + gl_Position.ww * uAdjustTrans; \n" + " } \n" + " if ((aModify[1]) != 0.0) \n" + " gl_Position.z *= gl_Position.w; \n" + " if ((aModify[3]) != 0.0) \n" + " vNumLights = 0.0; \n" " if (uFogUsage > 0) { \n" " lowp float fp; \n" " if (aPosition.z < -aPosition.w && aModify[1] == 0.0) \n" @@ -503,7 +513,8 @@ public: m_part = " gl_Position.z /= 8.0; \n"; } m_part += - " gl_Position.zw *= vec2(uClipRatio); \n" + " gl_Position.xy += uVertexOffset * vec2(gl_Position.w); \n" + " gl_Position.zw *= vec2(1024.0f); \n" "} \n" ; } @@ -946,6 +957,10 @@ public: "uniform lowp vec2 uTexMirrorEn1; \n" "uniform lowp vec2 uTexClampEn0; \n" "uniform lowp vec2 uTexClampEn1; \n" + "uniform highp vec2 uTexCoordOffset[2]; \n" + "uniform lowp int uUseTexCoordBounds; \n" + "uniform highp vec4 uTexCoordBounds0; \n" + "uniform highp vec4 uTexCoordBounds1; \n" "uniform lowp int uScreenSpaceTriangle; \n" "highp vec2 texCoord0; \n" "highp vec2 texCoord1; \n" @@ -2575,6 +2590,23 @@ public: }; +class ShaderFragmentCorrectTexCoords : public ShaderPart { +public: + ShaderFragmentCorrectTexCoords() { + m_part += + " highp vec2 mTexCoord0 = vTexCoord0 + vec2(0.0001); \n" + " highp vec2 mTexCoord1 = vTexCoord1 + vec2(0.0001); \n" + " mTexCoord0 += uTexCoordOffset[0]; \n" + " mTexCoord1 += uTexCoordOffset[1]; \n" + " if (uUseTexCoordBounds != 0) { \n" + " mTexCoord0 = clamp(mTexCoord0, uTexCoordBounds0.xy, uTexCoordBounds0.zw); \n" + " mTexCoord1 = clamp(mTexCoord1, uTexCoordBounds1.xy, uTexCoordBounds1.zw); \n" + " } \n" + ; + } +}; + + class ShaderTextureEngine : public ShaderPart { public: @@ -2637,7 +2669,7 @@ public: ShaderFragmentTextureEngineTex0(const opengl::GLInfo _glinfo) { m_part = - "textureEngine0(vTexCoord0, tcData0); \n" + "textureEngine0(mTexCoord0, tcData0); \n" ; } }; @@ -2647,7 +2679,7 @@ public: ShaderFragmentTextureEngineTex1(const opengl::GLInfo _glinfo) { m_part = - "textureEngine1(vTexCoord1, tcData1); \n" + "textureEngine1(mTexCoord1, tcData1); \n" ; } }; @@ -2891,6 +2923,7 @@ graphics::CombinerProgram * CombinerProgramBuilder::buildCombinerProgram(Combine if (bUseTextures) { + m_fragmentCorrectTexCoords->write(ssShader); if (combinerInputs.usesTile(0)) { m_fragmentTextureEngineTex0->write(ssShader); @@ -3060,6 +3093,7 @@ CombinerProgramBuilder::CombinerProgramBuilder(const opengl::GLInfo & _glinfo, o , m_fragmentBlendMux(new ShaderFragmentBlendMux(_glinfo)) , m_fragmentReadTex0(new ShaderFragmentReadTex0(_glinfo)) , m_fragmentReadTex1(new ShaderFragmentReadTex1(_glinfo)) +, m_fragmentCorrectTexCoords(new ShaderFragmentCorrectTexCoords()) , m_fragmentTextureEngineTex0(new ShaderFragmentTextureEngineTex0(_glinfo)) , m_fragmentTextureEngineTex1(new ShaderFragmentTextureEngineTex1(_glinfo)) , m_fragmentReadTexCopyMode(new ShaderFragmentReadTexCopyMode(_glinfo)) diff --git a/GLideN64/src/Graphics/OpenGLContext/GLSL/glsl_CombinerProgramBuilder.h b/GLideN64/src/Graphics/OpenGLContext/GLSL/glsl_CombinerProgramBuilder.h index d46a76b..9269803 100644 --- a/GLideN64/src/Graphics/OpenGLContext/GLSL/glsl_CombinerProgramBuilder.h +++ b/GLideN64/src/Graphics/OpenGLContext/GLSL/glsl_CombinerProgramBuilder.h @@ -74,6 +74,7 @@ namespace glsl { ShaderPartPtr m_fragmentBlendMux; ShaderPartPtr m_fragmentReadTex0; ShaderPartPtr m_fragmentReadTex1; + ShaderPartPtr m_fragmentCorrectTexCoords; ShaderPartPtr m_fragmentTextureEngineTex0; ShaderPartPtr m_fragmentTextureEngineTex1; ShaderPartPtr m_fragmentReadTexCopyMode; diff --git a/GLideN64/src/Graphics/OpenGLContext/GLSL/glsl_CombinerProgramUniformFactory.cpp b/GLideN64/src/Graphics/OpenGLContext/GLSL/glsl_CombinerProgramUniformFactory.cpp index d3efd7a..8c66d66 100644 --- a/GLideN64/src/Graphics/OpenGLContext/GLSL/glsl_CombinerProgramUniformFactory.cpp +++ b/GLideN64/src/Graphics/OpenGLContext/GLSL/glsl_CombinerProgramUniformFactory.cpp @@ -1,3 +1,4 @@ +#include #include #include "glsl_CombinerProgramUniformFactory.h" #include @@ -216,6 +217,113 @@ private: iUniform uScreenSpaceTriangle; }; +class URasterInfo : public UniformGroup { +public: + URasterInfo(GLuint _program) { + LocateUniform(uVertexOffset); + LocateUniform(uTexCoordOffset[0]); + LocateUniform(uTexCoordOffset[1]); + LocateUniform(uUseTexCoordBounds); + LocateUniform(uTexCoordBounds0); + LocateUniform(uTexCoordBounds1); + } + + void update(bool _force) override { + const bool isNativeRes = config.frameBufferEmulation.nativeResFactor == 1 && config.video.multisampling == 0; + const bool isTexRect = dwnd().getDrawer().getDrawingState() == DrawingState::TexRect; + const bool useTexCoordBounds = isTexRect && !isNativeRes && config.graphics2D.enableTexCoordBounds; + /* At rasterization stage, the N64 places samples on the top left of the fragment while OpenGL */ + /* places them in the fragment center. As a result, a normal approach results in shifted texture */ + /* coordinates. In native resolution, this difference can be negated by shifting vertices by 0.5. */ + /* In higher resolutions, there are more samples than the game intends, so shifting is not very */ + /* effective. Still, an heuristic is applied to render texture rectangles as correctly as possible */ + /* in higher resolutions too. See issue #2324 for details. */ + const float vertexOffset = isNativeRes ? 0.5f : 0.0f; + float texCoordOffset[2][2] = { 0.0f, 0.0f }; + if (isTexRect && !isNativeRes) { + float scale[2] = { 0.0f, 0.0f }; + if (config.graphics2D.enableNativeResTexrects != 0) { + scale[0] = scale[1] = 1.0f; + } else if (config.frameBufferEmulation.nativeResFactor != 0) { + scale[0] = scale[1] = static_cast(config.frameBufferEmulation.nativeResFactor); + } else { + scale[0] = dwnd().getScaleX(); + scale[1] = dwnd().getScaleY(); + } + + for (int t = 0; t < 2; t++) { + const CachedTexture* _pTexture = textureCache().current[t]; + if (_pTexture != nullptr) { + texCoordOffset[t][0] = (gDP.lastTexRectInfo.dsdx >= 0.0f ? -0.5f / scale[0] : -1.0f + 0.5f / scale[0]) * gDP.lastTexRectInfo.dsdx * _pTexture->hdRatioS; + texCoordOffset[t][1] = (gDP.lastTexRectInfo.dtdy >= 0.0f ? -0.5f / scale[1] : -1.0f + 0.5f / scale[1]) * gDP.lastTexRectInfo.dtdy * _pTexture->hdRatioT; + } + } + } + float tcbounds[2][4] = {}; + if (useTexCoordBounds) { + f32 uls, lrs, ult, lrt, S, T, shiftScaleS, shiftScaleT; + s16 shiftedS, shiftedT; + u32 shifts, shiftt; + for (int t = 0; t < 2; t++) { + const CachedTexture * _pTexture = textureCache().current[t]; + const gDPTile * _pTile = gSP.textureTile[t]; + if (_pTexture != nullptr && _pTile != nullptr){ + if (_pTile->shifts > 10) { + shifts = 16 - _pTile->shifts; + shiftedS = static_cast(gDP.lastTexRectInfo.s << shifts); + shiftScaleS = static_cast(1 << shifts); + } else { + shifts = _pTile->shifts; + shiftedS = static_cast(gDP.lastTexRectInfo.s >> shifts); + shiftScaleS = 1.0f / static_cast(1 << shifts); + } + if (_pTile->shiftt > 10) { + shiftt = 16 - _pTile->shiftt; + shiftedT = static_cast(gDP.lastTexRectInfo.t << shiftt); + shiftScaleT = static_cast(1 << shiftt); + } else { + shiftt = _pTile->shiftt; + shiftedT = static_cast(gDP.lastTexRectInfo.t >> shiftt); + shiftScaleT = 1.0f / static_cast(1 << shiftt); + } + + S = _FIXED2FLOAT(shiftedS, 5); + T = _FIXED2FLOAT(shiftedT, 5); + uls = S + (ceilf(gDP.lastTexRectInfo.ulx) - gDP.lastTexRectInfo.ulx) * gDP.lastTexRectInfo.dsdx * shiftScaleS; + lrs = S + (ceilf(gDP.lastTexRectInfo.lrx) - gDP.lastTexRectInfo.ulx - 1.0f) * gDP.lastTexRectInfo.dsdx * shiftScaleS; + ult = T + (ceilf(gDP.lastTexRectInfo.uly) - gDP.lastTexRectInfo.uly) * gDP.lastTexRectInfo.dtdy * shiftScaleT; + lrt = T + (ceilf(gDP.lastTexRectInfo.lry) - gDP.lastTexRectInfo.uly - 1.0f) * gDP.lastTexRectInfo.dtdy * shiftScaleT; + + tcbounds[t][0] = (fmin(uls, lrs) - _pTile->fuls) * _pTexture->hdRatioS; + tcbounds[t][1] = (fmin(ult, lrt) - _pTile->fult) * _pTexture->hdRatioT; + tcbounds[t][2] = (fmax(uls, lrs) - _pTile->fuls) * _pTexture->hdRatioS; + tcbounds[t][3] = (fmax(ult, lrt) - _pTile->fult) * _pTexture->hdRatioT; + if (_pTexture->frameBufferTexture != CachedTexture::fbNone) { + tcbounds[t][0] += _pTexture->offsetS * _pTexture->hdRatioS; + tcbounds[t][1] += _pTexture->offsetT * _pTexture->hdRatioT; + tcbounds[t][2] += _pTexture->offsetS * _pTexture->hdRatioS; + tcbounds[t][3] += _pTexture->offsetT * _pTexture->hdRatioT; + } + } + } + } + + uVertexOffset.set(vertexOffset, vertexOffset, _force); + uTexCoordOffset[0].set(texCoordOffset[0][0], texCoordOffset[0][1], _force); + uTexCoordOffset[1].set(texCoordOffset[1][0], texCoordOffset[1][1], _force); + uUseTexCoordBounds.set(useTexCoordBounds ? 1 : 0, _force); + uTexCoordBounds0.set(tcbounds[0], _force); + uTexCoordBounds1.set(tcbounds[1], _force); + } + +private: + fv2Uniform uVertexOffset; + fv2Uniform uTexCoordOffset[2]; + iUniform uUseTexCoordBounds; + fv4Uniform uTexCoordBounds0; + fv4Uniform uTexCoordBounds1; +}; + class UFrameBufferInfo : public UniformGroup { public: @@ -603,6 +711,43 @@ private: fUniform uAlphaTestValue; }; +class UViewportInfo : public UniformGroup +{ +public: + UViewportInfo(GLuint _program) { + LocateUniform(uVTrans); + LocateUniform(uVScale); + LocateUniform(uAdjustTrans); + LocateUniform(uAdjustScale); + } + + void update(bool _force) override + { + const bool isOrthographicProjection = gSP.matrix.projection[3][2] == -1.f; + float adjustTrans[2] = { 0.0f, 0.0f }; + float adjustScale[2] = { 1.0f, 1.0f }; + if (dwnd().isAdjustScreen() && (gDP.colorImage.width > VI.width * 98 / 100)) { + if (isOrthographicProjection) { + adjustScale[1] = 1.0f / dwnd().getAdjustScale(); + adjustTrans[1] = static_cast(gDP.colorImage.width) * 3.0f / 4.0f * (1.0f - adjustScale[1]) / 2.0f; + } else { + adjustScale[0] = dwnd().getAdjustScale(); + adjustTrans[0] = static_cast(gDP.colorImage.width) * (1.0f - adjustScale[0]) / 2.0f; + } + } + uVTrans.set(gSP.viewport.vtrans[0], gSP.viewport.vtrans[1], _force); + uVScale.set(gSP.viewport.vscale[0], -gSP.viewport.vscale[1], _force); + uAdjustTrans.set(adjustTrans[0], adjustTrans[1], _force); + uAdjustScale.set(adjustScale[0], adjustScale[1], _force); + } + +private: + fv2Uniform uVTrans; + fv2Uniform uVScale; + fv2Uniform uAdjustTrans; + fv2Uniform uAdjustScale; +}; + class UDepthScale : public UniformGroup { public: @@ -738,22 +883,6 @@ private: iUniform uClampMode; }; -class UClipRatio : public UniformGroup -{ -public: - UClipRatio(GLuint _program) { - LocateUniform(uClipRatio); - } - - void update(bool _force) override - { - uClipRatio.set(float(gSP.clipRatio), _force); - } - -private: - fUniform uClipRatio; -}; - class UPolygonOffset : public UniformGroup { public: @@ -1094,6 +1223,8 @@ void CombinerProgramUniformFactory::buildUniforms(GLuint _program, { _uniforms.emplace_back(new UNoiseTex(_program)); _uniforms.emplace_back(new UScreenSpaceTriangleInfo(_program)); + _uniforms.emplace_back(new URasterInfo(_program)); + _uniforms.emplace_back(new UViewportInfo(_program)); if (!m_glInfo.isGLES2) { _uniforms.emplace_back(new UDepthTex(_program)); @@ -1165,8 +1296,6 @@ void CombinerProgramUniformFactory::buildUniforms(GLuint _program, _uniforms.emplace_back(new UPolygonOffset(_program)); } - _uniforms.emplace_back(new UClipRatio(_program)); - _uniforms.emplace_back(new UScreenCoordsScale(_program)); _uniforms.emplace_back(new UColors(_program)); diff --git a/GLideN64/src/Graphics/OpenGLContext/GLSL/glsl_ShaderStorage.h b/GLideN64/src/Graphics/OpenGLContext/GLSL/glsl_ShaderStorage.h index b5598ed..a6d573b 100644 --- a/GLideN64/src/Graphics/OpenGLContext/GLSL/glsl_ShaderStorage.h +++ b/GLideN64/src/Graphics/OpenGLContext/GLSL/glsl_ShaderStorage.h @@ -20,7 +20,7 @@ namespace glsl { bool _saveCombinerKeys(const graphics::Combiners & _combiners) const; bool _loadFromCombinerKeys(graphics::Combiners & _combiners); - const u32 m_formatVersion = 0x33U; + const u32 m_formatVersion = 0x34U; const u32 m_keysFormatVersion = 0x05; const opengl::GLInfo & m_glinfo; opengl::CachedUseProgram * m_useProgram; diff --git a/GLideN64/src/Graphics/OpenGLContext/GraphicBuffer/GraphicBufferWrapper.cpp b/GLideN64/src/Graphics/OpenGLContext/GraphicBuffer/GraphicBufferWrapper.cpp index 5772b8a..6062d45 100644 --- a/GLideN64/src/Graphics/OpenGLContext/GraphicBuffer/GraphicBufferWrapper.cpp +++ b/GLideN64/src/Graphics/OpenGLContext/GraphicBuffer/GraphicBufferWrapper.cpp @@ -22,6 +22,8 @@ GraphicBufferWrapper::GraphicBufferWrapper() { m_private = true; m_privateGraphicBuffer = new GraphicBuffer(); } + + m_stride = 0; } GraphicBufferWrapper::~GraphicBufferWrapper() { @@ -51,7 +53,6 @@ bool GraphicBufferWrapper::allocate(const AHardwareBuffer_Desc *desc) { } } - int GraphicBufferWrapper::lock(uint64_t usage, void **out_virtual_address) { int returnValue = 0; @@ -64,7 +65,6 @@ int GraphicBufferWrapper::lock(uint64_t usage, void **out_virtual_address) { return returnValue; } - void GraphicBufferWrapper::release() { if (!m_private) { AndroidHardwareBufferCompat::GetInstance().Release(m_publicGraphicBuffer); @@ -81,7 +81,6 @@ void GraphicBufferWrapper::unlock() { } - EGLClientBuffer GraphicBufferWrapper::getClientBuffer() { EGLClientBuffer clientBuffer = nullptr; if (m_private) { @@ -93,6 +92,15 @@ EGLClientBuffer GraphicBufferWrapper::getClientBuffer() { return clientBuffer; } +unsigned GraphicBufferWrapper::getStride() const { + if (m_private) { + return m_privateGraphicBuffer->getStride(); + } else { + AHardwareBuffer_Desc bufferInfo; + AndroidHardwareBufferCompat::GetInstance().Describe(m_publicGraphicBuffer, &bufferInfo); + return bufferInfo.stride; + } +} int GraphicBufferWrapper::getApiLevel() { diff --git a/GLideN64/src/Graphics/OpenGLContext/GraphicBuffer/GraphicBufferWrapper.h b/GLideN64/src/Graphics/OpenGLContext/GraphicBuffer/GraphicBufferWrapper.h index 7d9ea85..a6e5344 100644 --- a/GLideN64/src/Graphics/OpenGLContext/GraphicBuffer/GraphicBufferWrapper.h +++ b/GLideN64/src/Graphics/OpenGLContext/GraphicBuffer/GraphicBufferWrapper.h @@ -28,6 +28,7 @@ public: void release(); void unlock(); EGLClientBuffer getClientBuffer(); + unsigned int getStride() const; private: @@ -36,6 +37,7 @@ private: bool m_private; GraphicBuffer* m_privateGraphicBuffer; AHardwareBuffer* m_publicGraphicBuffer; + unsigned int m_stride; }; diff --git a/GLideN64/src/Graphics/OpenGLContext/opengl_ColorBufferReaderWithEGLImage.cpp b/GLideN64/src/Graphics/OpenGLContext/opengl_ColorBufferReaderWithEGLImage.cpp index 1bb66a4..08a4cb9 100644 --- a/GLideN64/src/Graphics/OpenGLContext/opengl_ColorBufferReaderWithEGLImage.cpp +++ b/GLideN64/src/Graphics/OpenGLContext/opengl_ColorBufferReaderWithEGLImage.cpp @@ -55,7 +55,7 @@ const u8 * ColorBufferReaderWithEGLImage::_readPixels(const ReadColorBufferParam m_hardwareBuffer.lock(AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN, &gpuData); m_bufferLocked = true; _heightOffset = static_cast(_params.y0); - _stride = m_pTexture->width; + _stride = m_hardwareBuffer.getStride(); } else { gpuData = m_pixelData.data(); glReadPixels(_params.x0, _params.y0, m_pTexture->width, _params.height, format, type, gpuData); diff --git a/GLideN64/src/GraphicsDrawer.cpp b/GLideN64/src/GraphicsDrawer.cpp index 86bf060..baccfcb 100644 --- a/GLideN64/src/GraphicsDrawer.cpp +++ b/GLideN64/src/GraphicsDrawer.cpp @@ -238,86 +238,25 @@ void GraphicsDrawer::updateScissor(FrameBuffer * _pBuffer) const gDP.changed &= ~CHANGED_SCISSOR; } -inline -float _adjustViewportX(f32 _X0) +void GraphicsDrawer::_updateViewport(const FrameBuffer* _pBuffer, const f32 scale) const { - const f32 halfX = gDP.colorImage.width / 2.0f; - const f32 halfVP = gSP.viewport.width / 2.0f; - return (_X0 + halfVP - halfX) * dwnd().getAdjustScale() + halfX - halfVP; -} - -inline -void _adjustViewportToClipRatio(s32 & x, s32 & y, s32 & width, s32 & height) -{ - x -= static_cast(gSP.clipRatio - 1) * width / 2; - y -= static_cast(gSP.clipRatio - 1) * height / 2; - width *= gSP.clipRatio; - height *= gSP.clipRatio; -} - - -void GraphicsDrawer::_updateViewport() const -{ - DisplayWindow & wnd = DisplayWindow::get(); - FrameBuffer * pCurrentBuffer = frameBufferList().getCurrent(); - if (pCurrentBuffer == nullptr) { - const f32 scaleX = wnd.getScaleX(); - const f32 scaleY = wnd.getScaleY(); - float Xf = gSP.viewport.vscale[0] < 0 ? (gSP.viewport.x + gSP.viewport.vscale[0] * 2.0f) : gSP.viewport.x; - if (_needAdjustCoordinate(wnd)) - Xf = _adjustViewportX(Xf); - s32 X = static_cast(Xf * scaleX); - s32 Y = static_cast(gSP.viewport.y * scaleY); - s32 WIDTH = std::max(static_cast(gSP.viewport.width * scaleX), 0); - s32 HEIGHT = std::max(static_cast(gSP.viewport.height * scaleY), 0); - _adjustViewportToClipRatio(X, Y, WIDTH, HEIGHT); - gfxContext.setViewport(X, Y, WIDTH, HEIGHT); - } else { - const f32 scaleX = pCurrentBuffer->m_scale; - const f32 scaleY = pCurrentBuffer->m_scale; - float Xf = gSP.viewport.vscale[0] < 0 ? (gSP.viewport.x + gSP.viewport.vscale[0] * 2.0f) : gSP.viewport.x; - Xf += f32(pCurrentBuffer->m_originX); - if (_needAdjustCoordinate(wnd)) - Xf = _adjustViewportX(Xf); - s32 X = roundup(Xf, scaleX); - float Yf = gSP.viewport.vscale[1] < 0 ? (gSP.viewport.y + gSP.viewport.vscale[1] * 2.0f) : gSP.viewport.y; - Yf += f32(pCurrentBuffer->m_originY); - s32 Y = roundup(Yf, scaleY); - s32 WIDTH = std::max(roundup(gSP.viewport.width, scaleX), 0); - s32 HEIGHT = std::max(roundup(gSP.viewport.height, scaleY), 0); - _adjustViewportToClipRatio(X, Y, WIDTH, HEIGHT); - gfxContext.setViewport(X, Y, WIDTH, HEIGHT); - } - gSP.changed &= ~CHANGED_VIEWPORT; -} - -void GraphicsDrawer::_updateScreenCoordsViewport(const FrameBuffer * _pBuffer) const -{ - DisplayWindow & wnd = DisplayWindow::get(); - const FrameBuffer * pCurrentBuffer = _pBuffer != nullptr ? _pBuffer : frameBufferList().getCurrent(); - - u32 bufferWidth, bufferHeight; - f32 viewportScaleX, viewportScaleY; - s32 X = 0, Y = 0; - if (pCurrentBuffer == nullptr) { - bufferWidth = VI.width; - bufferHeight = VI.height; - viewportScaleX = wnd.getScaleX(); - viewportScaleY = wnd.getScaleY(); - } else { - bufferWidth = pCurrentBuffer->m_width; - bufferHeight = VI_GetMaxBufferHeight(static_cast(bufferWidth)); - viewportScaleX = viewportScaleY = pCurrentBuffer->m_scale; - X = roundup(f32(pCurrentBuffer->m_originX), viewportScaleX); - Y = roundup(f32(pCurrentBuffer->m_originY), viewportScaleY); - if (RSP.LLE || gSP.viewport.width == 0.0f) { - gSP.viewport.width = f32(bufferWidth); - gSP.viewport.height = f32(bufferHeight); + s32 X, Y, WIDTH, HEIGHT; + f32 scaleX, scaleY; + if (scale == 0.0f) { + const FrameBuffer* pCurrentBuffer = _pBuffer != nullptr ? _pBuffer : frameBufferList().getCurrent(); + if (pCurrentBuffer != nullptr) { + scaleX = scaleY = pCurrentBuffer->m_scale; + } else { + scaleX = dwnd().getScaleX(); + scaleY = dwnd().getScaleY(); } + } else { + scaleX = scaleY = scale; } - s32 WIDTH = roundup(f32(bufferWidth), viewportScaleX); - s32 HEIGHT = roundup(f32(bufferHeight), viewportScaleY); - _adjustViewportToClipRatio(X, Y, WIDTH, HEIGHT); + X = roundup(-1024.0f, scaleX); + Y = roundup(-1024.0f, scaleY); + WIDTH = roundup(2048.0f, scaleX); + HEIGHT = roundup(2048.0f, scaleY); gfxContext.setViewport(X, Y, WIDTH, HEIGHT); gSP.changed |= CHANGED_VIEWPORT; } @@ -796,7 +735,7 @@ void GraphicsDrawer::_prepareDrawTriangle(DrawingState _drawingState) m_bFlatColors = bFlatColors; if ((m_modifyVertices & MODIFY_XY) != 0) - _updateScreenCoordsViewport(); + _updateViewport(); m_modifyVertices = 0; } @@ -853,8 +792,6 @@ void GraphicsDrawer::drawScreenSpaceTriangle(u32 _numVtx, graphics::DrawModePara if (_numVtx == 0 || !_canDraw()) return; - ValueKeeper otherMode(gSP.clipRatio, 1U); - f32 maxY = 0; for (u32 i = 0; i < _numVtx; ++i) { SPVertex & vtx = m_dmaVertices[i]; @@ -1042,7 +979,7 @@ void GraphicsDrawer::drawLine(u32 _v0, u32 _v1, float _width) m_drawingState = DrawingState::Line; if ((triangles.vertices[_v0].modify & MODIFY_XY) != 0) - _updateScreenCoordsViewport(); + _updateViewport(); SPVertex vertexBuf[2] = { triangles.vertices[_v0], triangles.vertices[_v1] }; gfxContext.drawLine(lineWidth, vertexBuf); @@ -1050,7 +987,6 @@ void GraphicsDrawer::drawLine(u32 _v0, u32 _v1, float _width) void GraphicsDrawer::drawRect(int _ulx, int _uly, int _lrx, int _lry) { - ValueKeeper otherMode(gSP.clipRatio, 1U); m_texrectDrawer.draw(); m_statistics.fillRects++; @@ -1064,24 +1000,22 @@ void GraphicsDrawer::drawRect(int _ulx, int _uly, int _lrx, int _lry) m_drawingState = DrawingState::Rect; - _updateScreenCoordsViewport(); + _updateViewport(); gfxContext.enable(enable::CULL_FACE, false); - f32 scaleX, scaleY; - calcCoordsScales(frameBufferList().getCurrent(), scaleX, scaleY); const float Z = (gDP.otherMode.depthSource == G_ZS_PRIM) ? gDP.primDepth.z : 0.0f; const float W = 1.0f; - m_rect[0].x = static_cast(_ulx) * (2.0f * scaleX) - 1.0f; - m_rect[0].y = static_cast(_uly) * (2.0f * scaleY) - 1.0f; + m_rect[0].x = static_cast(_ulx); + m_rect[0].y = static_cast(_uly); m_rect[0].z = Z; m_rect[0].w = W; - m_rect[1].x = static_cast(_lrx) * (2.0f * scaleX) - 1.0f; + m_rect[1].x = static_cast(_lrx); m_rect[1].y = m_rect[0].y; m_rect[1].z = Z; m_rect[1].w = W; m_rect[2].x = m_rect[0].x; - m_rect[2].y = static_cast(_lry) * (2.0f * scaleY) - 1.0f; + m_rect[2].y = static_cast(_lry); m_rect[2].z = Z; m_rect[2].w = W; m_rect[3].x = m_rect[1].x; @@ -1101,8 +1035,11 @@ void GraphicsDrawer::drawRect(int _ulx, int _uly, int _lrx, int _lry) DisplayWindow & wnd = dwnd(); if (wnd.isAdjustScreen() && (gDP.colorImage.width > VI.width * 98 / 100) && (static_cast(_lrx - _ulx) < VI.width * 9 / 10)) { const float scale = wnd.getAdjustScale(); - for (u32 i = 0; i < 4; ++i) + const float offsetx = static_cast(gDP.colorImage.width) * (1.0f - scale) / 2.0f; + for (u32 i = 0; i < 4; ++i) { m_rect[i].x *= scale; + m_rect[i].x += offsetx; + } } Context::DrawRectParameters rectParams; @@ -1265,7 +1202,6 @@ void GraphicsDrawer::drawTexturedRect(const TexturedRectParams & _params) gSP.changed &= ~CHANGED_GEOMETRYMODE; // Don't update cull mode m_drawingState = DrawingState::TexRect; m_statistics.texRects++; - ValueKeeper otherMode(gSP.clipRatio, 1U); if (m_texrectDrawer.canContinue()) { CombinerInfo & cmbInfo = CombinerInfo::get(); @@ -1305,14 +1241,13 @@ void GraphicsDrawer::drawTexturedRect(const TexturedRectParams & _params) && ((cache.current[0]->frameBufferTexture == CachedTexture::fbNone && !cache.current[0]->bHDTexture)) && (cache.current[1] == nullptr || (cache.current[1]->frameBufferTexture == CachedTexture::fbNone && !cache.current[1]->bHDTexture))); - f32 scaleX, scaleY; - calcCoordsScales(pCurrentBuffer, scaleX, scaleY); const float Z = (gDP.otherMode.depthSource == G_ZS_PRIM) ? gDP.primDepth.z : 0.0f; const float W = 1.0f; - const f32 ulx = _params.ulx * (2.0f * scaleX) - 1.0f; - const f32 uly = _params.uly * (2.0f * scaleY) - 1.0f; - const f32 lrx = _params.lrx * (2.0f * scaleX) - 1.0f; - const f32 lry = _params.lry * (2.0f * scaleY) - 1.0f; + const f32 ulx = _params.ulx; + const f32 uly = _params.uly; + const f32 lrx = _params.lrx; + const f32 lry = _params.lry; + m_rect[0].x = ulx; m_rect[0].y = uly; m_rect[0].z = Z; @@ -1380,15 +1315,6 @@ void GraphicsDrawer::drawTexturedRect(const TexturedRectParams & _params) texST[t].t0 = ult - gSP.textureTile[t]->fult; texST[t].t1 = lrt - gSP.textureTile[t]->fult; - if (uls > lrs) { - texST[t].s0 -= _params.dsdx * shiftScaleS; - texST[t].s1 -= _params.dsdx * shiftScaleS; - } - if (ult > lrt) { - texST[t].t0 -= _params.dtdy * shiftScaleT; - texST[t].t1 -= _params.dtdy * shiftScaleT; - } - if (cache.current[t]->frameBufferTexture != CachedTexture::fbNone) { texST[t].s0 = cache.current[t]->offsetS + texST[t].s0; texST[t].t0 = cache.current[t]->offsetT + texST[t].t0; @@ -1425,13 +1351,6 @@ void GraphicsDrawer::drawTexturedRect(const TexturedRectParams & _params) texST[t].s1 *= cache.current[t]->hdRatioS; texST[t].t1 *= cache.current[t]->hdRatioT; - if (gDP.otherMode.textureFilter != G_TF_POINT && gDP.otherMode.cycleType != G_CYC_COPY) { - texST[t].s0 -= 0.5f; - texST[t].t0 -= 0.5f; - texST[t].s1 -= 0.5f; - texST[t].t1 -= 0.5f; - } - } } @@ -1482,8 +1401,11 @@ void GraphicsDrawer::drawTexturedRect(const TexturedRectParams & _params) ((gDP.colorImage.width > VI.width * 98 / 100) && (static_cast(_params.lrx - _params.ulx) < VI.width * 9 / 10)))) { const float scale = wnd.getAdjustScale(); - for (u32 i = 0; i < 4; ++i) + const float offsetx = static_cast(gDP.colorImage.width) * (1.0f-scale) / 2.0f; + for (u32 i = 0; i < 4; ++i) { m_rect[i].x *= scale; + m_rect[i].x += offsetx; + } } m_rect[0].bc0 = 0.0f; @@ -1505,7 +1427,7 @@ void GraphicsDrawer::drawTexturedRect(const TexturedRectParams & _params) return; } - _updateScreenCoordsViewport(_params.pBuffer); + _updateViewport(_params.pBuffer); Context::DrawRectParameters rectParams; rectParams.mode = drawmode::TRIANGLE_STRIP; rectParams.verticesCount = 4; @@ -1513,14 +1435,6 @@ void GraphicsDrawer::drawTexturedRect(const TexturedRectParams & _params) rectParams.combiner = currentCombiner(); gfxContext.drawRects(rectParams); if (g_debugger.isCaptureMode()) { - m_rect[0].x = _params.ulx; - m_rect[0].y = _params.uly; - m_rect[1].x = _params.lrx; - m_rect[1].y = _params.uly; - m_rect[2].x = _params.ulx; - m_rect[2].y = _params.lry; - m_rect[3].x = _params.lrx; - m_rect[3].y = _params.lry; g_debugger.addRects(rectParams); } diff --git a/GLideN64/src/GraphicsDrawer.h b/GLideN64/src/GraphicsDrawer.h index de06d59..87f432a 100644 --- a/GLideN64/src/GraphicsDrawer.h +++ b/GLideN64/src/GraphicsDrawer.h @@ -190,8 +190,7 @@ private: void _ordinaryBlending() const; void _dualSourceBlending() const; void _updateCullFace() const; - void _updateViewport() const; - void _updateScreenCoordsViewport(const FrameBuffer * _pBuffer = nullptr) const; + void _updateViewport(const FrameBuffer * _pBuffer = nullptr, const f32 scale = 0.0f) const; void _updateDepthUpdate() const; void _updateDepthCompare() const; void _updateTextures() const; diff --git a/GLideN64/src/TexrectDrawer.cpp b/GLideN64/src/TexrectDrawer.cpp index e833523..6421c97 100644 --- a/GLideN64/src/TexrectDrawer.cpp +++ b/GLideN64/src/TexrectDrawer.cpp @@ -29,8 +29,6 @@ TexrectDrawer::TexrectDrawer() , m_Z(0) , m_max_lrx(0) , m_max_lry(0) -, m_stepY(0.0f) -, m_stepX(0.0f) , m_scissor(gDPScissor()) , m_pTexture(nullptr) , m_pBuffer(nullptr) @@ -54,8 +52,6 @@ void TexrectDrawer::init() m_pTexture->width = 640; m_pTexture->height = 580; m_pTexture->textureBytes = m_pTexture->width * m_pTexture->height * fbTexFormats.colorFormatBytes; - m_stepX = 2.0f / 640.0f; - m_stepY = 2.0f / 580.0f; Context::InitTextureParams initParams; initParams.handle = m_pTexture->name; @@ -108,8 +104,7 @@ void TexrectDrawer::destroy() void TexrectDrawer::_setViewport() const { - const u32 bufferWidth = m_pBuffer == nullptr ? VI.width : m_pBuffer->m_width; - gfxContext.setViewport(0, 0, bufferWidth, VI_GetMaxBufferHeight(bufferWidth)); + dwnd().getDrawer()._updateViewport(nullptr, 1.0f); } void TexrectDrawer::_setDrawBuffer() @@ -381,13 +376,14 @@ bool TexrectDrawer::draw() scaleX *= 2.0f; scaleY *= 2.0f; - const float s0 = (m_ulx + 1.0f) / scaleX / (float)m_pTexture->width + 0.5f / (float)m_pTexture->width; - const float t0 = (m_lry + 1.0f) / scaleY / (float)m_pTexture->height;// +0.5f / (float)m_pTexture->height; - const float s1 = (m_lrx + 1.0f) / scaleX / (float)m_pTexture->width; - const float t1 = (m_uly + 1.0f) / scaleY / (float)m_pTexture->height; - const float W = 1.0f; + const float s0 = m_ulx / (float)m_pTexture->width; // +0.5f / (float)m_pTexture->width; + const float t0 = m_lry / (float)m_pTexture->height;// +0.5f / (float)m_pTexture->height; + const float s1 = m_lrx / (float)m_pTexture->width; + const float t1 = m_uly / (float)m_pTexture->height; + const float W = 1024.0f; + const float Z = m_Z * 1024.0f; - drawer._updateScreenCoordsViewport(m_pBuffer); + drawer._updateViewport(m_pBuffer); textureCache().activateTexture(0, m_pTexture); // Disable filtering to avoid black outlines @@ -404,25 +400,25 @@ bool TexrectDrawer::draw() rect[0].x = m_ulx; rect[0].y = m_lry; - rect[0].z = m_Z; + rect[0].z = Z; rect[0].w = W; rect[0].s0 = s0; rect[0].t0 = t0; rect[1].x = m_lrx; rect[1].y = m_lry; - rect[1].z = m_Z; + rect[1].z = Z; rect[1].w = W; rect[1].s0 = s1; rect[1].t0 = t0; rect[2].x = m_ulx; rect[2].y = m_uly; - rect[2].z = m_Z; + rect[2].z = Z; rect[2].w = W; rect[2].s0 = s0; rect[2].t0 = t1; rect[3].x = m_lrx; rect[3].y = m_uly; - rect[3].z = m_Z; + rect[3].z = Z; rect[3].w = W; rect[3].s0 = s1; rect[3].t0 = t1; @@ -440,15 +436,15 @@ bool TexrectDrawer::draw() gfxContext.bindFramebuffer(bufferTarget::DRAW_FRAMEBUFFER, m_FBO); m_programClear->activate(); - const f32 ulx = std::max(-1.0f, m_ulx - m_stepX); - const f32 lrx = std::min( 1.0f, m_lrx + m_stepX); + const f32 ulx = std::max(0.0f, m_ulx - 1.0f); + const f32 lrx = std::min(640.0f, m_lrx + 1.0f); rect[0].x = ulx; rect[1].x = lrx; rect[2].x = ulx; rect[3].x = lrx; - const f32 uly = std::max(-1.0f, m_uly - m_stepY); - const f32 lry = std::min( 1.0f, m_lry + m_stepY); + const f32 uly = std::max(0.0f, m_uly - 1.0f); + const f32 lry = std::min(580.0f, m_lry + 1.0f); rect[0].y = uly; rect[1].y = uly; rect[2].y = lry; diff --git a/GLideN64/src/TexrectDrawer.h b/GLideN64/src/TexrectDrawer.h index 6e90d05..e62ff60 100644 --- a/GLideN64/src/TexrectDrawer.h +++ b/GLideN64/src/TexrectDrawer.h @@ -34,8 +34,6 @@ private: f32 m_ulx, m_lrx, m_uly, m_lry, m_Z; s32 m_ulx_i, m_uly_i, m_lry_i; f32 m_max_lrx, m_max_lry; - f32 m_stepY; - f32 m_stepX; graphics::ObjectHandle m_FBO; gDPScissor m_scissor; CachedTexture * m_pTexture; diff --git a/GLideN64/src/VI.cpp b/GLideN64/src/VI.cpp index fbc019a..b3b88ad 100644 --- a/GLideN64/src/VI.cpp +++ b/GLideN64/src/VI.cpp @@ -130,6 +130,27 @@ static void checkHotkeys() textureCache().toggleDumpTex(); } + if (osal_is_key_pressed(config.hotkeys.keys[Config::hkTexCoordBounds], 0x0001)) { + if (config.graphics2D.enableTexCoordBounds == 0) + dwnd().getDrawer().showMessage("Bound texrect texture coordinates on\n", Milliseconds(1000)); + else + dwnd().getDrawer().showMessage("Bound texrect texture coordinates off\n", Milliseconds(1000)); + config.graphics2D.enableTexCoordBounds = !config.graphics2D.enableTexCoordBounds; + } + + if (osal_is_key_pressed(config.hotkeys.keys[Config::hkNativeResTexrects], 0x0001)) { + static u32 s_nativeResTexrects = Config::NativeResTexrectsMode::ntOptimized; + if (config.graphics2D.enableNativeResTexrects != Config::NativeResTexrectsMode::ntDisable) { + s_nativeResTexrects = config.graphics2D.enableNativeResTexrects; + config.graphics2D.enableNativeResTexrects = Config::NativeResTexrectsMode::ntDisable; + } + else + config.graphics2D.enableNativeResTexrects = s_nativeResTexrects; + if (config.graphics2D.enableNativeResTexrects == Config::NativeResTexrectsMode::ntDisable) + dwnd().getDrawer().showMessage("Disable 2D texrects in native resolution\n", Milliseconds(1000)); + else + dwnd().getDrawer().showMessage("Enable 2D texrects in native resolution\n", Milliseconds(1000)); + } if (osal_is_key_pressed(config.hotkeys.keys[Config::hkVsync], 0x0001)) { config.video.verticalSync = !config.video.verticalSync; diff --git a/GLideN64/src/gDP.cpp b/GLideN64/src/gDP.cpp index 8ee1d84..0c5c231 100644 --- a/GLideN64/src/gDP.cpp +++ b/GLideN64/src/gDP.cpp @@ -866,6 +866,15 @@ void gDPTextureRectangle(f32 ulx, f32 uly, f32 lrx, f32 lry, s32 tile, s16 s, s1 gDP.rectColor = gDPInfo::Color(); + gDP.lastTexRectInfo.ulx = ulx; + gDP.lastTexRectInfo.lrx = lrx; + gDP.lastTexRectInfo.uly = uly; + gDP.lastTexRectInfo.lry = lry; + gDP.lastTexRectInfo.s = !flip ? s : t; + gDP.lastTexRectInfo.t = !flip ? t : s; + gDP.lastTexRectInfo.dsdx = !flip ? dsdx : dtdy; + gDP.lastTexRectInfo.dtdy = !flip ? dtdy : dsdx; + GraphicsDrawer & drawer = dwnd().getDrawer(); GraphicsDrawer::TexturedRectParams params(ulx, uly, lrx, lry, dsdx, dtdy, s, t, flip, false, true, frameBufferList().getCurrent()); diff --git a/GLideN64/src/gDP.h b/GLideN64/src/gDP.h index 021c3dc..a845895 100644 --- a/GLideN64/src/gDP.h +++ b/GLideN64/src/gDP.h @@ -122,6 +122,13 @@ struct gDPScissor s16 xh, yh, xl, yl; }; +struct gDPTexrectInfo +{ + f32 ulx, lrx, uly, lry; + s16 s, t; + f32 dsdx, dtdy; +}; + struct gDPInfo { struct OtherMode @@ -255,7 +262,8 @@ struct gDPInfo u64 paletteCRC256; u32 half_1, half_2; - gDPLoadTileInfo loadInfo[512]; + gDPLoadTileInfo loadInfo[512]; + gDPTexrectInfo lastTexRectInfo; }; extern gDPInfo gDP; diff --git a/GLideN64/src/gSP.cpp b/GLideN64/src/gSP.cpp index e9cf9d3..08a8730 100644 --- a/GLideN64/src/gSP.cpp +++ b/GLideN64/src/gSP.cpp @@ -440,7 +440,7 @@ void gSPLookAt( u32 _l, u32 _n ) static void gSPUpdateLightVectors() { - InverseTransformVectorNormalizeN(&gSP.lights.xyz[0], &gSP.lights.i_xyz[0], + InverseTransformVectorNormalizeN(&gSP.lights.xyz[0], &gSP.lights.i_xyz[0], gSP.matrix.modelView[gSP.matrix.modelViewi], gSP.numLights); gSP.changed ^= CHANGED_LIGHT; gSP.changed |= CHANGED_HW_LIGHT; @@ -763,11 +763,13 @@ void gSPBillboardVertex(u32 v, SPVertex * spVtx) template void gSPClipVertex(u32 v, SPVertex * spVtx) { + const f32 scale = dwnd().getAdjustScale(); for (u32 j = 0; j < VNUM; ++j) { SPVertex & vtx = spVtx[v+j]; vtx.clip = 0; - if (vtx.x > +vtx.w) vtx.clip |= CLIP_POSX; - if (vtx.x < -vtx.w) vtx.clip |= CLIP_NEGX; + const f32 scaledX = vtx.x * scale; + if (scaledX > +vtx.w) vtx.clip |= CLIP_POSX; + if (scaledX < -vtx.w) vtx.clip |= CLIP_NEGX; if (vtx.y > +vtx.w) vtx.clip |= CLIP_POSY; if (vtx.y < -vtx.w) vtx.clip |= CLIP_NEGY; if (vtx.w < 0.01f) vtx.clip |= CLIP_W; @@ -817,28 +819,6 @@ void gSPProcessVertex(u32 v, SPVertex * spVtx) gSPTransformVertex(v, spVtx, gSP.matrix.combined ); - if (dwnd().isAdjustScreen() && (gDP.colorImage.width > VI.width * 98 / 100)) { - const f32 adjustScale = dwnd().getAdjustScale(); - for(int i = 0; i < VNUM; ++i) { - SPVertex & vtx = spVtx[v+i]; - vtx.x *= adjustScale; - if (gSP.matrix.projection[3][2] == -1.f) - vtx.w *= adjustScale; - } - } - if (gSP.viewport.vscale[0] < 0) { - for(int i = 0; i < VNUM; ++i) { - SPVertex & vtx = spVtx[v+i]; - vtx.x = -vtx.x; - } - } - if (gSP.viewport.vscale[1] < 0) { - for(int i = 0; i < VNUM; ++i) { - SPVertex & vtx = spVtx[v+i]; - vtx.y = -vtx.y; - } - } - if (gSP.matrix.billboard) gSPBillboardVertex(v, spVtx); @@ -1670,32 +1650,24 @@ void gSPModifyVertex( u32 _vtx, u32 _where, u32 _val ) case G_MWO_POINT_XYSCREEN: vtx0.x = _FIXED2FLOAT((s16)_SHIFTR(_val, 16, 16), 2); vtx0.y = _FIXED2FLOAT((s16)_SHIFTR(_val, 0, 16), 2); - DebugMsg(DEBUG_NORMAL, "gSPModifyVertex: XY(%02f, %02f);\n", vtx0.x, vtx0.y); + vtx0.modify |= MODIFY_XY; + vtx0.clip &= ~(CLIP_POSX | CLIP_NEGX | CLIP_POSY | CLIP_NEGY); if ((config.generalEmulation.hacks & hack_ModifyVertexXyInShader) == 0) { - vtx0.x = (vtx0.x - gSP.viewport.vtrans[0]) / gSP.viewport.vscale[0]; - if (gSP.viewport.vscale[0] < 0) - vtx0.x = -vtx0.x; - vtx0.x *= vtx0.w; - if (dwnd().isAdjustScreen()) { const f32 adjustScale = dwnd().getAdjustScale(); + const f32 adjustOffset = static_cast(VI.width) * (1.0f - adjustScale) / 2.0f; vtx0.x *= adjustScale; + vtx0.x += adjustOffset; if (gSP.matrix.projection[3][2] == -1.f) vtx0.w *= adjustScale; } - - vtx0.y = -(vtx0.y - gSP.viewport.vtrans[1]) / gSP.viewport.vscale[1]; - if (gSP.viewport.vscale[1] < 0) - vtx0.y = -vtx0.y; - vtx0.y *= vtx0.w; } else { - vtx0.modify |= MODIFY_XY; if (vtx0.w == 0.0f || gDP.otherMode.depthSource == G_ZS_PRIM) { vtx0.w = 1.0f; vtx0.clip &= ~(CLIP_W); } } - vtx0.clip &= ~(CLIP_POSX | CLIP_NEGX | CLIP_POSY | CLIP_NEGY); + DebugMsg(DEBUG_NORMAL, "gSPModifyVertex: XY(%02f, %02f);\n", vtx0.x, vtx0.y); break; case G_MWO_POINT_ZSCREEN: { diff --git a/GLideN64/src/mupenplus/Config_mupenplus.cpp b/GLideN64/src/mupenplus/Config_mupenplus.cpp index e93a509..29f6df4 100644 --- a/GLideN64/src/mupenplus/Config_mupenplus.cpp +++ b/GLideN64/src/mupenplus/Config_mupenplus.cpp @@ -29,6 +29,10 @@ const char* _hotkeyDescription(u32 _idx) return "Hotkey: reload HD textures"; case Config::HotKey::hkHdTexToggle: return "Hotkey: toggle HD textures"; + case Config::HotKey::hkTexCoordBounds: + return "Hotkey: toggle texcoords bounds"; + case Config::HotKey::hkNativeResTexrects: + return "Hotkey: toggle 2D texrects in native resolution"; case Config::HotKey::hkVsync: return "Hotkey: toggle VSync"; case Config::HotKey::hkFBEmulation: @@ -178,6 +182,8 @@ bool Config_SetDefault() assert(res == M64ERR_SUCCESS); res = ConfigSetDefaultInt(g_configVideoGliden64, "BackgroundsMode", config.graphics2D.bgMode, "Render backgrounds mode (HLE only). (0=One piece (fast), 1=Stripped (precise))"); assert(res == M64ERR_SUCCESS); + res = ConfigSetDefaultInt(g_configVideoGliden64, "EnableTexCoordBounds", config.graphics2D.enableTexCoordBounds, "Bound texture rectangle texture coordinates to the values they take in native resolutions. It prevents garbage due to fetching out of texture bounds, but can result in hard edges. (0=Off, 1=On)"); + assert(res == M64ERR_SUCCESS); //#Frame Buffer Settings:" res = ConfigSetDefaultBool(g_configVideoGliden64, "EnableFBEmulation", config.frameBufferEmulation.enable, "Enable frame and|or depth buffer emulation."); @@ -383,6 +389,8 @@ void Config_LoadCustomConfig() if (result == M64ERR_SUCCESS) config.graphics2D.enableNativeResTexrects = atoi(value); result = ConfigExternalGetParameter(fileHandle, sectionName, "graphics2D\\bgMode", value, sizeof(value)); if (result == M64ERR_SUCCESS) config.graphics2D.bgMode = atoi(value); + result = ConfigExternalGetParameter(fileHandle, sectionName, "graphics2D\\enableTexCoordBounds", value, sizeof(value)); + if (result == M64ERR_SUCCESS) config.graphics2D.enableTexCoordBounds = atoi(value); result = ConfigExternalGetParameter(fileHandle, sectionName, "frameBufferEmulation\\enable", value, sizeof(value)); if (result == M64ERR_SUCCESS) config.frameBufferEmulation.enable = atoi(value); @@ -509,6 +517,7 @@ void Config_LoadConfig() config.graphics2D.correctTexrectCoords = ConfigGetParamInt(g_configVideoGliden64, "CorrectTexrectCoords"); config.graphics2D.enableNativeResTexrects = ConfigGetParamInt(g_configVideoGliden64, "EnableNativeResTexrects"); config.graphics2D.bgMode = ConfigGetParamInt(g_configVideoGliden64, "BackgroundsMode"); + config.graphics2D.enableTexCoordBounds = ConfigGetParamInt(g_configVideoGliden64, "EnableTexCoordBounds"); //#Frame Buffer Settings:" config.frameBufferEmulation.enable = ConfigGetParamBool(g_configVideoGliden64, "EnableFBEmulation"); config.frameBufferEmulation.copyAuxToRDRAM = ConfigGetParamBool(g_configVideoGliden64, "EnableCopyAuxiliaryToRDRAM");