diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/citra_qt/debugger/graphics_cmdlists.cpp | 2 | ||||
| -rw-r--r-- | src/citra_qt/debugger/graphics_framebuffer.cpp | 88 | ||||
| -rw-r--r-- | src/citra_qt/debugger/graphics_framebuffer.h | 2 | ||||
| -rw-r--r-- | src/core/hw/gpu.cpp | 75 | ||||
| -rw-r--r-- | src/video_core/CMakeLists.txt | 1 | ||||
| -rw-r--r-- | src/video_core/color.h | 121 | ||||
| -rw-r--r-- | src/video_core/debug_utils/debug_utils.cpp | 36 | ||||
| -rw-r--r-- | src/video_core/pica.h | 6 | ||||
| -rw-r--r-- | src/video_core/rasterizer.cpp | 76 |
9 files changed, 213 insertions, 194 deletions
diff --git a/src/citra_qt/debugger/graphics_cmdlists.cpp b/src/citra_qt/debugger/graphics_cmdlists.cpp index bd420f24a..9bcd25821 100644 --- a/src/citra_qt/debugger/graphics_cmdlists.cpp +++ b/src/citra_qt/debugger/graphics_cmdlists.cpp | |||
| @@ -66,7 +66,7 @@ TextureInfoDockWidget::TextureInfoDockWidget(const Pica::DebugUtils::TextureInfo | |||
| 66 | QComboBox* format_choice = new QComboBox; | 66 | QComboBox* format_choice = new QComboBox; |
| 67 | format_choice->addItem(tr("RGBA8")); | 67 | format_choice->addItem(tr("RGBA8")); |
| 68 | format_choice->addItem(tr("RGB8")); | 68 | format_choice->addItem(tr("RGB8")); |
| 69 | format_choice->addItem(tr("RGBA5551")); | 69 | format_choice->addItem(tr("RGB5A1")); |
| 70 | format_choice->addItem(tr("RGB565")); | 70 | format_choice->addItem(tr("RGB565")); |
| 71 | format_choice->addItem(tr("RGBA4")); | 71 | format_choice->addItem(tr("RGBA4")); |
| 72 | format_choice->addItem(tr("IA8")); | 72 | format_choice->addItem(tr("IA8")); |
diff --git a/src/citra_qt/debugger/graphics_framebuffer.cpp b/src/citra_qt/debugger/graphics_framebuffer.cpp index 574f19cc1..5bd6c0235 100644 --- a/src/citra_qt/debugger/graphics_framebuffer.cpp +++ b/src/citra_qt/debugger/graphics_framebuffer.cpp | |||
| @@ -46,7 +46,7 @@ GraphicsFramebufferWidget::GraphicsFramebufferWidget(std::shared_ptr<Pica::Debug | |||
| 46 | framebuffer_format_control = new QComboBox; | 46 | framebuffer_format_control = new QComboBox; |
| 47 | framebuffer_format_control->addItem(tr("RGBA8")); | 47 | framebuffer_format_control->addItem(tr("RGBA8")); |
| 48 | framebuffer_format_control->addItem(tr("RGB8")); | 48 | framebuffer_format_control->addItem(tr("RGB8")); |
| 49 | framebuffer_format_control->addItem(tr("RGBA5551")); | 49 | framebuffer_format_control->addItem(tr("RGB5A1")); |
| 50 | framebuffer_format_control->addItem(tr("RGB565")); | 50 | framebuffer_format_control->addItem(tr("RGB565")); |
| 51 | framebuffer_format_control->addItem(tr("RGBA4")); | 51 | framebuffer_format_control->addItem(tr("RGBA4")); |
| 52 | 52 | ||
| @@ -199,66 +199,40 @@ void GraphicsFramebufferWidget::OnUpdate() | |||
| 199 | // TODO: Unify this decoding code with the texture decoder | 199 | // TODO: Unify this decoding code with the texture decoder |
| 200 | u32 bytes_per_pixel = GPU::Regs::BytesPerPixel(GPU::Regs::PixelFormat(framebuffer_format)); | 200 | u32 bytes_per_pixel = GPU::Regs::BytesPerPixel(GPU::Regs::PixelFormat(framebuffer_format)); |
| 201 | 201 | ||
| 202 | switch (framebuffer_format) { | 202 | QImage decoded_image(framebuffer_width, framebuffer_height, QImage::Format_ARGB32); |
| 203 | case Format::RGBA8: | 203 | u8* color_buffer = Memory::GetPointer(Pica::PAddrToVAddr(framebuffer_address)); |
| 204 | { | 204 | for (unsigned int y = 0; y < framebuffer_height; ++y) { |
| 205 | QImage decoded_image(framebuffer_width, framebuffer_height, QImage::Format_ARGB32); | 205 | for (unsigned int x = 0; x < framebuffer_width; ++x) { |
| 206 | u8* color_buffer = Memory::GetPointer(Pica::PAddrToVAddr(framebuffer_address)); | 206 | const u32 coarse_y = y & ~7; |
| 207 | for (unsigned int y = 0; y < framebuffer_height; ++y) { | 207 | u32 offset = VideoCore::GetMortonOffset(x, y, bytes_per_pixel) + coarse_y * framebuffer_width * bytes_per_pixel; |
| 208 | for (unsigned int x = 0; x < framebuffer_width; ++x) { | 208 | const u8* pixel = color_buffer + offset; |
| 209 | const u32 coarse_y = y & ~7; | 209 | Math::Vec4<u8> color = { 0, 0, 0, 0 }; |
| 210 | u32 offset = VideoCore::GetMortonOffset(x, y, bytes_per_pixel) + coarse_y * framebuffer_width * bytes_per_pixel; | 210 | |
| 211 | u8* value = color_buffer + offset; | 211 | switch (framebuffer_format) { |
| 212 | 212 | case Format::RGBA8: | |
| 213 | decoded_image.setPixel(x, y, qRgba(value[3], value[2], value[1], 255/*value >> 24*/)); | 213 | color = Color::DecodeRGBA8(pixel); |
| 214 | break; | ||
| 215 | case Format::RGB8: | ||
| 216 | color = Color::DecodeRGB8(pixel); | ||
| 217 | break; | ||
| 218 | case Format::RGB5A1: | ||
| 219 | color = Color::DecodeRGB5A1(pixel); | ||
| 220 | break; | ||
| 221 | case Format::RGB565: | ||
| 222 | color = Color::DecodeRGB565(pixel); | ||
| 223 | break; | ||
| 224 | case Format::RGBA4: | ||
| 225 | color = Color::DecodeRGBA4(pixel); | ||
| 226 | break; | ||
| 227 | default: | ||
| 228 | qDebug() << "Unknown fb color format " << static_cast<int>(framebuffer_format); | ||
| 229 | break; | ||
| 214 | } | 230 | } |
| 215 | } | ||
| 216 | pixmap = QPixmap::fromImage(decoded_image); | ||
| 217 | break; | ||
| 218 | } | ||
| 219 | 231 | ||
| 220 | case Format::RGB8: | 232 | decoded_image.setPixel(x, y, qRgba(color.r(), color.g(), color.b(), 255)); |
| 221 | { | ||
| 222 | QImage decoded_image(framebuffer_width, framebuffer_height, QImage::Format_ARGB32); | ||
| 223 | u8* color_buffer = Memory::GetPointer(Pica::PAddrToVAddr(framebuffer_address)); | ||
| 224 | for (unsigned int y = 0; y < framebuffer_height; ++y) { | ||
| 225 | for (unsigned int x = 0; x < framebuffer_width; ++x) { | ||
| 226 | const u32 coarse_y = y & ~7; | ||
| 227 | u32 offset = VideoCore::GetMortonOffset(x, y, bytes_per_pixel) + coarse_y * framebuffer_width * bytes_per_pixel; | ||
| 228 | u8* pixel_pointer = color_buffer + offset; | ||
| 229 | |||
| 230 | decoded_image.setPixel(x, y, qRgba(pixel_pointer[0], pixel_pointer[1], pixel_pointer[2], 255/*value >> 24*/)); | ||
| 231 | } | ||
| 232 | } | 233 | } |
| 233 | pixmap = QPixmap::fromImage(decoded_image); | ||
| 234 | break; | ||
| 235 | } | ||
| 236 | |||
| 237 | case Format::RGBA5551: | ||
| 238 | { | ||
| 239 | QImage decoded_image(framebuffer_width, framebuffer_height, QImage::Format_ARGB32); | ||
| 240 | u8* color_buffer = Memory::GetPointer(Pica::PAddrToVAddr(framebuffer_address)); | ||
| 241 | for (unsigned int y = 0; y < framebuffer_height; ++y) { | ||
| 242 | for (unsigned int x = 0; x < framebuffer_width; ++x) { | ||
| 243 | const u32 coarse_y = y & ~7; | ||
| 244 | u32 offset = VideoCore::GetMortonOffset(x, y, bytes_per_pixel) + coarse_y * framebuffer_width * bytes_per_pixel; | ||
| 245 | u16 value = *(u16*)(color_buffer + offset); | ||
| 246 | u8 r = Color::Convert5To8((value >> 11) & 0x1F); | ||
| 247 | u8 g = Color::Convert5To8((value >> 6) & 0x1F); | ||
| 248 | u8 b = Color::Convert5To8((value >> 1) & 0x1F); | ||
| 249 | u8 a = Color::Convert1To8(value & 1); | ||
| 250 | |||
| 251 | decoded_image.setPixel(x, y, qRgba(r, g, b, 255/*a*/)); | ||
| 252 | } | ||
| 253 | } | ||
| 254 | pixmap = QPixmap::fromImage(decoded_image); | ||
| 255 | break; | ||
| 256 | } | ||
| 257 | |||
| 258 | default: | ||
| 259 | qDebug() << "Unknown fb color format " << static_cast<int>(framebuffer_format); | ||
| 260 | break; | ||
| 261 | } | 234 | } |
| 235 | pixmap = QPixmap::fromImage(decoded_image); | ||
| 262 | 236 | ||
| 263 | framebuffer_address_control->SetValue(framebuffer_address); | 237 | framebuffer_address_control->SetValue(framebuffer_address); |
| 264 | framebuffer_width_control->setValue(framebuffer_width); | 238 | framebuffer_width_control->setValue(framebuffer_width); |
diff --git a/src/citra_qt/debugger/graphics_framebuffer.h b/src/citra_qt/debugger/graphics_framebuffer.h index c6e293bc9..15ebd1f7d 100644 --- a/src/citra_qt/debugger/graphics_framebuffer.h +++ b/src/citra_qt/debugger/graphics_framebuffer.h | |||
| @@ -29,7 +29,7 @@ class GraphicsFramebufferWidget : public BreakPointObserverDock { | |||
| 29 | enum class Format { | 29 | enum class Format { |
| 30 | RGBA8 = 0, | 30 | RGBA8 = 0, |
| 31 | RGB8 = 1, | 31 | RGB8 = 1, |
| 32 | RGBA5551 = 2, | 32 | RGB5A1 = 2, |
| 33 | RGB565 = 3, | 33 | RGB565 = 3, |
| 34 | RGBA4 = 4, | 34 | RGBA4 = 4, |
| 35 | }; | 35 | }; |
diff --git a/src/core/hw/gpu.cpp b/src/core/hw/gpu.cpp index 2f1a69d90..424ce2ca7 100644 --- a/src/core/hw/gpu.cpp +++ b/src/core/hw/gpu.cpp | |||
| @@ -113,8 +113,8 @@ inline void Write(u32 addr, const T data) { | |||
| 113 | { | 113 | { |
| 114 | const auto& config = g_regs.display_transfer_config; | 114 | const auto& config = g_regs.display_transfer_config; |
| 115 | if (config.trigger & 1) { | 115 | if (config.trigger & 1) { |
| 116 | u8* source_pointer = Memory::GetPointer(Memory::PhysicalToVirtualAddress(config.GetPhysicalInputAddress())); | 116 | u8* src_pointer = Memory::GetPointer(Memory::PhysicalToVirtualAddress(config.GetPhysicalInputAddress())); |
| 117 | u8* dest_pointer = Memory::GetPointer(Memory::PhysicalToVirtualAddress(config.GetPhysicalOutputAddress())); | 117 | u8* dst_pointer = Memory::GetPointer(Memory::PhysicalToVirtualAddress(config.GetPhysicalOutputAddress())); |
| 118 | 118 | ||
| 119 | unsigned horizontal_scale = (config.scale_horizontally != 0) ? 2 : 1; | 119 | unsigned horizontal_scale = (config.scale_horizontally != 0) ? 2 : 1; |
| 120 | unsigned vertical_scale = (config.scale_vertically != 0) ? 2 : 1; | 120 | unsigned vertical_scale = (config.scale_vertically != 0) ? 2 : 1; |
| @@ -125,7 +125,7 @@ inline void Write(u32 addr, const T data) { | |||
| 125 | if (config.raw_copy) { | 125 | if (config.raw_copy) { |
| 126 | // Raw copies do not perform color conversion nor tiled->linear / linear->tiled conversions | 126 | // Raw copies do not perform color conversion nor tiled->linear / linear->tiled conversions |
| 127 | // TODO(Subv): Verify if raw copies perform scaling | 127 | // TODO(Subv): Verify if raw copies perform scaling |
| 128 | memcpy(dest_pointer, source_pointer, config.output_width * config.output_height * | 128 | memcpy(dst_pointer, src_pointer, config.output_width * config.output_height * |
| 129 | GPU::Regs::BytesPerPixel(config.output_format)); | 129 | GPU::Regs::BytesPerPixel(config.output_format)); |
| 130 | 130 | ||
| 131 | LOG_TRACE(HW_GPU, "DisplayTriggerTransfer: 0x%08x bytes from 0x%08x(%ux%u)-> 0x%08x(%ux%u), flags 0x%08X, Raw copy", | 131 | LOG_TRACE(HW_GPU, "DisplayTriggerTransfer: 0x%08x bytes from 0x%08x(%ux%u)-> 0x%08x(%ux%u), flags 0x%08X, Raw copy", |
| @@ -142,9 +142,7 @@ inline void Write(u32 addr, const T data) { | |||
| 142 | // right now we're just skipping the extra pixels. | 142 | // right now we're just skipping the extra pixels. |
| 143 | for (u32 y = 0; y < output_height; ++y) { | 143 | for (u32 y = 0; y < output_height; ++y) { |
| 144 | for (u32 x = 0; x < output_width; ++x) { | 144 | for (u32 x = 0; x < output_width; ++x) { |
| 145 | struct { | 145 | Math::Vec4<u8> src_color = { 0, 0, 0, 0 }; |
| 146 | int r, g, b, a; | ||
| 147 | } source_color = { 0, 0, 0, 0 }; | ||
| 148 | 146 | ||
| 149 | u32 scaled_x = x * horizontal_scale; | 147 | u32 scaled_x = x * horizontal_scale; |
| 150 | u32 scaled_y = y * vertical_scale; | 148 | u32 scaled_y = y * vertical_scale; |
| @@ -170,77 +168,54 @@ inline void Write(u32 addr, const T data) { | |||
| 170 | dst_offset = (x + y * output_width) * dst_bytes_per_pixel; | 168 | dst_offset = (x + y * output_width) * dst_bytes_per_pixel; |
| 171 | } | 169 | } |
| 172 | 170 | ||
| 171 | const u8* src_pixel = src_pointer + src_offset; | ||
| 173 | switch (config.input_format) { | 172 | switch (config.input_format) { |
| 174 | case Regs::PixelFormat::RGBA8: | 173 | case Regs::PixelFormat::RGBA8: |
| 175 | { | 174 | src_color = Color::DecodeRGBA8(src_pixel); |
| 176 | u8* srcptr = source_pointer + src_offset; | 175 | break; |
| 177 | source_color.r = srcptr[3]; // red | 176 | |
| 178 | source_color.g = srcptr[2]; // green | 177 | case Regs::PixelFormat::RGB8: |
| 179 | source_color.b = srcptr[1]; // blue | 178 | src_color = Color::DecodeRGB8(src_pixel); |
| 180 | source_color.a = srcptr[0]; // alpha | 179 | break; |
| 180 | |||
| 181 | case Regs::PixelFormat::RGB565: | ||
| 182 | src_color = Color::DecodeRGB565(src_pixel); | ||
| 181 | break; | 183 | break; |
| 182 | } | ||
| 183 | 184 | ||
| 184 | case Regs::PixelFormat::RGB5A1: | 185 | case Regs::PixelFormat::RGB5A1: |
| 185 | { | 186 | src_color = Color::DecodeRGB5A1(src_pixel); |
| 186 | u16 srcval = *(u16*)(source_pointer + src_offset); | ||
| 187 | source_color.r = Color::Convert5To8((srcval >> 11) & 0x1F); // red | ||
| 188 | source_color.g = Color::Convert5To8((srcval >> 6) & 0x1F); // green | ||
| 189 | source_color.b = Color::Convert5To8((srcval >> 1) & 0x1F); // blue | ||
| 190 | source_color.a = Color::Convert1To8(srcval & 0x1); // alpha | ||
| 191 | break; | 187 | break; |
| 192 | } | ||
| 193 | 188 | ||
| 194 | case Regs::PixelFormat::RGBA4: | 189 | case Regs::PixelFormat::RGBA4: |
| 195 | { | 190 | src_color = Color::DecodeRGBA4(src_pixel); |
| 196 | u16 srcval = *(u16*)(source_pointer + src_offset); | ||
| 197 | source_color.r = Color::Convert4To8((srcval >> 12) & 0xF); // red | ||
| 198 | source_color.g = Color::Convert4To8((srcval >> 8) & 0xF); // green | ||
| 199 | source_color.b = Color::Convert4To8((srcval >> 4) & 0xF); // blue | ||
| 200 | source_color.a = Color::Convert4To8( srcval & 0xF); // alpha | ||
| 201 | break; | 191 | break; |
| 202 | } | ||
| 203 | 192 | ||
| 204 | default: | 193 | default: |
| 205 | LOG_ERROR(HW_GPU, "Unknown source framebuffer format %x", config.input_format.Value()); | 194 | LOG_ERROR(HW_GPU, "Unknown source framebuffer format %x", config.input_format.Value()); |
| 206 | break; | 195 | break; |
| 207 | } | 196 | } |
| 208 | 197 | ||
| 198 | u8* dst_pixel = dst_pointer + dst_offset; | ||
| 209 | switch (config.output_format) { | 199 | switch (config.output_format) { |
| 210 | case Regs::PixelFormat::RGBA8: | 200 | case Regs::PixelFormat::RGBA8: |
| 211 | { | 201 | Color::EncodeRGBA8(src_color, dst_pixel); |
| 212 | u8* dstptr = dest_pointer + dst_offset; | ||
| 213 | dstptr[3] = source_color.r; | ||
| 214 | dstptr[2] = source_color.g; | ||
| 215 | dstptr[1] = source_color.b; | ||
| 216 | dstptr[0] = source_color.a; | ||
| 217 | break; | 202 | break; |
| 218 | } | ||
| 219 | 203 | ||
| 220 | case Regs::PixelFormat::RGB8: | 204 | case Regs::PixelFormat::RGB8: |
| 221 | { | 205 | Color::EncodeRGB8(src_color, dst_pixel); |
| 222 | u8* dstptr = dest_pointer + dst_offset; | 206 | break; |
| 223 | dstptr[2] = source_color.r; // red | 207 | |
| 224 | dstptr[1] = source_color.g; // green | 208 | case Regs::PixelFormat::RGB565: |
| 225 | dstptr[0] = source_color.b; // blue | 209 | Color::EncodeRGB565(src_color, dst_pixel); |
| 226 | break; | 210 | break; |
| 227 | } | ||
| 228 | 211 | ||
| 229 | case Regs::PixelFormat::RGB5A1: | 212 | case Regs::PixelFormat::RGB5A1: |
| 230 | { | 213 | Color::EncodeRGB5A1(src_color, dst_pixel); |
| 231 | u16* dstptr = (u16*)(dest_pointer + dst_offset); | ||
| 232 | *dstptr = ((source_color.r >> 3) << 11) | ((source_color.g >> 3) << 6) | ||
| 233 | | ((source_color.b >> 3) << 1) | ( source_color.a >> 7); | ||
| 234 | break; | 214 | break; |
| 235 | } | ||
| 236 | 215 | ||
| 237 | case Regs::PixelFormat::RGBA4: | 216 | case Regs::PixelFormat::RGBA4: |
| 238 | { | 217 | Color::EncodeRGBA4(src_color, dst_pixel); |
| 239 | u16* dstptr = (u16*)(dest_pointer + dst_offset); | ||
| 240 | *dstptr = ((source_color.r >> 4) << 12) | ((source_color.g >> 4) << 8) | ||
| 241 | | ((source_color.b >> 4) << 4) | ( source_color.a >> 4); | ||
| 242 | break; | 218 | break; |
| 243 | } | ||
| 244 | 219 | ||
| 245 | default: | 220 | default: |
| 246 | LOG_ERROR(HW_GPU, "Unknown destination framebuffer format %x", config.output_format.Value()); | 221 | LOG_ERROR(HW_GPU, "Unknown destination framebuffer format %x", config.output_format.Value()); |
diff --git a/src/video_core/CMakeLists.txt b/src/video_core/CMakeLists.txt index 13c3f7b22..4c1e6449a 100644 --- a/src/video_core/CMakeLists.txt +++ b/src/video_core/CMakeLists.txt | |||
| @@ -19,6 +19,7 @@ set(HEADERS | |||
| 19 | renderer_opengl/gl_shaders.h | 19 | renderer_opengl/gl_shaders.h |
| 20 | renderer_opengl/renderer_opengl.h | 20 | renderer_opengl/renderer_opengl.h |
| 21 | clipper.h | 21 | clipper.h |
| 22 | color.h | ||
| 22 | command_processor.h | 23 | command_processor.h |
| 23 | gpu_debugger.h | 24 | gpu_debugger.h |
| 24 | math.h | 25 | math.h |
diff --git a/src/video_core/color.h b/src/video_core/color.h index f095d8ac5..35da901f2 100644 --- a/src/video_core/color.h +++ b/src/video_core/color.h | |||
| @@ -5,47 +5,152 @@ | |||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include "common/common_types.h" | 7 | #include "common/common_types.h" |
| 8 | #include "video_core/math.h" | ||
| 8 | 9 | ||
| 9 | namespace Color { | 10 | namespace Color { |
| 10 | 11 | ||
| 11 | /// Convert a 1-bit color component to 8 bit | 12 | /// Convert a 1-bit color component to 8 bit |
| 12 | static inline u8 Convert1To8(u8 value) { | 13 | inline u8 Convert1To8(u8 value) { |
| 13 | return value * 255; | 14 | return value * 255; |
| 14 | } | 15 | } |
| 15 | 16 | ||
| 16 | /// Convert a 4-bit color component to 8 bit | 17 | /// Convert a 4-bit color component to 8 bit |
| 17 | static inline u8 Convert4To8(u8 value) { | 18 | inline u8 Convert4To8(u8 value) { |
| 18 | return (value << 4) | value; | 19 | return (value << 4) | value; |
| 19 | } | 20 | } |
| 20 | 21 | ||
| 21 | /// Convert a 5-bit color component to 8 bit | 22 | /// Convert a 5-bit color component to 8 bit |
| 22 | static inline u8 Convert5To8(u8 value) { | 23 | inline u8 Convert5To8(u8 value) { |
| 23 | return (value << 3) | (value >> 2); | 24 | return (value << 3) | (value >> 2); |
| 24 | } | 25 | } |
| 25 | 26 | ||
| 26 | /// Convert a 6-bit color component to 8 bit | 27 | /// Convert a 6-bit color component to 8 bit |
| 27 | static inline u8 Convert6To8(u8 value) { | 28 | inline u8 Convert6To8(u8 value) { |
| 28 | return (value << 2) | (value >> 4); | 29 | return (value << 2) | (value >> 4); |
| 29 | } | 30 | } |
| 30 | 31 | ||
| 31 | /// Convert a 8-bit color component to 1 bit | 32 | /// Convert a 8-bit color component to 1 bit |
| 32 | static inline u8 Convert8To1(u8 value) { | 33 | inline u8 Convert8To1(u8 value) { |
| 33 | return value >> 7; | 34 | return value >> 7; |
| 34 | } | 35 | } |
| 35 | 36 | ||
| 36 | /// Convert a 8-bit color component to 4 bit | 37 | /// Convert a 8-bit color component to 4 bit |
| 37 | static inline u8 Convert8To4(u8 value) { | 38 | inline u8 Convert8To4(u8 value) { |
| 38 | return value >> 4; | 39 | return value >> 4; |
| 39 | } | 40 | } |
| 40 | 41 | ||
| 41 | /// Convert a 8-bit color component to 5 bit | 42 | /// Convert a 8-bit color component to 5 bit |
| 42 | static inline u8 Convert8To5(u8 value) { | 43 | inline u8 Convert8To5(u8 value) { |
| 43 | return value >> 3; | 44 | return value >> 3; |
| 44 | } | 45 | } |
| 45 | 46 | ||
| 46 | /// Convert a 8-bit color component to 6 bit | 47 | /// Convert a 8-bit color component to 6 bit |
| 47 | static inline u8 Convert8To6(u8 value) { | 48 | inline u8 Convert8To6(u8 value) { |
| 48 | return value >> 2; | 49 | return value >> 2; |
| 49 | } | 50 | } |
| 50 | 51 | ||
| 52 | /** | ||
| 53 | * Decode a color stored in RGBA8 format | ||
| 54 | * @param bytes Pointer to encoded source color | ||
| 55 | * @return Result color decoded as Math::Vec4<u8> | ||
| 56 | */ | ||
| 57 | inline const Math::Vec4<u8> DecodeRGBA8(const u8* bytes) { | ||
| 58 | return { bytes[3], bytes[2], bytes[1], bytes[0] }; | ||
| 59 | } | ||
| 60 | |||
| 61 | /** | ||
| 62 | * Decode a color stored in RGB8 format | ||
| 63 | * @param bytes Pointer to encoded source color | ||
| 64 | * @return Result color decoded as Math::Vec4<u8> | ||
| 65 | */ | ||
| 66 | inline const Math::Vec4<u8> DecodeRGB8(const u8* bytes) { | ||
| 67 | return { bytes[2], bytes[1], bytes[0], 255 }; | ||
| 68 | } | ||
| 69 | |||
| 70 | /** | ||
| 71 | * Decode a color stored in RGB565 format | ||
| 72 | * @param bytes Pointer to encoded source color | ||
| 73 | * @return Result color decoded as Math::Vec4<u8> | ||
| 74 | */ | ||
| 75 | inline const Math::Vec4<u8> DecodeRGB565(const u8* bytes) { | ||
| 76 | const u16_le pixel = *reinterpret_cast<const u16_le*>(bytes); | ||
| 77 | return { Convert5To8((pixel >> 11) & 0x1F), Convert6To8((pixel >> 5) & 0x3F), | ||
| 78 | Convert5To8(pixel & 0x1F), 255 }; | ||
| 79 | } | ||
| 80 | |||
| 81 | /** | ||
| 82 | * Decode a color stored in RGB5A1 format | ||
| 83 | * @param bytes Pointer to encoded source color | ||
| 84 | * @return Result color decoded as Math::Vec4<u8> | ||
| 85 | */ | ||
| 86 | inline const Math::Vec4<u8> DecodeRGB5A1(const u8* bytes) { | ||
| 87 | const u16_le pixel = *reinterpret_cast<const u16_le*>(bytes); | ||
| 88 | return { Convert5To8((pixel >> 11) & 0x1F), Convert5To8((pixel >> 6) & 0x1F), | ||
| 89 | Convert5To8((pixel >> 1) & 0x1F), Convert1To8(pixel & 0x1) }; | ||
| 90 | } | ||
| 91 | |||
| 92 | /** | ||
| 93 | * Decode a color stored in RGBA4 format | ||
| 94 | * @param bytes Pointer to encoded source color | ||
| 95 | * @return Result color decoded as Math::Vec4<u8> | ||
| 96 | */ | ||
| 97 | inline const Math::Vec4<u8> DecodeRGBA4(const u8* bytes) { | ||
| 98 | const u16_le pixel = *reinterpret_cast<const u16_le*>(bytes); | ||
| 99 | return { Convert4To8((pixel >> 12) & 0xF), Convert4To8((pixel >> 8) & 0xF), | ||
| 100 | Convert4To8((pixel >> 4) & 0xF), Convert4To8(pixel & 0xF) }; | ||
| 101 | } | ||
| 102 | |||
| 103 | /** | ||
| 104 | * Encode a color as RGBA8 format | ||
| 105 | * @param color Source color to encode | ||
| 106 | * @param bytes Destination pointer to store encoded color | ||
| 107 | */ | ||
| 108 | inline void EncodeRGBA8(const Math::Vec4<u8>& color, u8* bytes) { | ||
| 109 | bytes[3] = color.r(); | ||
| 110 | bytes[2] = color.g(); | ||
| 111 | bytes[1] = color.b(); | ||
| 112 | bytes[0] = color.a(); | ||
| 113 | } | ||
| 114 | |||
| 115 | /** | ||
| 116 | * Encode a color as RGB8 format | ||
| 117 | * @param color Source color to encode | ||
| 118 | * @param bytes Destination pointer to store encoded color | ||
| 119 | */ | ||
| 120 | inline void EncodeRGB8(const Math::Vec4<u8>& color, u8* bytes) { | ||
| 121 | bytes[2] = color.r(); | ||
| 122 | bytes[1] = color.g(); | ||
| 123 | bytes[0] = color.b(); | ||
| 124 | } | ||
| 125 | |||
| 126 | /** | ||
| 127 | * Encode a color as RGB565 format | ||
| 128 | * @param color Source color to encode | ||
| 129 | * @param bytes Destination pointer to store encoded color | ||
| 130 | */ | ||
| 131 | inline void EncodeRGB565(const Math::Vec4<u8>& color, u8* bytes) { | ||
| 132 | *reinterpret_cast<u16_le*>(bytes) = (Convert8To5(color.r()) << 11) | | ||
| 133 | (Convert8To6(color.g()) << 5) | Convert8To5(color.b()); | ||
| 134 | } | ||
| 135 | |||
| 136 | /** | ||
| 137 | * Encode a color as RGB5A1 format | ||
| 138 | * @param color Source color to encode | ||
| 139 | * @param bytes Destination pointer to store encoded color | ||
| 140 | */ | ||
| 141 | inline void EncodeRGB5A1(const Math::Vec4<u8>& color, u8* bytes) { | ||
| 142 | *reinterpret_cast<u16_le*>(bytes) = (Convert8To5(color.r()) << 11) | | ||
| 143 | (Convert8To5(color.g()) << 6) | (Convert8To5(color.b()) << 1) | Convert8To1(color.a()); | ||
| 144 | } | ||
| 145 | |||
| 146 | /** | ||
| 147 | * Encode a color as RGBA4 format | ||
| 148 | * @param color Source color to encode | ||
| 149 | * @param bytes Destination pointer to store encoded color | ||
| 150 | */ | ||
| 151 | inline void EncodeRGBA4(const Math::Vec4<u8>& color, u8* bytes) { | ||
| 152 | *reinterpret_cast<u16_le*>(bytes) = (Convert8To4(color.r()) << 12) | | ||
| 153 | (Convert8To4(color.g()) << 8) | (Convert8To4(color.b()) << 4) | Convert8To4(color.a()); | ||
| 154 | } | ||
| 155 | |||
| 51 | } // namespace | 156 | } // namespace |
diff --git a/src/video_core/debug_utils/debug_utils.cpp b/src/video_core/debug_utils/debug_utils.cpp index 27c246a99..a27d3828c 100644 --- a/src/video_core/debug_utils/debug_utils.cpp +++ b/src/video_core/debug_utils/debug_utils.cpp | |||
| @@ -321,44 +321,32 @@ const Math::Vec4<u8> LookupTexture(const u8* source, int x, int y, const Texture | |||
| 321 | switch (info.format) { | 321 | switch (info.format) { |
| 322 | case Regs::TextureFormat::RGBA8: | 322 | case Regs::TextureFormat::RGBA8: |
| 323 | { | 323 | { |
| 324 | const u8* source_ptr = source + VideoCore::GetMortonOffset(x, y, 4); | 324 | auto res = Color::DecodeRGBA8(source + VideoCore::GetMortonOffset(x, y, 4)); |
| 325 | return { source_ptr[3], source_ptr[2], source_ptr[1], disable_alpha ? (u8)255 : source_ptr[0] }; | 325 | return { res.r(), res.g(), res.b(), disable_alpha ? 255 : res.a() }; |
| 326 | } | 326 | } |
| 327 | 327 | ||
| 328 | case Regs::TextureFormat::RGB8: | 328 | case Regs::TextureFormat::RGB8: |
| 329 | { | 329 | { |
| 330 | const u8* source_ptr = source + VideoCore::GetMortonOffset(x, y, 3); | 330 | auto res = Color::DecodeRGB8(source + VideoCore::GetMortonOffset(x, y, 3)); |
| 331 | return { source_ptr[2], source_ptr[1], source_ptr[0], 255 }; | 331 | return { res.r(), res.g(), res.b(), 255 }; |
| 332 | } | 332 | } |
| 333 | 333 | ||
| 334 | case Regs::TextureFormat::RGBA5551: | 334 | case Regs::TextureFormat::RGB5A1: |
| 335 | { | 335 | { |
| 336 | const u16 source_ptr = *(const u16*)(source + VideoCore::GetMortonOffset(x, y, 2)); | 336 | auto res = Color::DecodeRGB5A1(source + VideoCore::GetMortonOffset(x, y, 2)); |
| 337 | u8 r = (source_ptr >> 11) & 0x1F; | 337 | return { res.r(), res.g(), res.b(), disable_alpha ? 255 : res.a() }; |
| 338 | u8 g = ((source_ptr) >> 6) & 0x1F; | ||
| 339 | u8 b = (source_ptr >> 1) & 0x1F; | ||
| 340 | u8 a = source_ptr & 1; | ||
| 341 | return Math::MakeVec<u8>(Color::Convert5To8(r), Color::Convert5To8(g), | ||
| 342 | Color::Convert5To8(b), disable_alpha ? 255 : Color::Convert1To8(a)); | ||
| 343 | } | 338 | } |
| 344 | 339 | ||
| 345 | case Regs::TextureFormat::RGB565: | 340 | case Regs::TextureFormat::RGB565: |
| 346 | { | 341 | { |
| 347 | const u16 source_ptr = *(const u16*)(source + VideoCore::GetMortonOffset(x, y, 2)); | 342 | auto res = Color::DecodeRGB565(source + VideoCore::GetMortonOffset(x, y, 2)); |
| 348 | u8 r = Color::Convert5To8((source_ptr >> 11) & 0x1F); | 343 | return { res.r(), res.g(), res.b(), 255 }; |
| 349 | u8 g = Color::Convert6To8(((source_ptr) >> 5) & 0x3F); | ||
| 350 | u8 b = Color::Convert5To8((source_ptr) & 0x1F); | ||
| 351 | return Math::MakeVec<u8>(r, g, b, 255); | ||
| 352 | } | 344 | } |
| 353 | 345 | ||
| 354 | case Regs::TextureFormat::RGBA4: | 346 | case Regs::TextureFormat::RGBA4: |
| 355 | { | 347 | { |
| 356 | const u8* source_ptr = source + VideoCore::GetMortonOffset(x, y, 2); | 348 | auto res = Color::DecodeRGBA4(source + VideoCore::GetMortonOffset(x, y, 2)); |
| 357 | u8 r = Color::Convert4To8(source_ptr[1] >> 4); | 349 | return { res.r(), res.g(), res.b(), disable_alpha ? 255 : res.a() }; |
| 358 | u8 g = Color::Convert4To8(source_ptr[1] & 0xF); | ||
| 359 | u8 b = Color::Convert4To8(source_ptr[0] >> 4); | ||
| 360 | u8 a = Color::Convert4To8(source_ptr[0] & 0xF); | ||
| 361 | return { r, g, b, disable_alpha ? (u8)255 : a }; | ||
| 362 | } | 350 | } |
| 363 | 351 | ||
| 364 | case Regs::TextureFormat::IA8: | 352 | case Regs::TextureFormat::IA8: |
| @@ -369,7 +357,7 @@ const Math::Vec4<u8> LookupTexture(const u8* source, int x, int y, const Texture | |||
| 369 | // Show intensity as red, alpha as green | 357 | // Show intensity as red, alpha as green |
| 370 | return { source_ptr[1], source_ptr[0], 0, 255 }; | 358 | return { source_ptr[1], source_ptr[0], 0, 255 }; |
| 371 | } else { | 359 | } else { |
| 372 | return { source_ptr[1], source_ptr[1], source_ptr[1], source_ptr[0]}; | 360 | return { source_ptr[1], source_ptr[1], source_ptr[1], source_ptr[0] }; |
| 373 | } | 361 | } |
| 374 | } | 362 | } |
| 375 | 363 | ||
diff --git a/src/video_core/pica.h b/src/video_core/pica.h index 96d0c72fe..b14de9278 100644 --- a/src/video_core/pica.h +++ b/src/video_core/pica.h | |||
| @@ -145,7 +145,7 @@ struct Regs { | |||
| 145 | enum class TextureFormat : u32 { | 145 | enum class TextureFormat : u32 { |
| 146 | RGBA8 = 0, | 146 | RGBA8 = 0, |
| 147 | RGB8 = 1, | 147 | RGB8 = 1, |
| 148 | RGBA5551 = 2, | 148 | RGB5A1 = 2, |
| 149 | RGB565 = 3, | 149 | RGB565 = 3, |
| 150 | RGBA4 = 4, | 150 | RGBA4 = 4, |
| 151 | IA8 = 5, | 151 | IA8 = 5, |
| @@ -167,7 +167,7 @@ struct Regs { | |||
| 167 | case TextureFormat::RGB8: | 167 | case TextureFormat::RGB8: |
| 168 | return 6; | 168 | return 6; |
| 169 | 169 | ||
| 170 | case TextureFormat::RGBA5551: | 170 | case TextureFormat::RGB5A1: |
| 171 | case TextureFormat::RGB565: | 171 | case TextureFormat::RGB565: |
| 172 | case TextureFormat::RGBA4: | 172 | case TextureFormat::RGBA4: |
| 173 | case TextureFormat::IA8: | 173 | case TextureFormat::IA8: |
| @@ -413,7 +413,7 @@ struct Regs { | |||
| 413 | enum ColorFormat : u32 { | 413 | enum ColorFormat : u32 { |
| 414 | RGBA8 = 0, | 414 | RGBA8 = 0, |
| 415 | RGB8 = 1, | 415 | RGB8 = 1, |
| 416 | RGBA5551 = 2, | 416 | RGB5A1 = 2, |
| 417 | RGB565 = 3, | 417 | RGB565 = 3, |
| 418 | RGBA4 = 4, | 418 | RGBA4 = 4, |
| 419 | }; | 419 | }; |
diff --git a/src/video_core/rasterizer.cpp b/src/video_core/rasterizer.cpp index 8c370781a..5861c1926 100644 --- a/src/video_core/rasterizer.cpp +++ b/src/video_core/rasterizer.cpp | |||
| @@ -22,7 +22,6 @@ namespace Rasterizer { | |||
| 22 | 22 | ||
| 23 | static void DrawPixel(int x, int y, const Math::Vec4<u8>& color) { | 23 | static void DrawPixel(int x, int y, const Math::Vec4<u8>& color) { |
| 24 | const PAddr addr = registers.framebuffer.GetColorBufferPhysicalAddress(); | 24 | const PAddr addr = registers.framebuffer.GetColorBufferPhysicalAddress(); |
| 25 | u8* color_buffer = Memory::GetPointer(PAddrToVAddr(addr)); | ||
| 26 | 25 | ||
| 27 | // Similarly to textures, the render framebuffer is laid out from bottom to top, too. | 26 | // Similarly to textures, the render framebuffer is laid out from bottom to top, too. |
| 28 | // NOTE: The framebuffer height register contains the actual FB height minus one. | 27 | // NOTE: The framebuffer height register contains the actual FB height minus one. |
| @@ -31,35 +30,28 @@ static void DrawPixel(int x, int y, const Math::Vec4<u8>& color) { | |||
| 31 | const u32 coarse_y = y & ~7; | 30 | const u32 coarse_y = y & ~7; |
| 32 | u32 bytes_per_pixel = GPU::Regs::BytesPerPixel(GPU::Regs::PixelFormat(registers.framebuffer.color_format.Value())); | 31 | u32 bytes_per_pixel = GPU::Regs::BytesPerPixel(GPU::Regs::PixelFormat(registers.framebuffer.color_format.Value())); |
| 33 | u32 dst_offset = VideoCore::GetMortonOffset(x, y, bytes_per_pixel) + coarse_y * registers.framebuffer.width * bytes_per_pixel; | 32 | u32 dst_offset = VideoCore::GetMortonOffset(x, y, bytes_per_pixel) + coarse_y * registers.framebuffer.width * bytes_per_pixel; |
| 33 | u8* dst_pixel = Memory::GetPointer(PAddrToVAddr(addr)) + dst_offset; | ||
| 34 | 34 | ||
| 35 | switch (registers.framebuffer.color_format) { | 35 | switch (registers.framebuffer.color_format) { |
| 36 | case registers.framebuffer.RGBA8: | 36 | case registers.framebuffer.RGBA8: |
| 37 | { | 37 | Color::EncodeRGBA8(color, dst_pixel); |
| 38 | u8* pixel = color_buffer + dst_offset; | ||
| 39 | pixel[3] = color.r(); | ||
| 40 | pixel[2] = color.g(); | ||
| 41 | pixel[1] = color.b(); | ||
| 42 | pixel[0] = color.a(); | ||
| 43 | break; | 38 | break; |
| 44 | } | ||
| 45 | 39 | ||
| 46 | case registers.framebuffer.RGBA4: | 40 | case registers.framebuffer.RGB8: |
| 47 | { | 41 | Color::EncodeRGB8(color, dst_pixel); |
| 48 | u8* pixel = color_buffer + dst_offset; | ||
| 49 | pixel[1] = (color.r() & 0xF0) | (color.g() >> 4); | ||
| 50 | pixel[0] = (color.b() & 0xF0) | (color.a() >> 4); | ||
| 51 | break; | 42 | break; |
| 52 | } | ||
| 53 | 43 | ||
| 54 | case registers.framebuffer.RGBA5551: | 44 | case registers.framebuffer.RGB5A1: |
| 55 | { | 45 | Color::EncodeRGB5A1(color, dst_pixel); |
| 56 | u16_le* pixel = (u16_le*)(color_buffer + dst_offset); | 46 | break; |
| 57 | *pixel = (Color::Convert8To5(color.r()) << 11) | | 47 | |
| 58 | (Color::Convert8To5(color.g()) << 6) | | 48 | case registers.framebuffer.RGB565: |
| 59 | (Color::Convert8To5(color.b()) << 1) | | 49 | Color::EncodeRGB565(color, dst_pixel); |
| 60 | Color::Convert8To1(color.a()); | 50 | break; |
| 51 | |||
| 52 | case registers.framebuffer.RGBA4: | ||
| 53 | Color::EncodeRGBA4(color, dst_pixel); | ||
| 61 | break; | 54 | break; |
| 62 | } | ||
| 63 | 55 | ||
| 64 | default: | 56 | default: |
| 65 | LOG_CRITICAL(Render_Software, "Unknown framebuffer color format %x", registers.framebuffer.color_format.Value()); | 57 | LOG_CRITICAL(Render_Software, "Unknown framebuffer color format %x", registers.framebuffer.color_format.Value()); |
| @@ -69,45 +61,29 @@ static void DrawPixel(int x, int y, const Math::Vec4<u8>& color) { | |||
| 69 | 61 | ||
| 70 | static const Math::Vec4<u8> GetPixel(int x, int y) { | 62 | static const Math::Vec4<u8> GetPixel(int x, int y) { |
| 71 | const PAddr addr = registers.framebuffer.GetColorBufferPhysicalAddress(); | 63 | const PAddr addr = registers.framebuffer.GetColorBufferPhysicalAddress(); |
| 72 | u8* color_buffer = Memory::GetPointer(PAddrToVAddr(addr)); | ||
| 73 | 64 | ||
| 74 | y = (registers.framebuffer.height - y); | 65 | y = (registers.framebuffer.height - y); |
| 75 | 66 | ||
| 76 | const u32 coarse_y = y & ~7; | 67 | const u32 coarse_y = y & ~7; |
| 77 | u32 bytes_per_pixel = GPU::Regs::BytesPerPixel(GPU::Regs::PixelFormat(registers.framebuffer.color_format.Value())); | 68 | u32 bytes_per_pixel = GPU::Regs::BytesPerPixel(GPU::Regs::PixelFormat(registers.framebuffer.color_format.Value())); |
| 78 | u32 src_offset = VideoCore::GetMortonOffset(x, y, bytes_per_pixel) + coarse_y * registers.framebuffer.width * bytes_per_pixel; | 69 | u32 src_offset = VideoCore::GetMortonOffset(x, y, bytes_per_pixel) + coarse_y * registers.framebuffer.width * bytes_per_pixel; |
| 79 | Math::Vec4<u8> ret; | 70 | u8* src_pixel = Memory::GetPointer(PAddrToVAddr(addr)) + src_offset; |
| 80 | 71 | ||
| 81 | switch (registers.framebuffer.color_format) { | 72 | switch (registers.framebuffer.color_format) { |
| 82 | case registers.framebuffer.RGBA8: | 73 | case registers.framebuffer.RGBA8: |
| 83 | { | 74 | return Color::DecodeRGBA8(src_pixel); |
| 84 | u8* pixel = color_buffer + src_offset; | ||
| 85 | ret.r() = pixel[3]; | ||
| 86 | ret.g() = pixel[2]; | ||
| 87 | ret.b() = pixel[1]; | ||
| 88 | ret.a() = pixel[0]; | ||
| 89 | return ret; | ||
| 90 | } | ||
| 91 | 75 | ||
| 92 | case registers.framebuffer.RGBA4: | 76 | case registers.framebuffer.RGB8: |
| 93 | { | 77 | return Color::DecodeRGB8(src_pixel); |
| 94 | u8* pixel = color_buffer + src_offset; | ||
| 95 | ret.r() = Color::Convert4To8(pixel[1] >> 4); | ||
| 96 | ret.g() = Color::Convert4To8(pixel[1] & 0x0F); | ||
| 97 | ret.b() = Color::Convert4To8(pixel[0] >> 4); | ||
| 98 | ret.a() = Color::Convert4To8(pixel[0] & 0x0F); | ||
| 99 | return ret; | ||
| 100 | } | ||
| 101 | 78 | ||
| 102 | case registers.framebuffer.RGBA5551: | 79 | case registers.framebuffer.RGB5A1: |
| 103 | { | 80 | return Color::DecodeRGB5A1(src_pixel); |
| 104 | u16_le pixel = *(u16_le*)(color_buffer + src_offset); | 81 | |
| 105 | ret.r() = Color::Convert5To8((pixel >> 11) & 0x1F); | 82 | case registers.framebuffer.RGB565: |
| 106 | ret.g() = Color::Convert5To8((pixel >> 6) & 0x1F); | 83 | return Color::DecodeRGB565(src_pixel); |
| 107 | ret.b() = Color::Convert5To8((pixel >> 1) & 0x1F); | 84 | |
| 108 | ret.a() = Color::Convert1To8(pixel & 0x1); | 85 | case registers.framebuffer.RGBA4: |
| 109 | return ret; | 86 | return Color::DecodeRGBA4(src_pixel); |
| 110 | } | ||
| 111 | 87 | ||
| 112 | default: | 88 | default: |
| 113 | LOG_CRITICAL(Render_Software, "Unknown framebuffer color format %x", registers.framebuffer.color_format.Value()); | 89 | LOG_CRITICAL(Render_Software, "Unknown framebuffer color format %x", registers.framebuffer.color_format.Value()); |