summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/core/hw/gpu.h19
-rw-r--r--src/video_core/renderer_opengl/renderer_opengl.cpp74
-rw-r--r--src/video_core/renderer_opengl/renderer_opengl.h5
3 files changed, 86 insertions, 12 deletions
diff --git a/src/core/hw/gpu.h b/src/core/hw/gpu.h
index 7c3a17ee5..9fd694f65 100644
--- a/src/core/hw/gpu.h
+++ b/src/core/hw/gpu.h
@@ -53,6 +53,7 @@ struct Regs {
53 "Structure size and register block length don't match") 53 "Structure size and register block length don't match")
54#endif 54#endif
55 55
56 // All of those formats are described in reverse byte order, since the 3DS is little-endian.
56 enum class PixelFormat : u32 { 57 enum class PixelFormat : u32 {
57 RGBA8 = 0, 58 RGBA8 = 0,
58 RGB8 = 1, 59 RGB8 = 1,
@@ -61,6 +62,24 @@ struct Regs {
61 RGBA4 = 4, 62 RGBA4 = 4,
62 }; 63 };
63 64
65 /**
66 * Returns the number of bytes per pixel.
67 */
68 static int BytesPerPixel(PixelFormat format) {
69 switch (format) {
70 case PixelFormat::RGBA8:
71 return 4;
72 case PixelFormat::RGB8:
73 return 3;
74 case PixelFormat::RGB565:
75 case PixelFormat::RGB5A1:
76 case PixelFormat::RGBA4:
77 return 2;
78 default:
79 UNIMPLEMENTED();
80 }
81 }
82
64 INSERT_PADDING_WORDS(0x4); 83 INSERT_PADDING_WORDS(0x4);
65 84
66 struct { 85 struct {
diff --git a/src/video_core/renderer_opengl/renderer_opengl.cpp b/src/video_core/renderer_opengl/renderer_opengl.cpp
index 735c0cf45..272695174 100644
--- a/src/video_core/renderer_opengl/renderer_opengl.cpp
+++ b/src/video_core/renderer_opengl/renderer_opengl.cpp
@@ -61,15 +61,13 @@ void RendererOpenGL::SwapBuffers() {
61 for(int i : {0, 1}) { 61 for(int i : {0, 1}) {
62 const auto& framebuffer = GPU::g_regs.framebuffer_config[i]; 62 const auto& framebuffer = GPU::g_regs.framebuffer_config[i];
63 63
64 if (textures[i].width != (GLsizei)framebuffer.width || textures[i].height != (GLsizei)framebuffer.height) { 64 if (textures[i].width != (GLsizei)framebuffer.width ||
65 textures[i].height != (GLsizei)framebuffer.height ||
66 textures[i].format != framebuffer.color_format) {
65 // Reallocate texture if the framebuffer size has changed. 67 // Reallocate texture if the framebuffer size has changed.
66 // This is expected to not happen very often and hence should not be a 68 // This is expected to not happen very often and hence should not be a
67 // performance problem. 69 // performance problem.
68 glBindTexture(GL_TEXTURE_2D, textures[i].handle); 70 ConfigureFramebufferTexture(textures[i], framebuffer);
69 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, framebuffer.width, framebuffer.height, 0,
70 GL_BGR, GL_UNSIGNED_BYTE, nullptr);
71 textures[i].width = framebuffer.width;
72 textures[i].height = framebuffer.height;
73 } 71 }
74 72
75 LoadFBToActiveGLTexture(GPU::g_regs.framebuffer_config[i], textures[i]); 73 LoadFBToActiveGLTexture(GPU::g_regs.framebuffer_config[i], textures[i]);
@@ -98,13 +96,12 @@ void RendererOpenGL::LoadFBToActiveGLTexture(const GPU::Regs::FramebufferConfig&
98 96
99 const u8* framebuffer_data = Memory::GetPointer(framebuffer_vaddr); 97 const u8* framebuffer_data = Memory::GetPointer(framebuffer_vaddr);
100 98
101 // TODO: Handle other pixel formats 99 int bpp = GPU::Regs::BytesPerPixel(framebuffer.color_format);
102 ASSERT_MSG(framebuffer.color_format == GPU::Regs::PixelFormat::RGB8, 100 size_t pixel_stride = framebuffer.stride / bpp;
103 "Unsupported 3DS pixel format.");
104 101
105 size_t pixel_stride = framebuffer.stride / 3;
106 // OpenGL only supports specifying a stride in units of pixels, not bytes, unfortunately 102 // OpenGL only supports specifying a stride in units of pixels, not bytes, unfortunately
107 ASSERT(pixel_stride * 3 == framebuffer.stride); 103 ASSERT(pixel_stride * bpp == framebuffer.stride);
104
108 // Ensure no bad interactions with GL_UNPACK_ALIGNMENT, which by default 105 // Ensure no bad interactions with GL_UNPACK_ALIGNMENT, which by default
109 // only allows rows to have a memory alignement of 4. 106 // only allows rows to have a memory alignement of 4.
110 ASSERT(pixel_stride % 4 == 0); 107 ASSERT(pixel_stride % 4 == 0);
@@ -118,7 +115,7 @@ void RendererOpenGL::LoadFBToActiveGLTexture(const GPU::Regs::FramebufferConfig&
118 // TODO: Applications could theoretically crash Citra here by specifying too large 115 // TODO: Applications could theoretically crash Citra here by specifying too large
119 // framebuffer sizes. We should make sure that this cannot happen. 116 // framebuffer sizes. We should make sure that this cannot happen.
120 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, framebuffer.width, framebuffer.height, 117 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, framebuffer.width, framebuffer.height,
121 GL_BGR, GL_UNSIGNED_BYTE, framebuffer_data); 118 texture.gl_format, texture.gl_type, framebuffer_data);
122 119
123 glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); 120 glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
124 121
@@ -171,6 +168,59 @@ void RendererOpenGL::InitOpenGLObjects() {
171 glBindTexture(GL_TEXTURE_2D, 0); 168 glBindTexture(GL_TEXTURE_2D, 0);
172} 169}
173 170
171void RendererOpenGL::ConfigureFramebufferTexture(TextureInfo& texture,
172 const GPU::Regs::FramebufferConfig& framebuffer) {
173 GPU::Regs::PixelFormat format = framebuffer.color_format;
174 GLint internal_format;
175
176 texture.format = format;
177 texture.width = framebuffer.width;
178 texture.height = framebuffer.height;
179
180 switch (format) {
181 case GPU::Regs::PixelFormat::RGBA8:
182 internal_format = GL_RGBA;
183 texture.gl_format = GL_RGBA;
184 texture.gl_type = GL_UNSIGNED_INT_8_8_8_8;
185 break;
186
187 case GPU::Regs::PixelFormat::RGB8:
188 // This pixel format uses BGR since GL_UNSIGNED_BYTE specifies byte-order, unlike every
189 // specific OpenGL type used in this function using native-endian (that is, little-endian
190 // mostly everywhere) for words or half-words.
191 // TODO: check how those behave on big-endian processors.
192 internal_format = GL_RGB;
193 texture.gl_format = GL_BGR;
194 texture.gl_type = GL_UNSIGNED_BYTE;
195 break;
196
197 case GPU::Regs::PixelFormat::RGB565:
198 internal_format = GL_RGB;
199 texture.gl_format = GL_RGB;
200 texture.gl_type = GL_UNSIGNED_SHORT_5_6_5;
201 break;
202
203 case GPU::Regs::PixelFormat::RGB5A1:
204 internal_format = GL_RGBA;
205 texture.gl_format = GL_RGBA;
206 texture.gl_type = GL_UNSIGNED_SHORT_5_5_5_1;
207 break;
208
209 case GPU::Regs::PixelFormat::RGBA4:
210 internal_format = GL_RGBA;
211 texture.gl_format = GL_RGBA;
212 texture.gl_type = GL_UNSIGNED_SHORT_4_4_4_4;
213 break;
214
215 default:
216 UNIMPLEMENTED();
217 }
218
219 glBindTexture(GL_TEXTURE_2D, texture.handle);
220 glTexImage2D(GL_TEXTURE_2D, 0, internal_format, texture.width, texture.height, 0,
221 texture.gl_format, texture.gl_type, nullptr);
222}
223
174/** 224/**
175 * Draws a single texture to the emulator window, rotating the texture to correct for the 3DS's LCD rotation. 225 * Draws a single texture to the emulator window, rotating the texture to correct for the 3DS's LCD rotation.
176 */ 226 */
diff --git a/src/video_core/renderer_opengl/renderer_opengl.h b/src/video_core/renderer_opengl/renderer_opengl.h
index cf78c1e77..bcabab557 100644
--- a/src/video_core/renderer_opengl/renderer_opengl.h
+++ b/src/video_core/renderer_opengl/renderer_opengl.h
@@ -43,9 +43,14 @@ private:
43 GLuint handle; 43 GLuint handle;
44 GLsizei width; 44 GLsizei width;
45 GLsizei height; 45 GLsizei height;
46 GPU::Regs::PixelFormat format;
47 GLenum gl_format;
48 GLenum gl_type;
46 }; 49 };
47 50
48 void InitOpenGLObjects(); 51 void InitOpenGLObjects();
52 static void ConfigureFramebufferTexture(TextureInfo& texture,
53 const GPU::Regs::FramebufferConfig& framebuffer);
49 void DrawScreens(); 54 void DrawScreens();
50 void DrawSingleScreenRotated(const TextureInfo& texture, float x, float y, float w, float h); 55 void DrawSingleScreenRotated(const TextureInfo& texture, float x, float y, float w, float h);
51 void UpdateFramerate(); 56 void UpdateFramerate();