BPMemLoader.cpp 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179
  1. // Copyright 2009 Dolphin Emulator Project
  2. // Licensed under GPLv2+
  3. // Refer to the license.txt file included.
  4. #include "Core/ConfigManager.h"
  5. #include "Core/Core.h"
  6. #include "Core/HW/Memmap.h"
  7. #include "VideoBackends/Software/BPMemLoader.h"
  8. #include "VideoBackends/Software/EfbCopy.h"
  9. #include "VideoBackends/Software/EfbInterface.h"
  10. #include "VideoBackends/Software/Rasterizer.h"
  11. #include "VideoBackends/Software/Tev.h"
  12. #include "VideoCommon/BoundingBox.h"
  13. #include "VideoCommon/PixelEngine.h"
  14. #include "VideoCommon/TextureDecoder.h"
  15. #include "VideoCommon/VideoCommon.h"
  16. void InitBPMemory()
  17. {
  18. memset(&bpmem, 0, sizeof(bpmem));
  19. bpmem.bpMask = 0xFFFFFF;
  20. }
  21. void SWLoadBPReg(u32 value)
  22. {
  23. //handle the mask register
  24. int address = value >> 24;
  25. int oldval = ((u32*)&bpmem)[address];
  26. int newval = (oldval & ~bpmem.bpMask) | (value & bpmem.bpMask);
  27. ((u32*)&bpmem)[address] = newval;
  28. //reset the mask register
  29. if (address != 0xFE)
  30. bpmem.bpMask = 0xFFFFFF;
  31. SWBPWritten(address, newval);
  32. }
  33. void SWBPWritten(int address, int newvalue)
  34. {
  35. switch (address)
  36. {
  37. case BPMEM_SCISSORTL:
  38. case BPMEM_SCISSORBR:
  39. case BPMEM_SCISSOROFFSET:
  40. Rasterizer::SetScissor();
  41. break;
  42. case BPMEM_SETDRAWDONE: // This is called when the game is done drawing (eg: like in DX: Begin(); Draw(); End();)
  43. switch (bpmem.drawdone & 0xFF)
  44. {
  45. case 0x02:
  46. PixelEngine::SetFinish(); // may generate interrupt
  47. DEBUG_LOG(VIDEO, "GXSetDrawDone SetPEFinish (value: 0x%02X)", (bpmem.drawdone & 0xFFFF));
  48. break;
  49. default:
  50. WARN_LOG(VIDEO, "GXSetDrawDone ??? (value 0x%02X)", (bpmem.drawdone & 0xFFFF));
  51. break;
  52. }
  53. break;
  54. case BPMEM_PE_TOKEN_ID: // Pixel Engine Token ID
  55. DEBUG_LOG(VIDEO, "SetPEToken 0x%04x", (bpmem.petoken & 0xFFFF));
  56. PixelEngine::SetToken(static_cast<u16>(bpmem.petokenint & 0xFFFF), false);
  57. break;
  58. case BPMEM_PE_TOKEN_INT_ID: // Pixel Engine Interrupt Token ID
  59. DEBUG_LOG(VIDEO, "SetPEToken + INT 0x%04x", (bpmem.petokenint & 0xFFFF));
  60. PixelEngine::SetToken(static_cast<u16>(bpmem.petokenint & 0xFFFF), true);
  61. break;
  62. case BPMEM_TRIGGER_EFB_COPY:
  63. EfbCopy::CopyEfb();
  64. break;
  65. case BPMEM_CLEARBBOX1:
  66. BoundingBox::coords[BoundingBox::LEFT] = newvalue >> 10;
  67. BoundingBox::coords[BoundingBox::RIGHT] = newvalue & 0x3ff;
  68. break;
  69. case BPMEM_CLEARBBOX2:
  70. BoundingBox::coords[BoundingBox::TOP] = newvalue >> 10;
  71. BoundingBox::coords[BoundingBox::BOTTOM] = newvalue & 0x3ff;
  72. break;
  73. case BPMEM_CLEAR_PIXEL_PERF:
  74. // TODO: I didn't test if the value written to this register affects the amount of cleared registers
  75. memset(EfbInterface::perf_values, 0, sizeof(EfbInterface::perf_values));
  76. break;
  77. case BPMEM_LOADTLUT0: // This one updates bpmem.tlutXferSrc, no need to do anything here.
  78. break;
  79. case BPMEM_LOADTLUT1: // Load a Texture Look Up Table
  80. {
  81. u32 tlutTMemAddr = (newvalue & 0x3FF) << 9;
  82. u32 tlutXferCount = (newvalue & 0x1FFC00) >> 5;
  83. u32 addr = bpmem.tmem_config.tlut_src << 5;
  84. // The GameCube ignores the upper bits of this address. Some games (WW, MKDD) set them.
  85. if (!SConfig::GetInstance().m_LocalCoreStartupParameter.bWii)
  86. addr = addr & 0x01FFFFFF;
  87. Memory::CopyFromEmu(texMem + tlutTMemAddr, addr, tlutXferCount);
  88. break;
  89. }
  90. case BPMEM_PRELOAD_MODE:
  91. if (newvalue != 0)
  92. {
  93. // TODO: Not quite sure if this is completely correct (likely not)
  94. // NOTE: libogc's implementation of GX_PreloadEntireTexture seems flawed, so it's not necessarily a good reference for RE'ing this feature.
  95. BPS_TmemConfig& tmem_cfg = bpmem.tmem_config;
  96. u32 src_addr = tmem_cfg.preload_addr << 5; // TODO: Should we add mask here on GC?
  97. u32 size = tmem_cfg.preload_tile_info.count * TMEM_LINE_SIZE;
  98. u32 tmem_addr_even = tmem_cfg.preload_tmem_even * TMEM_LINE_SIZE;
  99. if (tmem_cfg.preload_tile_info.type != 3)
  100. {
  101. if (tmem_addr_even + size > TMEM_SIZE)
  102. size = TMEM_SIZE - tmem_addr_even;
  103. Memory::CopyFromEmu(texMem + tmem_addr_even, src_addr, size);
  104. }
  105. else // RGBA8 tiles (and CI14, but that might just be stupid libogc!)
  106. {
  107. u8* src_ptr = Memory::GetPointer(src_addr);
  108. // AR and GB tiles are stored in separate TMEM banks => can't use a single memcpy for everything
  109. u32 tmem_addr_odd = tmem_cfg.preload_tmem_odd * TMEM_LINE_SIZE;
  110. for (unsigned int i = 0; i < tmem_cfg.preload_tile_info.count; ++i)
  111. {
  112. if (tmem_addr_even + TMEM_LINE_SIZE > TMEM_SIZE ||
  113. tmem_addr_odd + TMEM_LINE_SIZE > TMEM_SIZE)
  114. break;
  115. memcpy(texMem + tmem_addr_even, src_ptr, TMEM_LINE_SIZE);
  116. memcpy(texMem + tmem_addr_odd, src_ptr + TMEM_LINE_SIZE, TMEM_LINE_SIZE);
  117. tmem_addr_even += TMEM_LINE_SIZE;
  118. tmem_addr_odd += TMEM_LINE_SIZE;
  119. src_ptr += TMEM_LINE_SIZE * 2;
  120. }
  121. }
  122. }
  123. break;
  124. case BPMEM_TEV_COLOR_RA:
  125. case BPMEM_TEV_COLOR_RA + 2:
  126. case BPMEM_TEV_COLOR_RA + 4:
  127. case BPMEM_TEV_COLOR_RA + 6:
  128. {
  129. int regNum = (address >> 1 ) & 0x3;
  130. TevReg& reg = bpmem.tevregs[regNum];
  131. bool is_konst = reg.type_ra != 0;
  132. Rasterizer::SetTevReg(regNum, Tev::ALP_C, is_konst, static_cast<s16>(reg.alpha));
  133. Rasterizer::SetTevReg(regNum, Tev::RED_C, is_konst, static_cast<s16>(reg.red));
  134. break;
  135. }
  136. case BPMEM_TEV_COLOR_BG:
  137. case BPMEM_TEV_COLOR_BG + 2:
  138. case BPMEM_TEV_COLOR_BG + 4:
  139. case BPMEM_TEV_COLOR_BG + 6:
  140. {
  141. int regNum = (address >> 1 ) & 0x3;
  142. TevReg& reg = bpmem.tevregs[regNum];
  143. bool is_konst = reg.type_bg != 0;
  144. Rasterizer::SetTevReg(regNum, Tev::GRN_C, is_konst, static_cast<s16>(reg.green));
  145. Rasterizer::SetTevReg(regNum, Tev::BLU_C, is_konst, static_cast<s16>(reg.blue));
  146. break;
  147. }
  148. }
  149. }