summaryrefslogtreecommitdiff
path: root/src/core/hw/gpu.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/hw/gpu.cpp')
-rw-r--r--src/core/hw/gpu.cpp82
1 files changed, 61 insertions, 21 deletions
diff --git a/src/core/hw/gpu.cpp b/src/core/hw/gpu.cpp
index e6022d69f..2f1a69d90 100644
--- a/src/core/hw/gpu.cpp
+++ b/src/core/hw/gpu.cpp
@@ -18,10 +18,10 @@
18#include "core/hw/gpu.h" 18#include "core/hw/gpu.h"
19 19
20#include "video_core/command_processor.h" 20#include "video_core/command_processor.h"
21#include "video_core/utils.h"
21#include "video_core/video_core.h" 22#include "video_core/video_core.h"
22#include <video_core/color.h> 23#include <video_core/color.h>
23 24
24
25namespace GPU { 25namespace GPU {
26 26
27Regs g_regs; 27Regs g_regs;
@@ -116,24 +116,64 @@ inline void Write(u32 addr, const T data) {
116 u8* source_pointer = Memory::GetPointer(Memory::PhysicalToVirtualAddress(config.GetPhysicalInputAddress())); 116 u8* source_pointer = Memory::GetPointer(Memory::PhysicalToVirtualAddress(config.GetPhysicalInputAddress()));
117 u8* dest_pointer = Memory::GetPointer(Memory::PhysicalToVirtualAddress(config.GetPhysicalOutputAddress())); 117 u8* dest_pointer = Memory::GetPointer(Memory::PhysicalToVirtualAddress(config.GetPhysicalOutputAddress()));
118 118
119 // Cheap emulation of horizontal scaling: Just skip each second pixel of the 119 unsigned horizontal_scale = (config.scale_horizontally != 0) ? 2 : 1;
120 // input framebuffer. We keep track of this in the pixel_skip variable. 120 unsigned vertical_scale = (config.scale_vertically != 0) ? 2 : 1;
121 unsigned pixel_skip = (config.scale_horizontally != 0) ? 2 : 1; 121
122 122 u32 output_width = config.output_width / horizontal_scale;
123 u32 output_width = config.output_width / pixel_skip; 123 u32 output_height = config.output_height / vertical_scale;
124 124
125 for (u32 y = 0; y < config.output_height; ++y) { 125 if (config.raw_copy) {
126 // TODO: Why does the register seem to hold twice the framebuffer width? 126 // Raw copies do not perform color conversion nor tiled->linear / linear->tiled conversions
127 // TODO(Subv): Verify if raw copies perform scaling
128 memcpy(dest_pointer, source_pointer, config.output_width * config.output_height *
129 GPU::Regs::BytesPerPixel(config.output_format));
130
131 LOG_TRACE(HW_GPU, "DisplayTriggerTransfer: 0x%08x bytes from 0x%08x(%ux%u)-> 0x%08x(%ux%u), flags 0x%08X, Raw copy",
132 config.output_height * output_width * GPU::Regs::BytesPerPixel(config.output_format),
133 config.GetPhysicalInputAddress(), config.input_width.Value(), config.input_height.Value(),
134 config.GetPhysicalOutputAddress(), config.output_width.Value(), config.output_height.Value(),
135 config.output_format.Value(), config.flags);
136
137 GSP_GPU::SignalInterrupt(GSP_GPU::InterruptId::PPF);
138 break;
139 }
127 140
141 // TODO(Subv): Blend the pixels when horizontal / vertical scaling is enabled,
142 // right now we're just skipping the extra pixels.
143 for (u32 y = 0; y < output_height; ++y) {
128 for (u32 x = 0; x < output_width; ++x) { 144 for (u32 x = 0; x < output_width; ++x) {
129 struct { 145 struct {
130 int r, g, b, a; 146 int r, g, b, a;
131 } source_color = { 0, 0, 0, 0 }; 147 } source_color = { 0, 0, 0, 0 };
132 148
149 u32 scaled_x = x * horizontal_scale;
150 u32 scaled_y = y * vertical_scale;
151
152 u32 dst_bytes_per_pixel = GPU::Regs::BytesPerPixel(config.output_format);
153 u32 src_bytes_per_pixel = GPU::Regs::BytesPerPixel(config.input_format);
154 u32 src_offset;
155 u32 dst_offset;
156
157 if (config.output_tiled) {
158 // Interpret the input as linear and the output as tiled
159 u32 coarse_y = y & ~7;
160 u32 stride = output_width * dst_bytes_per_pixel;
161
162 src_offset = (scaled_x + scaled_y * config.input_width) * src_bytes_per_pixel;
163 dst_offset = VideoCore::GetMortonOffset(x, y, dst_bytes_per_pixel) + coarse_y * stride;
164 } else {
165 // Interpret the input as tiled and the output as linear
166 u32 coarse_y = scaled_y & ~7;
167 u32 stride = config.input_width * src_bytes_per_pixel;
168
169 src_offset = VideoCore::GetMortonOffset(scaled_x, scaled_y, src_bytes_per_pixel) + coarse_y * stride;
170 dst_offset = (x + y * output_width) * dst_bytes_per_pixel;
171 }
172
133 switch (config.input_format) { 173 switch (config.input_format) {
134 case Regs::PixelFormat::RGBA8: 174 case Regs::PixelFormat::RGBA8:
135 { 175 {
136 u8* srcptr = source_pointer + (x * pixel_skip + y * config.input_width) * 4; 176 u8* srcptr = source_pointer + src_offset;
137 source_color.r = srcptr[3]; // red 177 source_color.r = srcptr[3]; // red
138 source_color.g = srcptr[2]; // green 178 source_color.g = srcptr[2]; // green
139 source_color.b = srcptr[1]; // blue 179 source_color.b = srcptr[1]; // blue
@@ -143,7 +183,7 @@ inline void Write(u32 addr, const T data) {
143 183
144 case Regs::PixelFormat::RGB5A1: 184 case Regs::PixelFormat::RGB5A1:
145 { 185 {
146 u16 srcval = *(u16*)(source_pointer + x * 4 * pixel_skip + y * config.input_width * 4 * pixel_skip); 186 u16 srcval = *(u16*)(source_pointer + src_offset);
147 source_color.r = Color::Convert5To8((srcval >> 11) & 0x1F); // red 187 source_color.r = Color::Convert5To8((srcval >> 11) & 0x1F); // red
148 source_color.g = Color::Convert5To8((srcval >> 6) & 0x1F); // green 188 source_color.g = Color::Convert5To8((srcval >> 6) & 0x1F); // green
149 source_color.b = Color::Convert5To8((srcval >> 1) & 0x1F); // blue 189 source_color.b = Color::Convert5To8((srcval >> 1) & 0x1F); // blue
@@ -153,7 +193,7 @@ inline void Write(u32 addr, const T data) {
153 193
154 case Regs::PixelFormat::RGBA4: 194 case Regs::PixelFormat::RGBA4:
155 { 195 {
156 u16 srcval = *(u16*)(source_pointer + x * 4 * pixel_skip + y * config.input_width * 4 * pixel_skip); 196 u16 srcval = *(u16*)(source_pointer + src_offset);
157 source_color.r = Color::Convert4To8((srcval >> 12) & 0xF); // red 197 source_color.r = Color::Convert4To8((srcval >> 12) & 0xF); // red
158 source_color.g = Color::Convert4To8((srcval >> 8) & 0xF); // green 198 source_color.g = Color::Convert4To8((srcval >> 8) & 0xF); // green
159 source_color.b = Color::Convert4To8((srcval >> 4) & 0xF); // blue 199 source_color.b = Color::Convert4To8((srcval >> 4) & 0xF); // blue
@@ -169,7 +209,7 @@ inline void Write(u32 addr, const T data) {
169 switch (config.output_format) { 209 switch (config.output_format) {
170 case Regs::PixelFormat::RGBA8: 210 case Regs::PixelFormat::RGBA8:
171 { 211 {
172 u8* dstptr = dest_pointer + (x * pixel_skip + y * config.output_width) * 4; 212 u8* dstptr = dest_pointer + dst_offset;
173 dstptr[3] = source_color.r; 213 dstptr[3] = source_color.r;
174 dstptr[2] = source_color.g; 214 dstptr[2] = source_color.g;
175 dstptr[1] = source_color.b; 215 dstptr[1] = source_color.b;
@@ -179,7 +219,7 @@ inline void Write(u32 addr, const T data) {
179 219
180 case Regs::PixelFormat::RGB8: 220 case Regs::PixelFormat::RGB8:
181 { 221 {
182 u8* dstptr = dest_pointer + (x + y * output_width) * 3; 222 u8* dstptr = dest_pointer + dst_offset;
183 dstptr[2] = source_color.r; // red 223 dstptr[2] = source_color.r; // red
184 dstptr[1] = source_color.g; // green 224 dstptr[1] = source_color.g; // green
185 dstptr[0] = source_color.b; // blue 225 dstptr[0] = source_color.b; // blue
@@ -188,7 +228,7 @@ inline void Write(u32 addr, const T data) {
188 228
189 case Regs::PixelFormat::RGB5A1: 229 case Regs::PixelFormat::RGB5A1:
190 { 230 {
191 u16* dstptr = (u16*)(dest_pointer + x * 2 + y * config.output_width * 2); 231 u16* dstptr = (u16*)(dest_pointer + dst_offset);
192 *dstptr = ((source_color.r >> 3) << 11) | ((source_color.g >> 3) << 6) 232 *dstptr = ((source_color.r >> 3) << 11) | ((source_color.g >> 3) << 6)
193 | ((source_color.b >> 3) << 1) | ( source_color.a >> 7); 233 | ((source_color.b >> 3) << 1) | ( source_color.a >> 7);
194 break; 234 break;
@@ -196,7 +236,7 @@ inline void Write(u32 addr, const T data) {
196 236
197 case Regs::PixelFormat::RGBA4: 237 case Regs::PixelFormat::RGBA4:
198 { 238 {
199 u16* dstptr = (u16*)(dest_pointer + x * 2 + y * config.output_width * 2); 239 u16* dstptr = (u16*)(dest_pointer + dst_offset);
200 *dstptr = ((source_color.r >> 4) << 12) | ((source_color.g >> 4) << 8) 240 *dstptr = ((source_color.r >> 4) << 12) | ((source_color.g >> 4) << 8)
201 | ((source_color.b >> 4) << 4) | ( source_color.a >> 4); 241 | ((source_color.b >> 4) << 4) | ( source_color.a >> 4);
202 break; 242 break;
@@ -209,11 +249,11 @@ inline void Write(u32 addr, const T data) {
209 } 249 }
210 } 250 }
211 251
212 LOG_TRACE(HW_GPU, "DisplayTriggerTransfer: 0x%08x bytes from 0x%08x(%ux%u)-> 0x%08x(%ux%u), dst format %x", 252 LOG_TRACE(HW_GPU, "DisplayTriggerTransfer: 0x%08x bytes from 0x%08x(%ux%u)-> 0x%08x(%ux%u), dst format %x, flags 0x%08X",
213 config.output_height * output_width * 4, 253 config.output_height * output_width * GPU::Regs::BytesPerPixel(config.output_format),
214 config.GetPhysicalInputAddress(), (u32)config.input_width, (u32)config.input_height, 254 config.GetPhysicalInputAddress(), config.input_width.Value(), config.input_height.Value(),
215 config.GetPhysicalOutputAddress(), (u32)output_width, (u32)config.output_height, 255 config.GetPhysicalOutputAddress(), output_width, output_height,
216 config.output_format.Value()); 256 config.output_format.Value(), config.flags);
217 257
218 GSP_GPU::SignalInterrupt(GSP_GPU::InterruptId::PPF); 258 GSP_GPU::SignalInterrupt(GSP_GPU::InterruptId::PPF);
219 } 259 }