CGSH_OpenGL::TEXTURE_INFO CGSH_OpenGL::PrepareTexture(const TEX0& tex0) { TEXTURE_INFO texInfo; for(const auto& candidateFramebuffer : m_framebuffers) { bool canBeUsed = false; float offsetX = 0; //Case: TEX0 points at the start of a frame buffer with the same width if(candidateFramebuffer->m_basePtr == tex0.GetBufPtr() && candidateFramebuffer->m_width == tex0.GetBufWidth() && IsCompatibleFramebufferPSM(candidateFramebuffer->m_psm, tex0.nPsm)) { canBeUsed = true; } //Another case: TEX0 is pointing to the start of a page within our framebuffer (BGDA does this) else if(candidateFramebuffer->m_basePtr <= tex0.GetBufPtr() && candidateFramebuffer->m_psm == tex0.nPsm) { uint32 framebufferOffset = tex0.GetBufPtr() - candidateFramebuffer->m_basePtr; //Bail if offset is not aligned on a page boundary if((framebufferOffset & (CGsPixelFormats::PAGESIZE - 1)) != 0) continue; auto framebufferPageSize = CGsPixelFormats::GetPsmPageSize(candidateFramebuffer->m_psm); uint32 framebufferPageCountX = candidateFramebuffer->m_width / framebufferPageSize.first; uint32 framebufferPageIndex = framebufferOffset / CGsPixelFormats::PAGESIZE; //Bail if pointed page isn't on the first line if(framebufferPageIndex >= framebufferPageCountX) continue; canBeUsed = true; offsetX = static_cast<float>(framebufferPageIndex * framebufferPageSize.first) / static_cast<float>(candidateFramebuffer->m_width); } if(canBeUsed) { CommitFramebufferDirtyPages(candidateFramebuffer, 0, tex0.GetHeight()); //We have a winner glBindTexture(GL_TEXTURE_2D, candidateFramebuffer->m_texture); float scaleRatioX = static_cast<float>(tex0.GetWidth()) / static_cast<float>(candidateFramebuffer->m_textureWidth); float scaleRatioY = static_cast<float>(tex0.GetHeight()) / static_cast<float>(candidateFramebuffer->m_height); //If we're currently in interlaced mode, framebuffer will have twice the height bool halfHeight = GetCrtIsInterlaced() && GetCrtIsFrameMode(); if(halfHeight) scaleRatioY *= 2.0f; texInfo.offsetX = offsetX; texInfo.scaleRatioX = scaleRatioX; texInfo.scaleRatioY = scaleRatioY; return texInfo; } } auto texture = TexCache_Search(tex0); if(texture) { glBindTexture(GL_TEXTURE_2D, texture->m_texture); auto& cachedArea = texture->m_cachedArea; if(cachedArea.HasDirtyPages()) { auto texturePageSize = CGsPixelFormats::GetPsmPageSize(tex0.nPsm); auto pageRect = cachedArea.GetPageRect(); for(unsigned int dirtyPageIndex = 0; dirtyPageIndex < CGsCachedArea::MAX_DIRTYPAGES; dirtyPageIndex++) { if(!cachedArea.IsPageDirty(dirtyPageIndex)) continue; uint32 pageX = dirtyPageIndex % pageRect.first; uint32 pageY = dirtyPageIndex / pageRect.first; uint32 texX = pageX * texturePageSize.first; uint32 texY = pageY * texturePageSize.second; uint32 texWidth = texturePageSize.first; uint32 texHeight = texturePageSize.second; if(texX >= tex0.GetWidth()) continue; if(texY >= tex0.GetHeight()) continue; //assert(texX < tex0.GetWidth()); //assert(texY < tex0.GetHeight()); if((texX + texWidth) > tex0.GetWidth()) { texWidth = tex0.GetWidth() - texX; } if((texY + texHeight) > tex0.GetHeight()) { texHeight = tex0.GetHeight() - texY; } ((this)->*(m_textureUpdater[tex0.nPsm]))(tex0.GetBufPtr(), tex0.nBufWidth, texX, texY, texWidth, texHeight); } cachedArea.ClearDirtyPages(); } } else { //Validate texture dimensions to prevent problems auto texWidth = tex0.GetWidth(); auto texHeight = tex0.GetHeight(); assert(texWidth <= 1024); assert(texHeight <= 1024); texWidth = std::min<uint32>(texWidth, 1024); texHeight = std::min<uint32>(texHeight, 1024); GLuint nTexture = 0; glGenTextures(1, &nTexture); glBindTexture(GL_TEXTURE_2D, nTexture); ((this)->*(m_textureUploader[tex0.nPsm]))(tex0.GetBufPtr(), tex0.nBufWidth, texWidth, texHeight); TexCache_Insert(tex0, nTexture); } return texInfo; }
void CGSH_Direct3D9::SetRenderingContext(uint64 primReg) { auto prim = make_convertible<PRMODE>(primReg); unsigned int context = prim.nContext; uint64 testReg = m_nReg[GS_REG_TEST_1 + context]; uint64 frameReg = m_nReg[GS_REG_FRAME_1 + context]; uint64 alphaReg = m_nReg[GS_REG_ALPHA_1 + context]; uint64 zbufReg = m_nReg[GS_REG_ZBUF_1 + context]; uint64 tex0Reg = m_nReg[GS_REG_TEX0_1 + context]; uint64 tex1Reg = m_nReg[GS_REG_TEX1_1 + context]; uint64 clampReg = m_nReg[GS_REG_CLAMP_1 + context]; uint64 scissorReg = m_nReg[GS_REG_SCISSOR_1 + context]; if(!m_renderState.isValid || (m_renderState.primReg != primReg)) { m_device->SetRenderState(D3DRS_ALPHABLENDENABLE, ((prim.nAlpha != 0) && m_alphaBlendingEnabled) ? TRUE : FALSE); } if(!m_renderState.isValid || (m_renderState.alphaReg != alphaReg)) { SetupBlendingFunction(alphaReg); } if(!m_renderState.isValid || (m_renderState.testReg != testReg)) { SetupTestFunctions(testReg); } if(!m_renderState.isValid || (m_renderState.zbufReg != zbufReg) || (m_renderState.frameReg != frameReg)) { SetupDepthBuffer(zbufReg, frameReg); } if(!m_renderState.isValid || (m_renderState.frameReg != frameReg) || (m_renderState.scissorReg != scissorReg)) { SetupFramebuffer(frameReg, scissorReg); } if(!m_renderState.isValid || (m_renderState.tex0Reg != tex0Reg) || (m_renderState.tex1Reg != tex1Reg) || (m_renderState.clampReg != clampReg)) { SetupTexture(tex0Reg, tex1Reg, clampReg); } m_renderState.isValid = true; m_renderState.primReg = primReg; m_renderState.alphaReg = alphaReg; m_renderState.testReg = testReg; m_renderState.zbufReg = zbufReg; m_renderState.frameReg = frameReg; m_renderState.tex0Reg = tex0Reg; m_renderState.tex1Reg = tex1Reg; m_renderState.clampReg = clampReg; m_renderState.scissorReg = scissorReg; auto offset = make_convertible<XYOFFSET>(m_nReg[GS_REG_XYOFFSET_1 + context]); m_nPrimOfsX = offset.GetX(); m_nPrimOfsY = offset.GetY(); if(GetCrtIsInterlaced() && GetCrtIsFrameMode()) { if(m_nCSR & CSR_FIELD) { m_nPrimOfsY += 0.5; } } }