Skip to content

Commit 3988a99

Browse files
committed
Fix camera, save file images and inventory background image
1 parent b6a4375 commit 3988a99

File tree

7 files changed

+100
-20
lines changed

7 files changed

+100
-20
lines changed

include/pch.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -613,4 +613,4 @@ struct data_VRProjectionMatrixOut {
613613

614614
#include "game_structs.h"
615615
#include "cemu.h"
616-
#include "utils/logger.h"
616+
#include "utils/logger.h"

resources/BreathOfTheWild_BetterVR/patch_RND_Find3DFrameBuffer.asm

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -177,4 +177,35 @@ blr
177177

178178

179179
0x039B3044 = bla hookPostHDRComposedImage
180-
;0x0397AB30 = cmpw r3, r3
180+
;0x0397AB30 = cmpw r3, r3
181+
182+
183+
; for one frame, disable clearing the framebuffer (used for separating 2D hud from 3D scene)
184+
custom_turnOnTempLayerCopy:
185+
mflr r0
186+
stwu r1, -0x10(r1)
187+
stw r0, 0x14(r1)
188+
stw r3, 0x0C(r1)
189+
stw r4, 0x08(r1)
190+
stw r5, 0x04(r1)
191+
192+
; original code
193+
lwz r3, 0x86C(r3)
194+
li r4, 1
195+
stb r4, 0x318(r3)
196+
197+
lis r4, currentFrameCounter@ha
198+
lwz r4, currentFrameCounter@l(r4)
199+
lis r5, currentEyeSide@ha
200+
lwz r5, currentEyeSide@l(r5)
201+
bla import.coreinit.hook_FixCameraSaveFilesAndInventory
202+
203+
lwz r5, 0x04(r1)
204+
lwz r4, 0x08(r1)
205+
lwz r3, 0x0C(r1)
206+
lwz r0, 0x14(r1)
207+
addi r1, r1, 0x10
208+
mtlr r0
209+
blr
210+
211+
0x0340A8A8 = ba custom_turnOnTempLayerCopy

src/hooking/camera.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@
22
#include "instance.h"
33
#include "rendering/openxr.h"
44

5+
bool CemuHooks::UseMonoFrameBufferTemporarilyDuringMenusOrPictures() {
6+
return IsScreenOpen(ScreenId::PauseMenuInfo_00) || VRManager::instance().XR->GetRenderer()->IsGameCapturing3DFrameBuffer();
7+
}
58

69
void CemuHooks::hook_BeginCameraSide(PPCInterpreter_t* hCPU) {
710
hCPU->instructionPointer = hCPU->sprNew.LR;
@@ -335,6 +338,11 @@ void CemuHooks::hook_GetRenderProjection(PPCInterpreter_t* hCPU) {
335338
return;
336339
}
337340

341+
if (UseMonoFrameBufferTemporarilyDuringMenusOrPictures()) {
342+
return;
343+
}
344+
345+
338346
uint32_t projectionIn = hCPU->gpr[3];
339347
uint32_t projectionOut = hCPU->gpr[12];
340348
OpenXR::EyeSide side = hCPU->gpr[0] == 0 ? EyeSide::LEFT : EyeSide::RIGHT;
@@ -400,6 +408,10 @@ void CemuHooks::hook_ModifyLightPrePassProjectionMatrix(PPCInterpreter_t* hCPU)
400408
if (UseBlackBarsDuringEvents()) {
401409
return;
402410
}
411+
412+
if (UseMonoFrameBufferTemporarilyDuringMenusOrPictures()) {
413+
return;
414+
}
403415

404416
uint32_t projectionIn = hCPU->gpr[3];
405417
OpenXR::EyeSide side = hCPU->gpr[11] == 0 ? EyeSide::LEFT : EyeSide::RIGHT;
@@ -463,6 +475,10 @@ void CemuHooks::hook_ModifyProjectionUsingCamera(PPCInterpreter_t* hCPU) {
463475
return;
464476
}
465477

478+
if (UseMonoFrameBufferTemporarilyDuringMenusOrPictures()) {
479+
return;
480+
}
481+
466482
uint32_t projectionPtr = hCPU->gpr[4];
467483
uint32_t cameraPtr = hCPU->gpr[7];
468484
OpenXR::EyeSide side = hCPU->gpr[5] == 0 ? EyeSide::LEFT : EyeSide::RIGHT;

src/hooking/cemu_hooks.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ class CemuHooks {
7171
osLib_registerHLEFunction("coreinit", "hook_ModifyHandModelAccessSearch", &hook_ModifyHandModelAccessSearch);
7272
osLib_registerHLEFunction("coreinit", "hook_CreateNewScreen", &hook_CreateNewScreen);
7373
osLib_registerHLEFunction("coreinit", "hook_FixUIBlending", &hook_FixUIBlending);
74+
osLib_registerHLEFunction("coreinit", "hook_FixCameraSaveFilesAndInventory", &hook_FixCameraSaveFilesAndInventory);
7475
};
7576
~CemuHooks() {
7677
FreeLibrary(m_cemuHandle);

src/hooking/framebuffer.cpp

Lines changed: 35 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,19 @@ void VkDeviceOverrides::DestroyImage(const vkroots::VkDeviceDispatch& pDispatch,
4040
pDispatch.DestroyImage(device, image, pAllocator);
4141
}
4242

43+
44+
void CemuHooks::hook_FixCameraSaveFilesAndInventory(PPCInterpreter_t* hCPU) {
45+
hCPU->instructionPointer = hCPU->sprNew.LR;
46+
47+
uint32_t isEnabling3DFramebufferCapture = hCPU->gpr[3];
48+
EyeSide side = (EyeSide)hCPU->gpr[4];
49+
uint32_t frameIdx = hCPU->gpr[5];
50+
51+
Log::print<PPC>("hook_FixCameraSaveFilesAndInventory: isEnabling3DFramebufferCapture={}, side={}, frameIdx={}", isEnabling3DFramebufferCapture, side, frameIdx);
52+
VRManager::instance().XR->GetRenderer()->SignalGameCapturing3DFrameBuffer();
53+
}
54+
55+
4356
void VkDeviceOverrides::CmdClearColorImage(const vkroots::VkCommandBufferDispatch& pDispatch, VkCommandBuffer commandBuffer, VkImage image, VkImageLayout imageLayout, const VkClearColorValue* pColor, uint32_t rangeCount, const VkImageSubresourceRange* pRanges) {
4457
// check whether the magic values are there, and which order they are in to determine which eye
4558
OpenXR::EyeSide side = (OpenXR::EyeSide)-1;
@@ -128,6 +141,13 @@ void VkDeviceOverrides::CmdClearColorImage(const vkroots::VkCommandBufferDispatc
128141
VulkanUtils::DebugPipelineBarrier(commandBuffer);
129142
};
130143

144+
RND_Renderer::RenderFrame& frame = renderer->GetFrame(frameIdx);
145+
146+
auto clearFramebuffer = [&](bool disableAlpha) -> void {
147+
VkClearColorValue clearColor = disableAlpha ? VkClearColorValue{ { 0.0f, 0.0f, 0.0f, 1.0f } } : VkClearColorValue{ { 0.0f, 0.0f, 0.0f, 0.0f } };
148+
pDispatch.CmdClearColorImage(commandBuffer, image, imageLayout, &clearColor, rangeCount, pRanges);
149+
};
150+
131151
// 3D layer - color texture for 3D rendering
132152
if (captureIdx == 0) {
133153
// check if the color texture has the appropriate texture format
@@ -149,24 +169,19 @@ void VkDeviceOverrides::CmdClearColorImage(const vkroots::VkCommandBufferDispatc
149169

150170
if (image != s_curr3DColorImage) {
151171
Log::print<RENDERING>("Color image is not the same as the current 3D color image! ({} != {})", (void*)image, (void*)s_curr3DColorImage);
152-
VkClearColorValue clearColor;
153-
if (VRManager::instance().XR->GetRenderer()->IsRendering3D(frameIdx)) {
154-
clearColor = {{ 0.0f, 0.0f, 0.0f, 0.0f }};
155-
}
156-
else {
157-
clearColor = {{ 0.0f, 0.0f, 0.0f, 1.0f }};
158-
}
159172
returnToLayout();
160-
return pDispatch.CmdClearColorImage(commandBuffer, image, imageLayout, &clearColor, rangeCount, pRanges);
173+
return clearFramebuffer(!VRManager::instance().XR->GetRenderer()->IsRendering3D(frameIdx));
161174
}
162175

163176
if (renderer->GetFrame(frameIdx).copiedColor[side]) {
164177
// the color texture has already been copied to the layer
165178
Log::print<RENDERING>("A 3D color texture is already been copied for the current frame!");
166179

167-
VkClearColorValue clearColor = {{ 0.0f, 0.0f, 0.0f, 0.0f }};
168180
returnToLayout();
169-
return pDispatch.CmdClearColorImage(commandBuffer, image, imageLayout, &clearColor, rangeCount, pRanges);
181+
if (CemuHooks::UseMonoFrameBufferTemporarilyDuringMenusOrPictures()) {
182+
return;
183+
}
184+
return clearFramebuffer(false);
170185
}
171186

172187
// note: This uses vkCmdCopyImage to copy the image to the D3D12-created interop texture. s_activeCopyOperations queues a semaphore for the D3D12 side to wait on.
@@ -178,6 +193,10 @@ void VkDeviceOverrides::CmdClearColorImage(const vkroots::VkCommandBufferDispatc
178193
s_activeCopyOperations.emplace_back(commandBuffer, texture);
179194
}
180195

196+
if (CemuHooks::UseMonoFrameBufferTemporarilyDuringMenusOrPictures()) {
197+
return;
198+
}
199+
181200
// imgui needs only one eye to render Cemu's 2D output, so use right side since it looks better
182201
if (side == EyeSide::RIGHT) {
183202
// note: Uses vkCmdCopyImage to copy the (right-eye-only) image to the imgui overlay's texture
@@ -186,23 +205,21 @@ void VkDeviceOverrides::CmdClearColorImage(const vkroots::VkCommandBufferDispatc
186205
}
187206

188207
// clear the image to be transparent to allow for the HUD to be rendered on top of it which results in a transparent HUD layer
189-
VkClearColorValue clearColor = {{ 0.0f, 0.0f, 0.0f, 0.0f }};
190208
returnToLayout();
191-
return pDispatch.CmdClearColorImage(commandBuffer, image, imageLayout, &clearColor, rangeCount, pRanges);
209+
return clearFramebuffer(false);
192210
}
193211

194212
// 2D layer - color texture for HUD rendering
195213
if (captureIdx == 2) {
196214
bool hudCopied = renderer->GetFrame(frameIdx).copied2D;
197215

198-
if (side == OpenXR::EyeSide::LEFT) {
216+
if (side == EyeSide::LEFT) {
199217
if (hudCopied) {
200218
// the 2D texture has already been copied to the layer
201219
Log::print<RENDERING>("A 2D texture has already been copied for the current frame!");
202220

203-
VkClearColorValue clearColor = {{ 0.0f, 0.0f, 0.0f, 0.0f }};
204221
returnToLayout();
205-
return pDispatch.CmdClearColorImage(commandBuffer, image, imageLayout, &clearColor, rangeCount, pRanges);
222+
return clearFramebuffer(false);
206223
}
207224
else {
208225
// provide the HUD texture to the imgui overlay we'll use to recomposite Cemu's original flatscreen rendering
@@ -232,7 +249,7 @@ void VkDeviceOverrides::CmdClearColorImage(const vkroots::VkCommandBufferDispatc
232249
return;
233250
}
234251
}
235-
if (side == OpenXR::EyeSide::RIGHT) {
252+
if (side == EyeSide::RIGHT) {
236253
// render the imgui overlay on the right side
237254
if (imguiOverlay) {
238255
// render imgui, and then copy the framebuffer to the 2D layer
@@ -244,12 +261,12 @@ void VkDeviceOverrides::CmdClearColorImage(const vkroots::VkCommandBufferDispatc
244261
}
245262

246263
if (hudCopied) {
247-
VkClearColorValue clearColor = {{ 0.0f, 0.0f, 0.0f, 0.0f }};
248264
returnToLayout();
249-
return pDispatch.CmdClearColorImage(commandBuffer, image, imageLayout, &clearColor, rangeCount, pRanges);
265+
return clearFramebuffer(false);
250266
}
251267
}
252268
}
269+
returnToLayout();
253270
return;
254271
}
255272
else {

src/rendering/renderer.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,11 @@ void RND_Renderer::EndFrame() {
130130
m_renderFrames[frameIdx].Reset();
131131
}
132132

133+
// decrement camera capture counter since its active only for a few frames
134+
if (m_cameraIsCapturing3DFrameBuffer > 0) {
135+
--m_cameraIsCapturing3DFrameBuffer;
136+
}
137+
133138
m_lastFrameWorkTimeMs = std::chrono::duration<double, std::milli>(std::chrono::high_resolution_clock::now() - m_frameStartTime).count();
134139

135140
XrFrameEndInfo frameEndInfo = { XR_TYPE_FRAME_END_INFO };

src/rendering/renderer.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ class RND_Renderer {
1919
std::atomic_bool copiedDepth[2] = { false, false };
2020
std::atomic_bool copied2D = false;
2121
std::atomic_bool presented3D = false;
22+
std::atomic_uint8_t cameraIsCapturing3DFramebuffer = 0;
2223

2324
std::unique_ptr<VulkanTexture> mainFramebuffer;
2425
std::unique_ptr<VulkanTexture> hudFramebuffer;
@@ -41,6 +42,8 @@ class RND_Renderer {
4142
copiedDepth[0] = false;
4243
copiedDepth[1] = false;
4344
copied2D = false;
45+
if (cameraIsCapturing3DFramebuffer > 0)
46+
--cameraIsCapturing3DFramebuffer;
4447

4548
ranMotionAnalysis[0] = false;
4649
ranMotionAnalysis[1] = false;
@@ -209,6 +212,12 @@ class RND_Renderer {
209212
bool IsInitialized() {
210213
return m_isInitialized;
211214
}
215+
bool IsGameCapturing3DFrameBuffer() const {
216+
return m_cameraIsCapturing3DFrameBuffer > 0;
217+
}
218+
void SignalGameCapturing3DFrameBuffer() {
219+
m_cameraIsCapturing3DFrameBuffer = 1;
220+
}
212221

213222
protected:
214223
XrSession m_session;
@@ -218,6 +227,7 @@ class RND_Renderer {
218227

219228
std::atomic_bool m_isInitialized = false;
220229
std::atomic_bool m_presented2DLastFrame = false;
230+
std::atomic_uint8_t m_cameraIsCapturing3DFrameBuffer = 0;
221231

222232
// Full-frame timing derived from OpenXR timestamps (XrTime is in nanoseconds)
223233
XrTime m_lastPredictedDisplayTime = 0;

0 commit comments

Comments
 (0)