summaryrefslogtreecommitdiffstats
path: root/src/video_core/renderer_opengl
diff options
context:
space:
mode:
Diffstat (limited to 'src/video_core/renderer_opengl')
-rw-r--r--src/video_core/renderer_opengl/renderer_opengl.cpp197
-rw-r--r--src/video_core/renderer_opengl/renderer_opengl.h17
2 files changed, 78 insertions, 136 deletions
diff --git a/src/video_core/renderer_opengl/renderer_opengl.cpp b/src/video_core/renderer_opengl/renderer_opengl.cpp
index c481d1d76..de61987a8 100644
--- a/src/video_core/renderer_opengl/renderer_opengl.cpp
+++ b/src/video_core/renderer_opengl/renderer_opengl.cpp
@@ -56,7 +56,9 @@ out vec4 color;
uniform sampler2D color_texture;
void main() {
- color = texture(color_texture, frag_tex_coord);
+ // Swap RGBA -> ABGR so we don't have to do this on the CPU. This needs to change if we have to
+ // support more framebuffer pixel formats.
+ color = texture(color_texture, frag_tex_coord).abgr;
}
)";
@@ -98,44 +100,20 @@ RendererOpenGL::RendererOpenGL() = default;
RendererOpenGL::~RendererOpenGL() = default;
/// Swap buffers (render frame)
-void RendererOpenGL::SwapBuffers() {
+void RendererOpenGL::SwapBuffers(const FramebufferInfo& framebuffer_info) {
// Maintain the rasterizer's state as a priority
OpenGLState prev_state = OpenGLState::GetCurState();
state.Apply();
- for (int i : {0, 1}) {
- const auto& framebuffer = GPU::g_regs.framebuffer_config[i];
-
- // 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,
- screen_infos[i].texture);
-
- // Resize the texture in case the framebuffer size has changed
- screen_infos[i].texture.width = 1;
- screen_infos[i].texture.height = 1;
- } else {
- if (screen_infos[i].texture.width != (GLsizei)framebuffer.width ||
- screen_infos[i].texture.height != (GLsizei)framebuffer.height ||
- screen_infos[i].texture.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(screen_infos[i].texture, framebuffer);
- }
- LoadFBToScreenInfo(framebuffer, screen_infos[i]);
-
- // Resize the texture in case the framebuffer size has changed
- screen_infos[i].texture.width = framebuffer.width;
- screen_infos[i].texture.height = framebuffer.height;
- }
+ if (screen_info.texture.width != (GLsizei)framebuffer_info.width ||
+ screen_info.texture.height != (GLsizei)framebuffer_info.height ||
+ screen_info.texture.pixel_format != framebuffer_info.pixel_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(screen_info.texture, framebuffer_info);
}
+ LoadFBToScreenInfo(framebuffer_info, screen_info);
DrawScreens();
@@ -270,56 +248,48 @@ static void MortonCopyPixels128(u32 width, u32 height, u32 bytes_per_pixel, u32
/**
* Loads framebuffer from emulated memory into the active OpenGL texture.
*/
-void RendererOpenGL::LoadFBToScreenInfo(const GPU::Regs::FramebufferConfig& framebuffer,
+void RendererOpenGL::LoadFBToScreenInfo(const FramebufferInfo& framebuffer_info,
ScreenInfo& screen_info) {
+ const u32 bpp{FramebufferInfo::BytesPerPixel(framebuffer_info.pixel_format)};
+ const u32 size_in_bytes{framebuffer_info.stride * framebuffer_info.height * bpp};
- const PAddr framebuffer_addr =
- framebuffer.active_fb == 0 ? framebuffer.address_left1 : framebuffer.address_left2;
-
- LOG_TRACE(Render_OpenGL, "0x%08x bytes from 0x%08x(%dx%d), fmt %x",
- framebuffer.stride * framebuffer.height, framebuffer_addr, (int)framebuffer.width,
- (int)framebuffer.height, (int)framebuffer.format);
+ MortonCopyPixels128(framebuffer_info.width, framebuffer_info.height, bpp, 4,
+ Memory::GetPointer(framebuffer_info.address), gl_framebuffer_data.data(),
+ true);
- int bpp = GPU::Regs::BytesPerPixel(framebuffer.color_format);
- size_t pixel_stride = framebuffer.stride / bpp;
-
- // OpenGL only supports specifying a stride in units of pixels, not bytes, unfortunately
- ASSERT(pixel_stride * bpp == framebuffer.stride);
+ LOG_TRACE(Render_OpenGL, "0x%08x bytes from 0x%llx(%dx%d), fmt %x", size_in_bytes,
+ framebuffer_info.address, framebuffer_info.width, framebuffer_info.height,
+ (int)framebuffer_info.format);
// Ensure no bad interactions with GL_UNPACK_ALIGNMENT, which by default
// only allows rows to have a memory alignement of 4.
- ASSERT(pixel_stride % 4 == 0);
-
- if (!Rasterizer()->AccelerateDisplay(framebuffer, framebuffer_addr,
- static_cast<u32>(pixel_stride), screen_info)) {
- // Reset the screen info's display texture to its own permanent texture
- screen_info.display_texture = screen_info.texture.resource.handle;
- screen_info.display_texcoords = MathUtil::Rectangle<float>(0.f, 0.f, 1.f, 1.f);
+ ASSERT(framebuffer_info.stride % 4 == 0);
- Memory::RasterizerFlushRegion(framebuffer_addr, framebuffer.stride * framebuffer.height);
+ // Reset the screen info's display texture to its own permanent texture
+ screen_info.display_texture = screen_info.texture.resource.handle;
+ screen_info.display_texcoords = MathUtil::Rectangle<float>(0.f, 0.f, 1.f, 1.f);
- const u8* framebuffer_data = Memory::GetPhysicalPointer(framebuffer_addr);
+ Memory::RasterizerFlushRegion(framebuffer_info.address, size_in_bytes);
- state.texture_units[0].texture_2d = screen_info.texture.resource.handle;
- state.Apply();
+ state.texture_units[0].texture_2d = screen_info.texture.resource.handle;
+ state.Apply();
- glActiveTexture(GL_TEXTURE0);
- glPixelStorei(GL_UNPACK_ROW_LENGTH, (GLint)pixel_stride);
+ glActiveTexture(GL_TEXTURE0);
+ glPixelStorei(GL_UNPACK_ROW_LENGTH, (GLint)framebuffer_info.stride);
- // Update existing texture
- // TODO: Test what happens on hardware when you change the framebuffer dimensions so that
- // they differ from the LCD resolution.
- // 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,
- screen_info.texture.gl_format, screen_info.texture.gl_type,
- framebuffer_data);
+ // Update existing texture
+ // TODO: Test what happens on hardware when you change the framebuffer dimensions so that
+ // they differ from the LCD resolution.
+ // 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_info.width, framebuffer_info.height,
+ screen_info.texture.gl_format, screen_info.texture.gl_type,
+ gl_framebuffer_data.data());
- glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
+ glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
- state.texture_units[0].texture_2d = 0;
- state.Apply();
- }
+ state.texture_units[0].texture_2d = 0;
+ state.Apply();
}
/**
@@ -377,74 +347,43 @@ void RendererOpenGL::InitOpenGLObjects() {
glEnableVertexAttribArray(attrib_position);
glEnableVertexAttribArray(attrib_tex_coord);
- // Allocate textures for each screen
- for (auto& screen_info : screen_infos) {
- screen_info.texture.resource.Create();
+ // Allocate textures for the screen
+ screen_info.texture.resource.Create();
- // Allocation of storage is deferred until the first frame, when we
- // know the framebuffer size.
+ // Allocation of storage is deferred until the first frame, when we
+ // know the framebuffer size.
- state.texture_units[0].texture_2d = screen_info.texture.resource.handle;
- state.Apply();
+ state.texture_units[0].texture_2d = screen_info.texture.resource.handle;
+ state.Apply();
- glActiveTexture(GL_TEXTURE0);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ glActiveTexture(GL_TEXTURE0);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
- screen_info.display_texture = screen_info.texture.resource.handle;
- }
+ screen_info.display_texture = screen_info.texture.resource.handle;
state.texture_units[0].texture_2d = 0;
state.Apply();
}
void RendererOpenGL::ConfigureFramebufferTexture(TextureInfo& texture,
- const GPU::Regs::FramebufferConfig& framebuffer) {
- GPU::Regs::PixelFormat format = framebuffer.color_format;
- GLint internal_format;
+ const FramebufferInfo& framebuffer_info) {
- texture.format = format;
- texture.width = framebuffer.width;
- texture.height = framebuffer.height;
+ texture.width = framebuffer_info.width;
+ texture.height = framebuffer_info.height;
- switch (format) {
- case GPU::Regs::PixelFormat::RGBA8:
+ GLint internal_format;
+ switch (framebuffer_info.pixel_format) {
+ case FramebufferInfo::PixelFormat::ABGR8:
+ // Use RGBA8 and swap in the fragment shader
internal_format = GL_RGBA;
texture.gl_format = GL_RGBA;
texture.gl_type = GL_UNSIGNED_INT_8_8_8_8;
+ gl_framebuffer_data.resize(texture.width * texture.height * 4);
break;
-
- case GPU::Regs::PixelFormat::RGB8:
- // This pixel format uses BGR since GL_UNSIGNED_BYTE specifies byte-order, unlike every
- // specific OpenGL type used in this function using native-endian (that is, little-endian
- // mostly everywhere) for words or half-words.
- // TODO: check how those behave on big-endian processors.
- internal_format = GL_RGB;
- texture.gl_format = GL_BGR;
- texture.gl_type = GL_UNSIGNED_BYTE;
- break;
-
- case GPU::Regs::PixelFormat::RGB565:
- internal_format = GL_RGB;
- texture.gl_format = GL_RGB;
- texture.gl_type = GL_UNSIGNED_SHORT_5_6_5;
- break;
-
- case GPU::Regs::PixelFormat::RGB5A1:
- internal_format = GL_RGBA;
- texture.gl_format = GL_RGBA;
- texture.gl_type = GL_UNSIGNED_SHORT_5_5_5_1;
- break;
-
- case GPU::Regs::PixelFormat::RGBA4:
- internal_format = GL_RGBA;
- texture.gl_format = GL_RGBA;
- texture.gl_type = GL_UNSIGNED_SHORT_4_4_4_4;
- break;
-
default:
UNIMPLEMENTED();
}
@@ -465,10 +404,10 @@ void RendererOpenGL::DrawSingleScreen(const ScreenInfo& screen_info, float x, fl
auto& texcoords = screen_info.display_texcoords;
std::array<ScreenRectVertex, 4> vertices = {{
- ScreenRectVertex(x, y, texcoords.top, texcoords.left),
- ScreenRectVertex(x + w, y, texcoords.bottom, texcoords.left),
- ScreenRectVertex(x, y + h, texcoords.top, texcoords.right),
- ScreenRectVertex(x + w, y + h, texcoords.bottom, texcoords.right),
+ ScreenRectVertex(x, y, texcoords.top, texcoords.right),
+ ScreenRectVertex(x + w, y, texcoords.bottom, texcoords.right),
+ ScreenRectVertex(x, y + h, texcoords.top, texcoords.left),
+ ScreenRectVertex(x + w, y + h, texcoords.bottom, texcoords.left),
}};
state.texture_units[0].texture_2d = screen_info.display_texture;
@@ -500,8 +439,8 @@ void RendererOpenGL::DrawScreens() {
glActiveTexture(GL_TEXTURE0);
glUniform1i(uniform_color_texture, 0);
- DrawSingleScreen(screen_infos[0], (float)screen.left, (float)screen.top,
- (float)screen.GetWidth(), (float)screen.GetHeight());
+ DrawSingleScreen(screen_info, (float)screen.left, (float)screen.top, (float)screen.GetWidth(),
+ (float)screen.GetHeight());
m_current_frame++;
}
diff --git a/src/video_core/renderer_opengl/renderer_opengl.h b/src/video_core/renderer_opengl/renderer_opengl.h
index 111b78466..9d2bb8423 100644
--- a/src/video_core/renderer_opengl/renderer_opengl.h
+++ b/src/video_core/renderer_opengl/renderer_opengl.h
@@ -4,7 +4,7 @@
#pragma once
-#include <array>
+#include <vector>
#include <glad/glad.h>
#include "common/common_types.h"
#include "common/math_util.h"
@@ -20,9 +20,9 @@ struct TextureInfo {
OGLTexture resource;
GLsizei width;
GLsizei height;
- GPU::Regs::PixelFormat format;
GLenum gl_format;
GLenum gl_type;
+ RendererBase::FramebufferInfo::PixelFormat pixel_format;
};
/// Structure used for storing information about the display target for each 3DS screen
@@ -38,7 +38,7 @@ public:
~RendererOpenGL() override;
/// Swap buffers (render frame)
- void SwapBuffers() override;
+ void SwapBuffers(const FramebufferInfo& framebuffer_info) override;
/**
* Set the emulator window to use for renderer
@@ -55,13 +55,13 @@ public:
private:
void InitOpenGLObjects();
void ConfigureFramebufferTexture(TextureInfo& texture,
- const GPU::Regs::FramebufferConfig& framebuffer);
+ const FramebufferInfo& framebuffer_info);
void DrawScreens();
void DrawSingleScreen(const ScreenInfo& screen_info, float x, float y, float w, float h);
void UpdateFramerate();
// Loads framebuffer from emulated memory into the display information structure
- void LoadFBToScreenInfo(const GPU::Regs::FramebufferConfig& framebuffer,
+ void LoadFBToScreenInfo(const FramebufferInfo& framebuffer_info,
ScreenInfo& screen_info);
// Fills active OpenGL texture with the given RGB color.
void LoadColorToActiveGLTexture(u8 color_r, u8 color_g, u8 color_b, const TextureInfo& texture);
@@ -75,8 +75,11 @@ private:
OGLBuffer vertex_buffer;
OGLShader shader;
- /// Display information for top and bottom screens respectively
- std::array<ScreenInfo, 2> screen_infos;
+ /// Display information for Switch screen
+ ScreenInfo screen_info;
+
+ /// OpenGL framebuffer data
+ std::vector<u8> gl_framebuffer_data;
// Shader uniform location indices
GLuint uniform_modelview_matrix;