diff --git a/GPU/Directx9/GPU_DX9.cpp b/GPU/Directx9/GPU_DX9.cpp index f3bd3a217fae..7dc8efe47731 100644 --- a/GPU/Directx9/GPU_DX9.cpp +++ b/GPU/Directx9/GPU_DX9.cpp @@ -740,8 +740,10 @@ void DIRECTX9_GPU::ExecuteOp(u32 op, u32 diff) { case GE_CMD_REGION1: case GE_CMD_REGION2: - if (diff) + if (diff) { gstate_c.framebufChanged = true; + gstate_c.textureChanged = true; + } break; case GE_CMD_CLIPENABLE: @@ -830,8 +832,10 @@ void DIRECTX9_GPU::ExecuteOp(u32 op, u32 diff) { case GE_CMD_FRAMEBUFPTR: case GE_CMD_FRAMEBUFWIDTH: case GE_CMD_FRAMEBUFPIXFORMAT: - if (diff) + if (diff) { gstate_c.framebufChanged = true; + gstate_c.textureChanged = true; + } break; case GE_CMD_TEXADDR0: @@ -1045,8 +1049,10 @@ void DIRECTX9_GPU::ExecuteOp(u32 op, u32 diff) { case GE_CMD_VIEWPORTY2: case GE_CMD_VIEWPORTZ1: case GE_CMD_VIEWPORTZ2: - if (diff) + if (diff) { gstate_c.framebufChanged = true; + gstate_c.textureChanged = true; + } break; case GE_CMD_LIGHTENABLE0: diff --git a/GPU/GLES/Framebuffer.cpp b/GPU/GLES/Framebuffer.cpp index 8613a5113062..7f8efd786a43 100644 --- a/GPU/GLES/Framebuffer.cpp +++ b/GPU/GLES/Framebuffer.cpp @@ -331,6 +331,10 @@ FramebufferManager::~FramebufferManager() { } SetNumExtraFBOs(0); + for (auto it = renderCopies_.begin(), end = renderCopies_.end(); it != end; ++it) { + fbo_destroy(it->second); + } + #ifndef USING_GLES2 delete [] pixelBufObj_; #endif @@ -907,6 +911,7 @@ void FramebufferManager::BindFramebufferDepth(VirtualFramebuffer *sourceframebuf if (MaskedEqual(sourceframebuffer->z_address, targetframebuffer->z_address) && sourceframebuffer->renderWidth == targetframebuffer->renderWidth && sourceframebuffer->renderHeight == targetframebuffer->renderHeight) { + #ifndef USING_GLES2 if (gl_extensions.FBO_ARB) { #else @@ -922,7 +927,53 @@ void FramebufferManager::BindFramebufferDepth(VirtualFramebuffer *sourceframebuf #endif } } +} + +void FramebufferManager::BindFramebufferColor(VirtualFramebuffer *framebuffer) { + if (!framebuffer->fbo || !useBufferedRendering_) { + glBindTexture(GL_TEXTURE_2D, 0); + gstate_c.skipDrawReason |= SKIPDRAW_BAD_FB_TEXTURE; + return; + } + + if (MaskedEqual(framebuffer->fb_address, gstate.getFrameBufRawAddress())) { +#ifndef USING_GLES2 + if (gl_extensions.FBO_ARB) { +#else + if (gl_extensions.GLES3) { +#endif +#ifdef MAY_HAVE_GLES3 + // TODO: Maybe merge with bvfbs_? Not sure if those could be packing, and they're created at a different size. + FBO *renderCopy = NULL; + std::pair copySize = std::make_pair((int)framebuffer->renderWidth, (int)framebuffer->renderHeight); + for (auto it = renderCopies_.begin(), end = renderCopies_.end(); it != end; ++it) { + if (it->first == copySize) { + renderCopy = it->second; + break; + } + } + if (!renderCopy) { + renderCopy = fbo_create(framebuffer->renderWidth, framebuffer->renderHeight, 1, true, framebuffer->colorDepth); + renderCopies_[copySize] = renderCopy; + } + + fbo_bind_as_render_target(renderCopy); + glViewport(0, 0, framebuffer->renderWidth, framebuffer->renderHeight); + fbo_bind_for_read(framebuffer->fbo); + glBlitFramebuffer(0, 0, framebuffer->renderWidth, framebuffer->renderHeight, 0, 0, framebuffer->renderWidth, framebuffer->renderHeight, GL_COLOR_BUFFER_BIT, GL_NEAREST); + + fbo_bind_as_render_target(currentRenderVfb_->fbo); + if (gl_extensions.gpuVendor != GPU_VENDOR_POWERVR) + glstate.viewport.restore(); + fbo_bind_color_as_texture(renderCopy, 0); +#endif + } else { + fbo_bind_color_as_texture(framebuffer->fbo, 0); + } + } else { + fbo_bind_color_as_texture(framebuffer->fbo, 0); + } } void FramebufferManager::CopyDisplayToOutput() { diff --git a/GPU/GLES/Framebuffer.h b/GPU/GLES/Framebuffer.h index 3d4277742aef..0c6d777efceb 100644 --- a/GPU/GLES/Framebuffer.h +++ b/GPU/GLES/Framebuffer.h @@ -139,7 +139,10 @@ class FramebufferManager { void SetLineWidth(); void BindFramebufferDepth(VirtualFramebuffer *sourceframebuffer, VirtualFramebuffer *targetframebuffer); - + + // For use when texturing from a framebuffer. May create a duplicate if target. + void BindFramebufferColor(VirtualFramebuffer *framebuffer); + // Just for logging right now. Might remove/change. void NotifyBlockTransfer(u32 dst, u32 src); @@ -228,6 +231,7 @@ class FramebufferManager { bool useBufferedRendering_; std::vector bvfbs_; // blitting FBOs + std::map, FBO *> renderCopies_; std::set> knownFramebufferCopies_; diff --git a/GPU/GLES/GLES_GPU.cpp b/GPU/GLES/GLES_GPU.cpp index 1bd87cf69efa..a25bc42267cf 100644 --- a/GPU/GLES/GLES_GPU.cpp +++ b/GPU/GLES/GLES_GPU.cpp @@ -397,6 +397,7 @@ GLES_GPU::GLES_GPU() transformDraw_.SetFramebufferManager(&framebufferManager_); framebufferManager_.SetTextureCache(&textureCache_); framebufferManager_.SetShaderManager(shaderManager_); + textureCache_.SetFramebufferManager(&framebufferManager_); // Sanity check gstate if ((int *)&gstate.transferstart - (int *)&gstate != 0xEA) { @@ -893,8 +894,10 @@ void GLES_GPU::ExecuteOpInternal(u32 op, u32 diff) { case GE_CMD_REGION1: case GE_CMD_REGION2: - if (diff) + if (diff) { gstate_c.framebufChanged = true; + gstate_c.textureChanged = true; + } break; case GE_CMD_CLIPENABLE: @@ -970,8 +973,10 @@ void GLES_GPU::ExecuteOpInternal(u32 op, u32 diff) { case GE_CMD_SCISSOR1: case GE_CMD_SCISSOR2: - if (diff) + if (diff) { gstate_c.framebufChanged = true; + gstate_c.textureChanged = true; + } break; /// @@ -982,8 +987,10 @@ void GLES_GPU::ExecuteOpInternal(u32 op, u32 diff) { case GE_CMD_FRAMEBUFPTR: case GE_CMD_FRAMEBUFWIDTH: case GE_CMD_FRAMEBUFPIXFORMAT: - if (diff) + if (diff) { gstate_c.framebufChanged = true; + gstate_c.textureChanged = true; + } break; case GE_CMD_TEXADDR0: @@ -1209,8 +1216,10 @@ void GLES_GPU::ExecuteOpInternal(u32 op, u32 diff) { case GE_CMD_VIEWPORTY2: case GE_CMD_VIEWPORTZ1: case GE_CMD_VIEWPORTZ2: - if (diff) + if (diff) { gstate_c.framebufChanged = true; + gstate_c.textureChanged = true; + } break; case GE_CMD_LIGHTENABLE0: diff --git a/GPU/GLES/TextureCache.cpp b/GPU/GLES/TextureCache.cpp index 44d3df79eb27..fc7c23f4bab1 100644 --- a/GPU/GLES/TextureCache.cpp +++ b/GPU/GLES/TextureCache.cpp @@ -285,7 +285,7 @@ void TextureCache::NotifyFramebuffer(u32 address, VirtualFramebuffer *framebuffe } } -void *TextureCache::UnswizzleFromMem(u32 texaddr, u32 bufw, u32 bytesPerPixel, u32 level) { +void *TextureCache::UnswizzleFromMem(const u8 *texptr, u32 bufw, u32 bytesPerPixel, u32 level) { const u32 rowWidth = (bytesPerPixel > 0) ? (bufw * bytesPerPixel) : (bufw / 2); const u32 pitch = rowWidth / 4; const int bxc = rowWidth / 16; @@ -295,7 +295,7 @@ void *TextureCache::UnswizzleFromMem(u32 texaddr, u32 bufw, u32 bytesPerPixel, u u32 ydest = 0; if (rowWidth >= 16) { - const u32 *src = (u32 *) Memory::GetPointer(texaddr); + const u32 *src = (const u32 *) texptr; u32 *ydestp = tmpTexBuf32.data(); for (int by = 0; by < byc; by++) { u32 *xdest = ydestp; @@ -311,7 +311,7 @@ void *TextureCache::UnswizzleFromMem(u32 texaddr, u32 bufw, u32 bytesPerPixel, u ydestp += (rowWidth * 8) / 4; } } else if (rowWidth == 8) { - const u32 *src = (u32 *) Memory::GetPointer(texaddr); + const u32 *src = (const u32 *) texptr; for (int by = 0; by < byc; by++) { for (int n = 0; n < 8; n++, ydest += 2) { tmpTexBuf32[ydest + 0] = *src++; @@ -320,7 +320,7 @@ void *TextureCache::UnswizzleFromMem(u32 texaddr, u32 bufw, u32 bytesPerPixel, u } } } else if (rowWidth == 4) { - const u32 *src = (u32 *) Memory::GetPointer(texaddr); + const u32 *src = (const u32 *) texptr; for (int by = 0; by < byc; by++) { for (int n = 0; n < 8; n++, ydest++) { tmpTexBuf32[ydest] = *src++; @@ -328,7 +328,7 @@ void *TextureCache::UnswizzleFromMem(u32 texaddr, u32 bufw, u32 bytesPerPixel, u } } } else if (rowWidth == 2) { - const u16 *src = (u16 *) Memory::GetPointer(texaddr); + const u16 *src = (const u16 *) texptr; for (int by = 0; by < byc; by++) { for (int n = 0; n < 4; n++, ydest++) { u16 n1 = src[0]; @@ -338,7 +338,7 @@ void *TextureCache::UnswizzleFromMem(u32 texaddr, u32 bufw, u32 bytesPerPixel, u } } } else if (rowWidth == 1) { - const u8 *src = (u8 *) Memory::GetPointer(texaddr); + const u8 *src = (const u8 *) texptr; for (int by = 0; by < byc; by++) { for (int n = 0; n < 2; n++, ydest++) { u8 n1 = src[ 0]; @@ -353,7 +353,7 @@ void *TextureCache::UnswizzleFromMem(u32 texaddr, u32 bufw, u32 bytesPerPixel, u return tmpTexBuf32.data(); } -void *TextureCache::ReadIndexedTex(int level, u32 texaddr, int bytesPerIndex, GLuint dstFmt, int bufw) { +void *TextureCache::ReadIndexedTex(int level, const u8 *texptr, int bytesPerIndex, GLuint dstFmt, int bufw) { int w = gstate.getTextureWidth(level); int h = gstate.getTextureHeight(level); int length = bufw * h; @@ -369,20 +369,20 @@ void *TextureCache::ReadIndexedTex(int level, u32 texaddr, int bytesPerIndex, GL if (!gstate.isTextureSwizzled()) { switch (bytesPerIndex) { case 1: - DeIndexTexture(tmpTexBuf16.data(), texaddr, length, clut); + DeIndexTexture(tmpTexBuf16.data(), (const u8 *)texptr, length, clut); break; case 2: - DeIndexTexture(tmpTexBuf16.data(), texaddr, length, clut); + DeIndexTexture(tmpTexBuf16.data(), (const u16_le *)texptr, length, clut); break; case 4: - DeIndexTexture(tmpTexBuf16.data(), texaddr, length, clut); + DeIndexTexture(tmpTexBuf16.data(), (const u32_le *)texptr, length, clut); break; } } else { tmpTexBuf32.resize(std::max(bufw, w) * h); - UnswizzleFromMem(texaddr, bufw, bytesPerIndex, level); + UnswizzleFromMem(texptr, bufw, bytesPerIndex, level); switch (bytesPerIndex) { case 1: DeIndexTexture(tmpTexBuf16.data(), (u8 *) tmpTexBuf32.data(), length, clut); @@ -409,20 +409,20 @@ void *TextureCache::ReadIndexedTex(int level, u32 texaddr, int bytesPerIndex, GL if (!gstate.isTextureSwizzled()) { switch (bytesPerIndex) { case 1: - DeIndexTexture(tmpTexBuf32.data(), texaddr, length, clut); + DeIndexTexture(tmpTexBuf32.data(), (const u8 *)texptr, length, clut); break; case 2: - DeIndexTexture(tmpTexBuf32.data(), texaddr, length, clut); + DeIndexTexture(tmpTexBuf32.data(), (const u16_le *)texptr, length, clut); break; case 4: - DeIndexTexture(tmpTexBuf32.data(), texaddr, length, clut); + DeIndexTexture(tmpTexBuf32.data(), (const u32_le *)texptr, length, clut); break; } buf = tmpTexBuf32.data(); } else { - UnswizzleFromMem(texaddr, bufw, bytesPerIndex, level); + UnswizzleFromMem(texptr, bufw, bytesPerIndex, level); // Since we had to unswizzle to tmpTexBuf32, let's output to tmpTexBuf16. tmpTexBuf16.resize(std::max(bufw, w) * h * 2); u32 *dest32 = (u32 *) tmpTexBuf16.data(); @@ -830,22 +830,15 @@ bool SetDebugTexture() { } #endif -void TextureCache::SetTextureFramebuffer(TexCacheEntry *entry) -{ +void TextureCache::SetTextureFramebuffer(TexCacheEntry *entry) { entry->framebuffer->usageFlags |= FB_USAGE_TEXTURE; bool useBufferedRendering = g_Config.iRenderingMode != FB_NON_BUFFERED_MODE; if (useBufferedRendering) { - // For now, let's not bind FBOs that we know are off (invalidHint will be -1.) - // But let's still not use random memory. - if (entry->framebuffer->fbo) { - fbo_bind_color_as_texture(entry->framebuffer->fbo, 0); - // Keep the framebuffer alive. - // TODO: Dangerous if it sets a new one? - entry->framebuffer->last_frame_used = gpuStats.numFlips; - } else { - glBindTexture(GL_TEXTURE_2D, 0); - gstate_c.skipDrawReason |= SKIPDRAW_BAD_FB_TEXTURE; - } + framebufferManager_->BindFramebufferColor(entry->framebuffer); + + // Keep the framebuffer alive. + entry->framebuffer->last_frame_used = gpuStats.numFlips; + // We need to force it, since we may have set it on a texture before attaching. UpdateSamplingParams(*entry, true); gstate_c.curTextureWidth = entry->framebuffer->width; @@ -883,11 +876,6 @@ void TextureCache::SetTexture(bool force) { int w = gstate.getTextureWidth(0); int h = gstate.getTextureHeight(0); - u32 fb_addr = gstate.getFrameBufRawAddress() | 0x04000000; - if (fb_addr == gstate.getTextureAddress(0)) { - WARN_LOG_REPORT(HLE, "Texturing from same buffer as target (%08x : %ix%i)", fb_addr, w, h); - } - GETextureFormat format = gstate.getTextureFormat(); if (format >= 11) { ERROR_LOG_REPORT(G3D, "Unknown texture format %i", format); @@ -1263,17 +1251,17 @@ void *TextureCache::DecodeTextureLevel(GETextureFormat format, GEPaletteFormat c texByteAlign = 2; if (!gstate.isTextureSwizzled()) { if (clutAlphaLinear_ && mipmapShareClut) { - DeIndexTexture4Optimal(tmpTexBuf16.data(), texaddr, bufw * h, clutAlphaLinearColor_); + DeIndexTexture4Optimal(tmpTexBuf16.data(), texptr, bufw * h, clutAlphaLinearColor_); } else { - DeIndexTexture4(tmpTexBuf16.data(), texaddr, bufw * h, clut); + DeIndexTexture4(tmpTexBuf16.data(), texptr, bufw * h, clut); } } else { tmpTexBuf32.resize(std::max(bufw, w) * h); - UnswizzleFromMem(texaddr, bufw, 0, level); + UnswizzleFromMem(texptr, bufw, 0, level); if (clutAlphaLinear_ && mipmapShareClut) { - DeIndexTexture4Optimal(tmpTexBuf16.data(), (u8 *)tmpTexBuf32.data(), bufw * h, clutAlphaLinearColor_); + DeIndexTexture4Optimal(tmpTexBuf16.data(), (const u8 *)tmpTexBuf32.data(), bufw * h, clutAlphaLinearColor_); } else { - DeIndexTexture4(tmpTexBuf16.data(), (u8 *)tmpTexBuf32.data(), bufw * h, clut); + DeIndexTexture4(tmpTexBuf16.data(), (const u8 *)tmpTexBuf32.data(), bufw * h, clut); } } finalBuf = tmpTexBuf16.data(); @@ -1286,10 +1274,10 @@ void *TextureCache::DecodeTextureLevel(GETextureFormat format, GEPaletteFormat c tmpTexBufRearrange.resize(std::max(bufw, w) * h); const u32 *clut = GetCurrentClut() + clutSharingOffset; if (!gstate.isTextureSwizzled()) { - DeIndexTexture4(tmpTexBuf32.data(), texaddr, bufw * h, clut); + DeIndexTexture4(tmpTexBuf32.data(), texptr, bufw * h, clut); finalBuf = tmpTexBuf32.data(); } else { - UnswizzleFromMem(texaddr, bufw, 0, level); + UnswizzleFromMem(texptr, bufw, 0, level); // Let's reuse tmpTexBuf16, just need double the space. tmpTexBuf16.resize(std::max(bufw, w) * h * 2); DeIndexTexture4((u32 *)tmpTexBuf16.data(), (u8 *)tmpTexBuf32.data(), bufw * h, clut); @@ -1307,17 +1295,17 @@ void *TextureCache::DecodeTextureLevel(GETextureFormat format, GEPaletteFormat c case GE_TFMT_CLUT8: texByteAlign = texByteAlignMap[gstate.getClutPaletteFormat()]; - finalBuf = ReadIndexedTex(level, texaddr, 1, dstFmt, bufw); + finalBuf = ReadIndexedTex(level, texptr, 1, dstFmt, bufw); break; case GE_TFMT_CLUT16: texByteAlign = texByteAlignMap[gstate.getClutPaletteFormat()]; - finalBuf = ReadIndexedTex(level, texaddr, 2, dstFmt, bufw); + finalBuf = ReadIndexedTex(level, texptr, 2, dstFmt, bufw); break; case GE_TFMT_CLUT32: texByteAlign = texByteAlignMap[gstate.getClutPaletteFormat()]; - finalBuf = ReadIndexedTex(level, texaddr, 4, dstFmt, bufw); + finalBuf = ReadIndexedTex(level, texptr, 4, dstFmt, bufw); break; case GE_TFMT_4444: @@ -1330,10 +1318,10 @@ void *TextureCache::DecodeTextureLevel(GETextureFormat format, GEPaletteFormat c tmpTexBuf16.resize(len); tmpTexBufRearrange.resize(len); finalBuf = tmpTexBuf16.data(); - ConvertColors(finalBuf, Memory::GetPointer(texaddr), dstFmt, bufw * h); + ConvertColors(finalBuf, texptr, dstFmt, bufw * h); } else { tmpTexBuf32.resize(std::max(bufw, w) * h); - finalBuf = UnswizzleFromMem(texaddr, bufw, 2, level); + finalBuf = UnswizzleFromMem(texptr, bufw, 2, level); ConvertColors(finalBuf, finalBuf, dstFmt, bufw * h); } break; @@ -1342,18 +1330,18 @@ void *TextureCache::DecodeTextureLevel(GETextureFormat format, GEPaletteFormat c if (!gstate.isTextureSwizzled()) { // Special case: if we don't need to deal with packing, we don't need to copy. if ((g_Config.iTexScalingLevel == 1 && gl_extensions.EXT_unpack_subimage) || w == bufw) { - finalBuf = Memory::GetPointer(texaddr); + finalBuf = (void *)texptr; } else { int len = bufw * h; tmpTexBuf32.resize(std::max(bufw, w) * h); tmpTexBufRearrange.resize(std::max(bufw, w) * h); - Memory::Memcpy(tmpTexBuf32.data(), texaddr, len * sizeof(u32)); + memcpy(tmpTexBuf32.data(), texptr, len * sizeof(u32)); finalBuf = tmpTexBuf32.data(); } } else { tmpTexBuf32.resize(std::max(bufw, w) * h); - finalBuf = UnswizzleFromMem(texaddr, bufw, 4, level); + finalBuf = UnswizzleFromMem(texptr, bufw, 4, level); } break; diff --git a/GPU/GLES/TextureCache.h b/GPU/GLES/TextureCache.h index 7637788c9ca4..5516f7f301c2 100644 --- a/GPU/GLES/TextureCache.h +++ b/GPU/GLES/TextureCache.h @@ -24,6 +24,7 @@ #include "TextureScaler.h" struct VirtualFramebuffer; +class FramebufferManager; enum TextureFiltering { AUTO = 1, @@ -56,6 +57,10 @@ class TextureCache { // are being rendered to. This is barebones so far. void NotifyFramebuffer(u32 address, VirtualFramebuffer *framebuffer, FramebufferNotification msg); + void SetFramebufferManager(FramebufferManager *fbManager) { + framebufferManager_ = fbManager; + } + size_t NumLoadedTextures() const { return cache.size(); } @@ -115,8 +120,8 @@ class TextureCache { }; void Decimate(); // Run this once per frame to get rid of old textures. - void *UnswizzleFromMem(u32 texaddr, u32 bufw, u32 bytesPerPixel, u32 level); - void *ReadIndexedTex(int level, u32 texaddr, int bytesPerIndex, GLuint dstFmt, int bufw); + void *UnswizzleFromMem(const u8 *texptr, u32 bufw, u32 bytesPerPixel, u32 level); + void *ReadIndexedTex(int level, const u8 *texptr, int bytesPerIndex, GLuint dstFmt, int bufw); void UpdateSamplingParams(TexCacheEntry &entry, bool force); void LoadTextureLevel(TexCacheEntry &entry, int level, bool replaceImages, GLenum dstFmt); GLenum GetDestFormat(GETextureFormat format, GEPaletteFormat clutFormat) const; @@ -160,5 +165,6 @@ class TextureCache { float maxAnisotropyLevel; int decimationCounter_; + FramebufferManager *framebufferManager_; };