diff options
| author | 2015-02-23 18:24:35 -0500 | |
|---|---|---|
| committer | 2015-02-26 21:17:14 -0500 | |
| commit | c564c21668912b803947adddc166ff1315b218e4 (patch) | |
| tree | df5cf2de4044864e0b6698427d68daacba71937e /src/core/hw/gpu.cpp | |
| parent | Merge pull request #612 from yuriks/fix-A4 (diff) | |
| download | yuzu-c564c21668912b803947adddc166ff1315b218e4.tar.gz yuzu-c564c21668912b803947adddc166ff1315b218e4.tar.xz yuzu-c564c21668912b803947adddc166ff1315b218e4.zip | |
GPU: Implemented bits 3 and 1 from the display transfer flags.
Bit 3 is used to specify a raw copy, where no processing is done to the data, seems to behave exactly as a DMA.
Bit 1 is used to specify whether to convert from a tiled format to a linear format or viceversa.
Diffstat (limited to 'src/core/hw/gpu.cpp')
| -rw-r--r-- | src/core/hw/gpu.cpp | 82 |
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 | |||
| 25 | namespace GPU { | 25 | namespace GPU { |
| 26 | 26 | ||
| 27 | Regs g_regs; | 27 | Regs 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 | } |