summaryrefslogtreecommitdiff
path: root/src/core/hw/gpu.cpp
diff options
context:
space:
mode:
authorGravatar Yuri Kunde Schlesner2015-01-14 05:03:14 -0200
committerGravatar Yuri Kunde Schlesner2015-01-14 05:20:14 -0200
commita09f71521e6a20de86e9b31451c82c3df5c301a0 (patch)
treed957fb880483b1f99d3f238d5778d1f13f58359d /src/core/hw/gpu.cpp
parentGSP: Fix appending of interrupts to the shared memory buffer (diff)
downloadyuzu-a09f71521e6a20de86e9b31451c82c3df5c301a0.tar.gz
yuzu-a09f71521e6a20de86e9b31451c82c3df5c301a0.tar.xz
yuzu-a09f71521e6a20de86e9b31451c82c3df5c301a0.zip
GPU: Fix buffer overrun in Display Transfers
Display transfers with the horizontal downscaling flag were calculating the wrong output size, causing them to write double the amount of data intended. It is likely that this was perceived as correct due to a separate bug in calculating source indices which caused the image to be padded unless the previous bug was present. This fixes both issues, correcting flickering issues in 3dscraft, blargSnes and more (caused by the transfer overwriting the back buffer which followed) as well as potentially fixing other crashes.
Diffstat (limited to 'src/core/hw/gpu.cpp')
-rw-r--r--src/core/hw/gpu.cpp21
1 files changed, 12 insertions, 9 deletions
diff --git a/src/core/hw/gpu.cpp b/src/core/hw/gpu.cpp
index 256e11c37..58eec3005 100644
--- a/src/core/hw/gpu.cpp
+++ b/src/core/hw/gpu.cpp
@@ -100,22 +100,25 @@ inline void Write(u32 addr, const T data) {
100 u8* source_pointer = Memory::GetPointer(Memory::PhysicalToVirtualAddress(config.GetPhysicalInputAddress())); 100 u8* source_pointer = Memory::GetPointer(Memory::PhysicalToVirtualAddress(config.GetPhysicalInputAddress()));
101 u8* dest_pointer = Memory::GetPointer(Memory::PhysicalToVirtualAddress(config.GetPhysicalOutputAddress())); 101 u8* dest_pointer = Memory::GetPointer(Memory::PhysicalToVirtualAddress(config.GetPhysicalOutputAddress()));
102 102
103 // Cheap emulation of horizontal scaling: Just skip each second pixel of the
104 // input framebuffer. We keep track of this in the pixel_skip variable.
105 unsigned pixel_skip = (config.scale_horizontally != 0) ? 2 : 1;
106
107 u32 output_width = config.output_width / pixel_skip;
108
103 for (u32 y = 0; y < config.output_height; ++y) { 109 for (u32 y = 0; y < config.output_height; ++y) {
104 // TODO: Why does the register seem to hold twice the framebuffer width? 110 // TODO: Why does the register seem to hold twice the framebuffer width?
105 for (u32 x = 0; x < config.output_width; ++x) { 111
112 for (u32 x = 0; x < output_width; ++x) {
106 struct { 113 struct {
107 int r, g, b, a; 114 int r, g, b, a;
108 } source_color = { 0, 0, 0, 0 }; 115 } source_color = { 0, 0, 0, 0 };
109 116
110 // Cheap emulation of horizontal scaling: Just skip each second pixel of the
111 // input framebuffer. We keep track of this in the pixel_skip variable.
112 unsigned pixel_skip = (config.scale_horizontally != 0) ? 2 : 1;
113
114 switch (config.input_format) { 117 switch (config.input_format) {
115 case Regs::PixelFormat::RGBA8: 118 case Regs::PixelFormat::RGBA8:
116 { 119 {
117 // TODO: Most likely got the component order messed up. 120 // TODO: Most likely got the component order messed up.
118 u8* srcptr = source_pointer + x * 4 * pixel_skip + y * config.input_width * 4 * pixel_skip; 121 u8* srcptr = source_pointer + (x * pixel_skip + y * config.input_width) * 4;
119 source_color.r = srcptr[0]; // blue 122 source_color.r = srcptr[0]; // blue
120 source_color.g = srcptr[1]; // green 123 source_color.g = srcptr[1]; // green
121 source_color.b = srcptr[2]; // red 124 source_color.b = srcptr[2]; // red
@@ -143,7 +146,7 @@ inline void Write(u32 addr, const T data) {
143 case Regs::PixelFormat::RGB8: 146 case Regs::PixelFormat::RGB8:
144 { 147 {
145 // TODO: Most likely got the component order messed up. 148 // TODO: Most likely got the component order messed up.
146 u8* dstptr = dest_pointer + x * 3 + y * config.output_width * 3; 149 u8* dstptr = dest_pointer + (x + y * output_width) * 3;
147 dstptr[0] = source_color.r; // blue 150 dstptr[0] = source_color.r; // blue
148 dstptr[1] = source_color.g; // green 151 dstptr[1] = source_color.g; // green
149 dstptr[2] = source_color.b; // red 152 dstptr[2] = source_color.b; // red
@@ -158,9 +161,9 @@ inline void Write(u32 addr, const T data) {
158 } 161 }
159 162
160 LOG_TRACE(HW_GPU, "DisplayTriggerTransfer: 0x%08x bytes from 0x%08x(%ux%u)-> 0x%08x(%ux%u), dst format %x", 163 LOG_TRACE(HW_GPU, "DisplayTriggerTransfer: 0x%08x bytes from 0x%08x(%ux%u)-> 0x%08x(%ux%u), dst format %x",
161 config.output_height * config.output_width * 4, 164 config.output_height * output_width * 4,
162 config.GetPhysicalInputAddress(), (u32)config.input_width, (u32)config.input_height, 165 config.GetPhysicalInputAddress(), (u32)config.input_width, (u32)config.input_height,
163 config.GetPhysicalOutputAddress(), (u32)config.output_width, (u32)config.output_height, 166 config.GetPhysicalOutputAddress(), (u32)output_width, (u32)config.output_height,
164 config.output_format.Value()); 167 config.output_format.Value());
165 168
166 GSP_GPU::SignalInterrupt(GSP_GPU::InterruptId::PPF); 169 GSP_GPU::SignalInterrupt(GSP_GPU::InterruptId::PPF);