mirror of
				https://github.com/PabloMK7/citra.git
				synced 2025-10-31 05:40:04 +00:00 
			
		
		
		
	Added LCD registers, and implementation for color filling in OGL code.
This commit is contained in:
		
							parent
							
								
									47010fea31
								
							
						
					
					
						commit
						041e99b613
					
				
					 11 changed files with 234 additions and 37 deletions
				
			
		|  | @ -45,6 +45,7 @@ static std::shared_ptr<Logger> global_logger; | ||||||
|         SUB(Service, SOC) \ |         SUB(Service, SOC) \ | ||||||
|         CLS(HW) \ |         CLS(HW) \ | ||||||
|         SUB(HW, Memory) \ |         SUB(HW, Memory) \ | ||||||
|  |         SUB(HW, LCD) \ | ||||||
|         SUB(HW, GPU) \ |         SUB(HW, GPU) \ | ||||||
|         CLS(Frontend) \ |         CLS(Frontend) \ | ||||||
|         CLS(Render) \ |         CLS(Render) \ | ||||||
|  |  | ||||||
|  | @ -65,6 +65,7 @@ enum class Class : ClassType { | ||||||
|     Service_SOC,                ///< The SOC (Socket) service
 |     Service_SOC,                ///< The SOC (Socket) service
 | ||||||
|     HW,                         ///< Low-level hardware emulation
 |     HW,                         ///< Low-level hardware emulation
 | ||||||
|     HW_Memory,                  ///< Memory-map and address translation
 |     HW_Memory,                  ///< Memory-map and address translation
 | ||||||
|  |     HW_LCD,                     ///< LCD register emulation
 | ||||||
|     HW_GPU,                     ///< GPU control emulation
 |     HW_GPU,                     ///< GPU control emulation
 | ||||||
|     Frontend,                   ///< Emulator UI
 |     Frontend,                   ///< Emulator UI
 | ||||||
|     Render,                     ///< Emulator video output and hardware acceleration
 |     Render,                     ///< Emulator video output and hardware acceleration
 | ||||||
|  |  | ||||||
|  | @ -87,6 +87,7 @@ set(SRCS | ||||||
|             hle/svc.cpp |             hle/svc.cpp | ||||||
|             hw/gpu.cpp |             hw/gpu.cpp | ||||||
|             hw/hw.cpp |             hw/hw.cpp | ||||||
|  |             hw/lcd.cpp | ||||||
|             loader/elf.cpp |             loader/elf.cpp | ||||||
|             loader/loader.cpp |             loader/loader.cpp | ||||||
|             loader/ncch.cpp |             loader/ncch.cpp | ||||||
|  | @ -196,6 +197,7 @@ set(HEADERS | ||||||
|             hle/svc.h |             hle/svc.h | ||||||
|             hw/gpu.h |             hw/gpu.h | ||||||
|             hw/hw.h |             hw/hw.h | ||||||
|  |             hw/lcd.h | ||||||
|             loader/elf.h |             loader/elf.h | ||||||
|             loader/loader.h |             loader/loader.h | ||||||
|             loader/ncch.h |             loader/ncch.h | ||||||
|  |  | ||||||
|  | @ -11,12 +11,16 @@ | ||||||
| #include "gsp_gpu.h" | #include "gsp_gpu.h" | ||||||
| #include "core/hw/hw.h" | #include "core/hw/hw.h" | ||||||
| #include "core/hw/gpu.h" | #include "core/hw/gpu.h" | ||||||
|  | #include "core/hw/lcd.h" | ||||||
| 
 | 
 | ||||||
| #include "video_core/gpu_debugger.h" | #include "video_core/gpu_debugger.h" | ||||||
| 
 | 
 | ||||||
| // Main graphics debugger object - TODO: Here is probably not the best place for this
 | // Main graphics debugger object - TODO: Here is probably not the best place for this
 | ||||||
| GraphicsDebugger g_debugger; | GraphicsDebugger g_debugger; | ||||||
| 
 | 
 | ||||||
|  | // Beginning address of HW regs
 | ||||||
|  | const static u32 REGS_BEGIN = 0x1EB00000; | ||||||
|  | 
 | ||||||
| ////////////////////////////////////////////////////////////////////////////////////////////////////
 | ////////////////////////////////////////////////////////////////////////////////////////////////////
 | ||||||
| // Namespace GSP_GPU
 | // Namespace GSP_GPU
 | ||||||
| 
 | 
 | ||||||
|  | @ -87,7 +91,7 @@ static void WriteHWRegs(u32 base_address, u32 size_in_bytes, const u32* data) { | ||||||
|         return; |         return; | ||||||
| 
 | 
 | ||||||
|     while (size_in_bytes > 0) { |     while (size_in_bytes > 0) { | ||||||
|         HW::Write<u32>(base_address + 0x1EB00000, *data); |         HW::Write<u32>(base_address + REGS_BEGIN, *data); | ||||||
| 
 | 
 | ||||||
|         size_in_bytes -= 4; |         size_in_bytes -= 4; | ||||||
|         ++data; |         ++data; | ||||||
|  | @ -130,7 +134,7 @@ static void WriteHWRegsWithMask(u32 base_address, u32 size_in_bytes, const u32* | ||||||
|         return; |         return; | ||||||
| 
 | 
 | ||||||
|     while (size_in_bytes > 0) { |     while (size_in_bytes > 0) { | ||||||
|         const u32 reg_address = base_address + 0x1EB00000; |         const u32 reg_address = base_address + REGS_BEGIN; | ||||||
| 
 | 
 | ||||||
|         u32 reg_value; |         u32 reg_value; | ||||||
|         HW::Read<u32>(reg_value, reg_address); |         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]); |     u32* dst = (u32*)Memory::GetPointer(cmd_buff[0x41]); | ||||||
| 
 | 
 | ||||||
|     while (size > 0) { |     while (size > 0) { | ||||||
|         HW::Read<u32>(*dst, reg_addr + 0x1EB00000); |         HW::Read<u32>(*dst, reg_addr + REGS_BEGIN); | ||||||
| 
 | 
 | ||||||
|         size -= 4; |         size -= 4; | ||||||
|         ++dst; |         ++dst; | ||||||
|  | @ -439,24 +443,18 @@ static void ExecuteCommand(const Command& command, u32 thread_id) { | ||||||
|  *  Outputs: |  *  Outputs: | ||||||
|  *      1: Result code |  *      1: Result code | ||||||
|  */ |  */ | ||||||
| void SetLcdForceBlack(Service::Interface* self) { | static void SetLcdForceBlack(Service::Interface* self) { | ||||||
|     // TODO: currently has no effect, as LCD reg writes have nowhere to go. 
 |  | ||||||
| 
 |  | ||||||
|     u32* cmd_buff = Kernel::GetCommandBuffer(); |     u32* cmd_buff = Kernel::GetCommandBuffer(); | ||||||
|  | 
 | ||||||
|     bool enable_black = cmd_buff[1] != 0; |     bool enable_black = cmd_buff[1] != 0; | ||||||
|     u32 data = 0; |     LCD::Regs::ColorFill data = {0}; | ||||||
| 
 | 
 | ||||||
|     if (enable_black) { |     // Since data is already zeroed, there is no need to explicitly set
 | ||||||
|         // Sets bit 24 to 1, enabling the fill
 |     // the color to black (all zero).
 | ||||||
|         // Since data is already 0x00000000, there is no need to explicitly set
 |     data.is_enabled = enable_black; | ||||||
|         // bits 0-23 to zero (black), or bit 24 to 0 (fill disabled).
 |  | ||||||
|         data |= (1 << 24); |  | ||||||
|     } |  | ||||||
| 
 | 
 | ||||||
|     u32 data_main = data; |     LCD::Write(HW::VADDR_LCD + 4 * LCD_REG_INDEX(color_fill_top), data.raw); // Top LCD
 | ||||||
|     u32 data_sub  = data; |     LCD::Write(HW::VADDR_LCD + 4 * LCD_REG_INDEX(color_fill_bottom), data.raw); // Bottom LCD
 | ||||||
|     WriteHWRegs(0x202204, 4, &data_main); // Main LCD
 |  | ||||||
|     WriteHWRegs(0x202A04, 4, &data_sub);  // Sub LCD
 |  | ||||||
|      |      | ||||||
|     cmd_buff[1] = RESULT_SUCCESS.raw; |     cmd_buff[1] = RESULT_SUCCESS.raw; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -246,6 +246,8 @@ struct Regs { | ||||||
|         return content[index]; |         return content[index]; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | #undef ASSERT_MEMBER_SIZE | ||||||
|  | 
 | ||||||
| private: | private: | ||||||
|     /*
 |     /*
 | ||||||
|      * Most physical addresses which GPU registers refer to are 8-byte aligned. |      * Most physical addresses which GPU registers refer to are 8-byte aligned. | ||||||
|  |  | ||||||
|  | @ -6,17 +6,19 @@ | ||||||
| 
 | 
 | ||||||
| #include "core/hw/hw.h" | #include "core/hw/hw.h" | ||||||
| #include "core/hw/gpu.h" | #include "core/hw/gpu.h" | ||||||
|  | #include "core/hw/lcd.h" | ||||||
| 
 | 
 | ||||||
| namespace HW { | namespace HW { | ||||||
| 
 | 
 | ||||||
| template <typename T> | template <typename T> | ||||||
| inline void Read(T &var, const u32 addr) { | inline void Read(T &var, const u32 addr) { | ||||||
|     switch (addr & 0xFFFFF000) { |     switch (addr & 0xFFFFF000) { | ||||||
| 
 |  | ||||||
|     case VADDR_GPU: |     case VADDR_GPU: | ||||||
|         GPU::Read(var, addr); |         GPU::Read(var, addr); | ||||||
|         break; |         break; | ||||||
| 
 |     case VADDR_LCD: | ||||||
|  |         LCD::Write(var, addr); | ||||||
|  |         break; | ||||||
|     default: |     default: | ||||||
|         LOG_ERROR(HW_Memory, "unknown Read%lu @ 0x%08X", sizeof(var) * 8, addr); |         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> | template <typename T> | ||||||
| inline void Write(u32 addr, const T data) { | inline void Write(u32 addr, const T data) { | ||||||
|     switch (addr & 0xFFFFF000) { |     switch (addr & 0xFFFFF000) { | ||||||
| 
 |  | ||||||
|     case VADDR_GPU: |     case VADDR_GPU: | ||||||
|         GPU::Write(addr, data); |         GPU::Write(addr, data); | ||||||
|         break; |         break; | ||||||
| 
 |     case VADDR_LCD: | ||||||
|  |         LCD::Write(addr, data); | ||||||
|  |         break; | ||||||
|     default: |     default: | ||||||
|         LOG_ERROR(HW_Memory, "unknown Write%lu 0x%08X @ 0x%08X", sizeof(data) * 8, (u32)data, addr); |         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
 | /// Initialize hardware
 | ||||||
| void Init() { | void Init() { | ||||||
|     GPU::Init(); |     GPU::Init(); | ||||||
|  |     LCD::Init(); | ||||||
|     LOG_DEBUG(HW, "initialized OK"); |     LOG_DEBUG(HW, "initialized OK"); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -8,8 +8,8 @@ | ||||||
| 
 | 
 | ||||||
| namespace HW { | namespace HW { | ||||||
| 
 | 
 | ||||||
| enum { | /// Beginnings of IO register regions, in the user VA space.
 | ||||||
|     VADDR_IO        = 0x1EC00000, | enum : u32 { | ||||||
|     VADDR_HASH      = 0x1EC01000, |     VADDR_HASH      = 0x1EC01000, | ||||||
|     VADDR_CSND      = 0x1EC03000, |     VADDR_CSND      = 0x1EC03000, | ||||||
|     VADDR_DSP       = 0x1EC40000, |     VADDR_DSP       = 0x1EC40000, | ||||||
|  | @ -25,9 +25,7 @@ enum { | ||||||
|     VADDR_SPI_3     = 0x1EC60000, |     VADDR_SPI_3     = 0x1EC60000, | ||||||
|     VADDR_I2C_3     = 0x1EC61000, |     VADDR_I2C_3     = 0x1EC61000, | ||||||
|     VADDR_MIC       = 0x1EC62000, |     VADDR_MIC       = 0x1EC62000, | ||||||
|     VADDR_PXI       = 0x1EC63000,   // 0xFFFD2000
 |     VADDR_PXI       = 0x1EC63000, | ||||||
|     //VADDR_NTRCARD
 |  | ||||||
|     VADDR_CDMA      = 0xFFFDA000,   // CoreLink DMA-330? Info
 |  | ||||||
|     VADDR_LCD       = 0x1ED02000, |     VADDR_LCD       = 0x1ED02000, | ||||||
|     VADDR_DSP_2     = 0x1ED03000, |     VADDR_DSP_2     = 0x1ED03000, | ||||||
|     VADDR_HASH_2    = 0x1EE01000, |     VADDR_HASH_2    = 0x1EE01000, | ||||||
|  |  | ||||||
							
								
								
									
										66
									
								
								src/core/hw/lcd.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										66
									
								
								src/core/hw/lcd.cpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -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
 | ||||||
							
								
								
									
										88
									
								
								src/core/hw/lcd.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										88
									
								
								src/core/hw/lcd.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -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
 | ||||||
|  | @ -3,6 +3,8 @@ | ||||||
| // Refer to the license.txt file included.
 | // Refer to the license.txt file included.
 | ||||||
| 
 | 
 | ||||||
| #include "core/hw/gpu.h" | #include "core/hw/gpu.h" | ||||||
|  | #include "core/hw/hw.h" | ||||||
|  | #include "core/hw/lcd.h" | ||||||
| #include "core/mem_map.h" | #include "core/mem_map.h" | ||||||
| #include "common/emu_window.h" | #include "common/emu_window.h" | ||||||
| #include "video_core/video_core.h" | #include "video_core/video_core.h" | ||||||
|  | @ -61,16 +63,33 @@ void RendererOpenGL::SwapBuffers() { | ||||||
|     for(int i : {0, 1}) { |     for(int i : {0, 1}) { | ||||||
|         const auto& framebuffer = GPU::g_regs.framebuffer_config[i]; |         const auto& framebuffer = GPU::g_regs.framebuffer_config[i]; | ||||||
| 
 | 
 | ||||||
|         if (textures[i].width != (GLsizei)framebuffer.width || |         // Main LCD (0): 0x1ED02204, Sub LCD (1): 0x1ED02A04
 | ||||||
|             textures[i].height != (GLsizei)framebuffer.height || |         u32 lcd_color_addr = (i == 0) ? LCD_REG_INDEX(color_fill_top) : LCD_REG_INDEX(color_fill_bottom); | ||||||
|             textures[i].format != framebuffer.color_format) { |         lcd_color_addr = HW::VADDR_LCD + 4 * lcd_color_addr; | ||||||
|             // Reallocate texture if the framebuffer size has changed.
 |         LCD::Regs::ColorFill color_fill = {0}; | ||||||
|             // This is expected to not happen very often and hence should not be a
 |         LCD::Read(color_fill.raw, lcd_color_addr); | ||||||
|             // performance problem.
 |  | ||||||
|             ConfigureFramebufferTexture(textures[i], framebuffer); |  | ||||||
|         } |  | ||||||
| 
 | 
 | ||||||
|         LoadFBToActiveGLTexture(GPU::g_regs.framebuffer_config[i], textures[i]); |         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; | ||||||
|  |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     DrawScreens(); |     DrawScreens(); | ||||||
|  | @ -115,10 +134,25 @@ void RendererOpenGL::LoadFBToActiveGLTexture(const GPU::Regs::FramebufferConfig& | ||||||
|     // TODO: Applications could theoretically crash Citra here by specifying too large
 |     // TODO: Applications could theoretically crash Citra here by specifying too large
 | ||||||
|     //       framebuffer sizes. We should make sure that this cannot happen.
 |     //       framebuffer sizes. We should make sure that this cannot happen.
 | ||||||
|     glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, framebuffer.width, framebuffer.height, |     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); |     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); |     glBindTexture(GL_TEXTURE_2D, 0); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -58,6 +58,9 @@ private: | ||||||
|     // Loads framebuffer from emulated memory into the active OpenGL texture.
 |     // Loads framebuffer from emulated memory into the active OpenGL texture.
 | ||||||
|     static void LoadFBToActiveGLTexture(const GPU::Regs::FramebufferConfig& framebuffer, |     static void LoadFBToActiveGLTexture(const GPU::Regs::FramebufferConfig& framebuffer, | ||||||
|                                         const TextureInfo& texture); |                                         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
 |     /// Computes the viewport rectangle
 | ||||||
|     MathUtil::Rectangle<unsigned> GetViewportExtent(); |     MathUtil::Rectangle<unsigned> GetViewportExtent(); | ||||||
|  | @ -72,7 +75,7 @@ private: | ||||||
|     GLuint vertex_array_handle; |     GLuint vertex_array_handle; | ||||||
|     GLuint vertex_buffer_handle; |     GLuint vertex_buffer_handle; | ||||||
|     GLuint program_id; |     GLuint program_id; | ||||||
|     std::array<TextureInfo, 2> textures; |     std::array<TextureInfo, 2> textures;          ///< Textures for top and bottom screens respectively
 | ||||||
|     // Shader uniform location indices
 |     // Shader uniform location indices
 | ||||||
|     GLuint uniform_modelview_matrix; |     GLuint uniform_modelview_matrix; | ||||||
|     GLuint uniform_color_texture; |     GLuint uniform_color_texture; | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue