diff options
author | archshift <admin@archshift.com> | 2014-10-13 07:40:26 +0200 |
---|---|---|
committer | archshift <admin@archshift.com> | 2015-03-09 23:51:41 +0100 |
commit | 041e99b6132775ff52822060512b8384b735e582 (patch) | |
tree | cd8dee92a0b578e512a188cd7e70239b627a5341 | |
parent | Implement SetLcdForceBlack, move register enum to hw.h (diff) | |
download | yuzu-041e99b6132775ff52822060512b8384b735e582.tar yuzu-041e99b6132775ff52822060512b8384b735e582.tar.gz yuzu-041e99b6132775ff52822060512b8384b735e582.tar.bz2 yuzu-041e99b6132775ff52822060512b8384b735e582.tar.lz yuzu-041e99b6132775ff52822060512b8384b735e582.tar.xz yuzu-041e99b6132775ff52822060512b8384b735e582.tar.zst yuzu-041e99b6132775ff52822060512b8384b735e582.zip |
-rw-r--r-- | src/common/logging/backend.cpp | 1 | ||||
-rw-r--r-- | src/common/logging/log.h | 1 | ||||
-rw-r--r-- | src/core/CMakeLists.txt | 2 | ||||
-rw-r--r-- | src/core/hle/service/gsp_gpu.cpp | 32 | ||||
-rw-r--r-- | src/core/hw/gpu.h | 2 | ||||
-rw-r--r-- | src/core/hw/hw.cpp | 12 | ||||
-rw-r--r-- | src/core/hw/hw.h | 8 | ||||
-rw-r--r-- | src/core/hw/lcd.cpp | 66 | ||||
-rw-r--r-- | src/core/hw/lcd.h | 88 | ||||
-rw-r--r-- | src/video_core/renderer_opengl/renderer_opengl.cpp | 54 | ||||
-rw-r--r-- | src/video_core/renderer_opengl/renderer_opengl.h | 5 |
11 files changed, 234 insertions, 37 deletions
diff --git a/src/common/logging/backend.cpp b/src/common/logging/backend.cpp index 7c1010b22..da287f69e 100644 --- a/src/common/logging/backend.cpp +++ b/src/common/logging/backend.cpp @@ -45,6 +45,7 @@ static std::shared_ptr<Logger> global_logger; SUB(Service, SOC) \ CLS(HW) \ SUB(HW, Memory) \ + SUB(HW, LCD) \ SUB(HW, GPU) \ CLS(Frontend) \ CLS(Render) \ diff --git a/src/common/logging/log.h b/src/common/logging/log.h index 7b67b3c07..83d64145b 100644 --- a/src/common/logging/log.h +++ b/src/common/logging/log.h @@ -65,6 +65,7 @@ enum class Class : ClassType { Service_SOC, ///< The SOC (Socket) service HW, ///< Low-level hardware emulation HW_Memory, ///< Memory-map and address translation + HW_LCD, ///< LCD register emulation HW_GPU, ///< GPU control emulation Frontend, ///< Emulator UI Render, ///< Emulator video output and hardware acceleration diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 212da25c5..33e5be3a4 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -87,6 +87,7 @@ set(SRCS hle/svc.cpp hw/gpu.cpp hw/hw.cpp + hw/lcd.cpp loader/elf.cpp loader/loader.cpp loader/ncch.cpp @@ -196,6 +197,7 @@ set(HEADERS hle/svc.h hw/gpu.h hw/hw.h + hw/lcd.h loader/elf.h loader/loader.h loader/ncch.h diff --git a/src/core/hle/service/gsp_gpu.cpp b/src/core/hle/service/gsp_gpu.cpp index 3b4a7b664..cff585698 100644 --- a/src/core/hle/service/gsp_gpu.cpp +++ b/src/core/hle/service/gsp_gpu.cpp @@ -11,12 +11,16 @@ #include "gsp_gpu.h" #include "core/hw/hw.h" #include "core/hw/gpu.h" +#include "core/hw/lcd.h" #include "video_core/gpu_debugger.h" // Main graphics debugger object - TODO: Here is probably not the best place for this GraphicsDebugger g_debugger; +// Beginning address of HW regs +const static u32 REGS_BEGIN = 0x1EB00000; + //////////////////////////////////////////////////////////////////////////////////////////////////// // Namespace GSP_GPU @@ -87,7 +91,7 @@ static void WriteHWRegs(u32 base_address, u32 size_in_bytes, const u32* data) { return; while (size_in_bytes > 0) { - HW::Write<u32>(base_address + 0x1EB00000, *data); + HW::Write<u32>(base_address + REGS_BEGIN, *data); size_in_bytes -= 4; ++data; @@ -130,7 +134,7 @@ static void WriteHWRegsWithMask(u32 base_address, u32 size_in_bytes, const u32* return; while (size_in_bytes > 0) { - const u32 reg_address = base_address + 0x1EB00000; + const u32 reg_address = base_address + REGS_BEGIN; u32 reg_value; HW::Read<u32>(reg_value, reg_address); @@ -190,7 +194,7 @@ static void ReadHWRegs(Service::Interface* self) { u32* dst = (u32*)Memory::GetPointer(cmd_buff[0x41]); while (size > 0) { - HW::Read<u32>(*dst, reg_addr + 0x1EB00000); + HW::Read<u32>(*dst, reg_addr + REGS_BEGIN); size -= 4; ++dst; @@ -439,24 +443,18 @@ static void ExecuteCommand(const Command& command, u32 thread_id) { * Outputs: * 1: Result code */ -void SetLcdForceBlack(Service::Interface* self) { - // TODO: currently has no effect, as LCD reg writes have nowhere to go. - +static void SetLcdForceBlack(Service::Interface* self) { u32* cmd_buff = Kernel::GetCommandBuffer(); + bool enable_black = cmd_buff[1] != 0; - u32 data = 0; + LCD::Regs::ColorFill data = {0}; - if (enable_black) { - // Sets bit 24 to 1, enabling the fill - // Since data is already 0x00000000, there is no need to explicitly set - // bits 0-23 to zero (black), or bit 24 to 0 (fill disabled). - data |= (1 << 24); - } + // Since data is already zeroed, there is no need to explicitly set + // the color to black (all zero). + data.is_enabled = enable_black; - u32 data_main = data; - u32 data_sub = data; - WriteHWRegs(0x202204, 4, &data_main); // Main LCD - WriteHWRegs(0x202A04, 4, &data_sub); // Sub LCD + LCD::Write(HW::VADDR_LCD + 4 * LCD_REG_INDEX(color_fill_top), data.raw); // Top LCD + LCD::Write(HW::VADDR_LCD + 4 * LCD_REG_INDEX(color_fill_bottom), data.raw); // Bottom LCD cmd_buff[1] = RESULT_SUCCESS.raw; } diff --git a/src/core/hw/gpu.h b/src/core/hw/gpu.h index 737b1e968..76f4d66fe 100644 --- a/src/core/hw/gpu.h +++ b/src/core/hw/gpu.h @@ -246,6 +246,8 @@ struct Regs { return content[index]; } +#undef ASSERT_MEMBER_SIZE + private: /* * Most physical addresses which GPU registers refer to are 8-byte aligned. diff --git a/src/core/hw/hw.cpp b/src/core/hw/hw.cpp index bf4722cf7..bed50af50 100644 --- a/src/core/hw/hw.cpp +++ b/src/core/hw/hw.cpp @@ -6,17 +6,19 @@ #include "core/hw/hw.h" #include "core/hw/gpu.h" +#include "core/hw/lcd.h" namespace HW { template <typename T> inline void Read(T &var, const u32 addr) { switch (addr & 0xFFFFF000) { - case VADDR_GPU: GPU::Read(var, addr); break; - + case VADDR_LCD: + LCD::Write(var, addr); + break; default: LOG_ERROR(HW_Memory, "unknown Read%lu @ 0x%08X", sizeof(var) * 8, addr); } @@ -25,11 +27,12 @@ inline void Read(T &var, const u32 addr) { template <typename T> inline void Write(u32 addr, const T data) { switch (addr & 0xFFFFF000) { - case VADDR_GPU: GPU::Write(addr, data); break; - + case VADDR_LCD: + LCD::Write(addr, data); + break; default: LOG_ERROR(HW_Memory, "unknown Write%lu 0x%08X @ 0x%08X", sizeof(data) * 8, (u32)data, addr); } @@ -54,6 +57,7 @@ void Update() { /// Initialize hardware void Init() { GPU::Init(); + LCD::Init(); LOG_DEBUG(HW, "initialized OK"); } diff --git a/src/core/hw/hw.h b/src/core/hw/hw.h index 6feeba08c..d65608910 100644 --- a/src/core/hw/hw.h +++ b/src/core/hw/hw.h @@ -8,8 +8,8 @@ namespace HW { -enum { - VADDR_IO = 0x1EC00000, +/// Beginnings of IO register regions, in the user VA space. +enum : u32 { VADDR_HASH = 0x1EC01000, VADDR_CSND = 0x1EC03000, VADDR_DSP = 0x1EC40000, @@ -25,9 +25,7 @@ enum { VADDR_SPI_3 = 0x1EC60000, VADDR_I2C_3 = 0x1EC61000, VADDR_MIC = 0x1EC62000, - VADDR_PXI = 0x1EC63000, // 0xFFFD2000 - //VADDR_NTRCARD - VADDR_CDMA = 0xFFFDA000, // CoreLink DMA-330? Info + VADDR_PXI = 0x1EC63000, VADDR_LCD = 0x1ED02000, VADDR_DSP_2 = 0x1ED03000, VADDR_HASH_2 = 0x1EE01000, diff --git a/src/core/hw/lcd.cpp b/src/core/hw/lcd.cpp new file mode 100644 index 000000000..7986f3ddb --- /dev/null +++ b/src/core/hw/lcd.cpp @@ -0,0 +1,66 @@ +// Copyright 2015 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "common/common_types.h" + +#include "core/arm/arm_interface.h" +#include "core/hle/hle.h" +#include "core/hw/hw.h" +#include "core/hw/lcd.h" + +namespace LCD { + +Regs g_regs; + +template <typename T> +inline void Read(T &var, const u32 raw_addr) { + u32 addr = raw_addr - HW::VADDR_LCD; + u32 index = addr / 4; + + // Reads other than u32 are untested, so I'd rather have them abort than silently fail + if (index >= 0x400 || !std::is_same<T, u32>::value) { + LOG_ERROR(HW_LCD, "unknown Read%lu @ 0x%08X", sizeof(var) * 8, addr); + return; + } + + var = g_regs[index]; +} + +template <typename T> +inline void Write(u32 addr, const T data) { + addr -= HW::VADDR_LCD; + u32 index = addr / 4; + + // Writes other than u32 are untested, so I'd rather have them abort than silently fail + if (index >= 0x400 || !std::is_same<T, u32>::value) { + LOG_ERROR(HW_LCD, "unknown Write%lu 0x%08X @ 0x%08X", sizeof(data) * 8, (u32)data, addr); + return; + } + + g_regs[index] = static_cast<u32>(data); +} + +// Explicitly instantiate template functions because we aren't defining this in the header: + +template void Read<u64>(u64 &var, const u32 addr); +template void Read<u32>(u32 &var, const u32 addr); +template void Read<u16>(u16 &var, const u32 addr); +template void Read<u8>(u8 &var, const u32 addr); + +template void Write<u64>(u32 addr, const u64 data); +template void Write<u32>(u32 addr, const u32 data); +template void Write<u16>(u32 addr, const u16 data); +template void Write<u8>(u32 addr, const u8 data); + +/// Initialize hardware +void Init() { + LOG_DEBUG(HW_LCD, "initialized OK"); +} + +/// Shutdown hardware +void Shutdown() { + LOG_DEBUG(HW_LCD, "shutdown OK"); +} + +} // namespace diff --git a/src/core/hw/lcd.h b/src/core/hw/lcd.h new file mode 100644 index 000000000..43893a625 --- /dev/null +++ b/src/core/hw/lcd.h @@ -0,0 +1,88 @@ +// Copyright 2015 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include <cstddef> + +#include "common/common_types.h" +#include "common/bit_field.h" + +#define LCD_REG_INDEX(field_name) (offsetof(LCD::Regs, field_name) / sizeof(u32)) + +namespace LCD { + +struct Regs { + + union ColorFill { + u32 raw; + + BitField<0, 8, u32> color_r; + BitField<8, 8, u32> color_g; + BitField<16, 8, u32> color_b; + BitField<24, 1, u32> is_enabled; + }; + + INSERT_PADDING_WORDS(0x81); + ColorFill color_fill_top; + INSERT_PADDING_WORDS(0xE); + u32 backlight_top; + + INSERT_PADDING_WORDS(0x1F0); + + ColorFill color_fill_bottom; + INSERT_PADDING_WORDS(0xE); + u32 backlight_bottom; + INSERT_PADDING_WORDS(0x16F); + + static inline size_t NumIds() { + return sizeof(Regs) / sizeof(u32); + } + + u32& operator [] (int index) const { + u32* content = (u32*)this; + return content[index]; + } + + u32& operator [] (int index) { + u32* content = (u32*)this; + return content[index]; + } + +#undef ASSERT_MEMBER_SIZE + +}; +static_assert(std::is_standard_layout<Regs>::value, "Structure does not use standard layout"); + +// TODO: MSVC does not support using offsetof() on non-static data members even though this +// is technically allowed since C++11. This macro should be enabled once MSVC adds +// support for that. +#ifndef _MSC_VER +#define ASSERT_REG_POSITION(field_name, position) \ + static_assert(offsetof(Regs, field_name) == position * 4, \ + "Field "#field_name" has invalid position") + +ASSERT_REG_POSITION(color_fill_top, 0x81); +ASSERT_REG_POSITION(backlight_top, 0x90); +ASSERT_REG_POSITION(color_fill_bottom, 0x281); +ASSERT_REG_POSITION(backlight_bottom, 0x290); + +#undef ASSERT_REG_POSITION +#endif // !defined(_MSC_VER) + +extern Regs g_regs; + +template <typename T> +void Read(T &var, const u32 addr); + +template <typename T> +void Write(u32 addr, const T data); + +/// Initialize hardware +void Init(); + +/// Shutdown hardware +void Shutdown(); + +} // namespace diff --git a/src/video_core/renderer_opengl/renderer_opengl.cpp b/src/video_core/renderer_opengl/renderer_opengl.cpp index 272695174..2fcbb0cca 100644 --- a/src/video_core/renderer_opengl/renderer_opengl.cpp +++ b/src/video_core/renderer_opengl/renderer_opengl.cpp @@ -3,6 +3,8 @@ // Refer to the license.txt file included. #include "core/hw/gpu.h" +#include "core/hw/hw.h" +#include "core/hw/lcd.h" #include "core/mem_map.h" #include "common/emu_window.h" #include "video_core/video_core.h" @@ -61,16 +63,33 @@ void RendererOpenGL::SwapBuffers() { for(int i : {0, 1}) { const auto& framebuffer = GPU::g_regs.framebuffer_config[i]; - if (textures[i].width != (GLsizei)framebuffer.width || - textures[i].height != (GLsizei)framebuffer.height || - textures[i].format != framebuffer.color_format) { - // Reallocate texture if the framebuffer size has changed. - // This is expected to not happen very often and hence should not be a - // performance problem. - ConfigureFramebufferTexture(textures[i], framebuffer); + // Main LCD (0): 0x1ED02204, Sub LCD (1): 0x1ED02A04 + u32 lcd_color_addr = (i == 0) ? LCD_REG_INDEX(color_fill_top) : LCD_REG_INDEX(color_fill_bottom); + lcd_color_addr = HW::VADDR_LCD + 4 * lcd_color_addr; + LCD::Regs::ColorFill color_fill = {0}; + LCD::Read(color_fill.raw, lcd_color_addr); + + if (color_fill.is_enabled) { + LoadColorToActiveGLTexture(color_fill.color_r, color_fill.color_g, color_fill.color_b, textures[i]); + + // Resize the texture in case the framebuffer size has changed + textures[i].width = 1; + textures[i].height = 1; + } else { + if (textures[i].width != (GLsizei)framebuffer.width || + textures[i].height != (GLsizei)framebuffer.height || + textures[i].format != framebuffer.color_format) { + // Reallocate texture if the framebuffer size has changed. + // This is expected to not happen very often and hence should not be a + // performance problem. + ConfigureFramebufferTexture(textures[i], framebuffer); + } + LoadFBToActiveGLTexture(framebuffer, textures[i]); + + // Resize the texture in case the framebuffer size has changed + textures[i].width = framebuffer.width; + textures[i].height = framebuffer.height; } - - LoadFBToActiveGLTexture(GPU::g_regs.framebuffer_config[i], textures[i]); } DrawScreens(); @@ -115,10 +134,25 @@ void RendererOpenGL::LoadFBToActiveGLTexture(const GPU::Regs::FramebufferConfig& // TODO: Applications could theoretically crash Citra here by specifying too large // framebuffer sizes. We should make sure that this cannot happen. glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, framebuffer.width, framebuffer.height, - texture.gl_format, texture.gl_type, framebuffer_data); + texture.gl_format, texture.gl_type, framebuffer_data); glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); + glBindTexture(GL_TEXTURE_2D, 0); +} +/** + * Fills active OpenGL texture with the given RGB color. + * Since the color is solid, the texture can be 1x1 but will stretch across whatever it's rendered on. + * This has the added benefit of being *really fast*. + */ +void RendererOpenGL::LoadColorToActiveGLTexture(u8 color_r, u8 color_g, u8 color_b, + const TextureInfo& texture) { + glBindTexture(GL_TEXTURE_2D, texture.handle); + + u8 framebuffer_data[3] = { color_r, color_g, color_b }; + + // Update existing texture + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 1, 1, 0, GL_RGB, GL_UNSIGNED_BYTE, framebuffer_data); glBindTexture(GL_TEXTURE_2D, 0); } diff --git a/src/video_core/renderer_opengl/renderer_opengl.h b/src/video_core/renderer_opengl/renderer_opengl.h index bcabab557..cd782428e 100644 --- a/src/video_core/renderer_opengl/renderer_opengl.h +++ b/src/video_core/renderer_opengl/renderer_opengl.h @@ -58,6 +58,9 @@ private: // Loads framebuffer from emulated memory into the active OpenGL texture. static void LoadFBToActiveGLTexture(const GPU::Regs::FramebufferConfig& framebuffer, const TextureInfo& texture); + // Fills active OpenGL texture with the given RGB color. + static void LoadColorToActiveGLTexture(u8 color_r, u8 color_g, u8 color_b, + const TextureInfo& texture); /// Computes the viewport rectangle MathUtil::Rectangle<unsigned> GetViewportExtent(); @@ -72,7 +75,7 @@ private: GLuint vertex_array_handle; GLuint vertex_buffer_handle; GLuint program_id; - std::array<TextureInfo, 2> textures; + std::array<TextureInfo, 2> textures; ///< Textures for top and bottom screens respectively // Shader uniform location indices GLuint uniform_modelview_matrix; GLuint uniform_color_texture; |