diff --git a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp index 94530724e9..7cd1d93062 100644 --- a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp +++ b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp @@ -26,14 +26,14 @@ void nvdisp_disp0::flip(u32 buffer_handle, u32 offset, u32 format, u32 width, u3 "Drawing from address %lx offset %08X Width %u Height %u Stride %u Format %u", addr, offset, width, height, stride, format); - using PixelFormat = RendererBase::FramebufferInfo::PixelFormat; + using PixelFormat = Tegra::FramebufferConfig::PixelFormat; using Flags = NVFlinger::BufferQueue::BufferTransformFlags; const bool flip_vertical = static_cast(transform) & static_cast(Flags::FlipV); - const RendererBase::FramebufferInfo framebuffer_info{ + const Tegra::FramebufferConfig framebuffer{ addr, offset, width, height, stride, static_cast(format), flip_vertical}; Core::System::GetInstance().perf_stats.EndGameFrame(); - VideoCore::g_renderer->SwapBuffers(framebuffer_info); + VideoCore::g_renderer->SwapBuffers(framebuffer); } } // namespace Devices diff --git a/src/video_core/gpu.h b/src/video_core/gpu.h index f9a725dee0..f3c5e366a7 100644 --- a/src/video_core/gpu.h +++ b/src/video_core/gpu.h @@ -12,6 +12,35 @@ namespace Tegra { +/** + * Struct describing framebuffer configuration + */ +struct FramebufferConfig { + enum class PixelFormat : u32 { + ABGR8 = 1, + }; + + /** + * Returns the number of bytes per pixel. + */ + static u32 BytesPerPixel(PixelFormat format) { + switch (format) { + case PixelFormat::ABGR8: + return 4; + } + + UNREACHABLE(); + } + + VAddr address; + u32 offset; + u32 width; + u32 height; + u32 stride; + PixelFormat pixel_format; + bool flip_vertical; +}; + namespace Engines { class Fermi2D; class Maxwell3D; diff --git a/src/video_core/rasterizer_interface.h b/src/video_core/rasterizer_interface.h index 6c7bd08268..966e25f347 100644 --- a/src/video_core/rasterizer_interface.h +++ b/src/video_core/rasterizer_interface.h @@ -5,6 +5,7 @@ #pragma once #include "common/common_types.h" +#include "video_core/gpu.h" struct ScreenInfo; @@ -49,7 +50,8 @@ public: } /// Attempt to use a faster method to display the framebuffer to screen - virtual bool AccelerateDisplay(const void* config, PAddr framebuffer_addr, u32 pixel_stride, + virtual bool AccelerateDisplay(const Tegra::FramebufferConfig& framebuffer, + PAddr framebuffer_addr, u32 pixel_stride, ScreenInfo& screen_info) { return false; } diff --git a/src/video_core/renderer_base.h b/src/video_core/renderer_base.h index 532e5b37c8..89a960eaf8 100644 --- a/src/video_core/renderer_base.h +++ b/src/video_core/renderer_base.h @@ -8,6 +8,7 @@ #include #include "common/assert.h" #include "common/common_types.h" +#include "video_core/gpu.h" #include "video_core/rasterizer_interface.h" class EmuWindow; @@ -17,40 +18,10 @@ public: /// Used to reference a framebuffer enum kFramebuffer { kFramebuffer_VirtualXFB = 0, kFramebuffer_EFB, kFramebuffer_Texture }; - /** - * Struct describing framebuffer metadata - * TODO(bunnei): This struct belongs in the GPU code, but we don't have a good place for it yet. - */ - struct FramebufferInfo { - enum class PixelFormat : u32 { - ABGR8 = 1, - }; - - /** - * Returns the number of bytes per pixel. - */ - static u32 BytesPerPixel(PixelFormat format) { - switch (format) { - case PixelFormat::ABGR8: - return 4; - } - - UNREACHABLE(); - } - - VAddr address; - u32 offset; - u32 width; - u32 height; - u32 stride; - PixelFormat pixel_format; - bool flip_vertical; - }; - virtual ~RendererBase() {} /// Swap buffers (render frame) - virtual void SwapBuffers(boost::optional framebuffer_info) = 0; + virtual void SwapBuffers(boost::optional framebuffer) = 0; /** * Set the emulator window to use for renderer diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp index 0aed4b0486..abc6607b0d 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp @@ -226,8 +226,9 @@ bool RasterizerOpenGL::AccelerateFill(const void* config) { return true; } -bool RasterizerOpenGL::AccelerateDisplay(const void* config, PAddr framebuffer_addr, - u32 pixel_stride, ScreenInfo& screen_info) { +bool RasterizerOpenGL::AccelerateDisplay(const Tegra::FramebufferConfig& framebuffer, + PAddr framebuffer_addr, u32 pixel_stride, + ScreenInfo& screen_info) { ASSERT_MSG(false, "Unimplemented"); return true; } diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h index 7a68480d96..8f213404d0 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.h +++ b/src/video_core/renderer_opengl/gl_rasterizer.h @@ -38,8 +38,8 @@ public: bool AccelerateDisplayTransfer(const void* config) override; bool AccelerateTextureCopy(const void* config) override; bool AccelerateFill(const void* config) override; - bool AccelerateDisplay(const void* config, PAddr framebuffer_addr, u32 pixel_stride, - ScreenInfo& screen_info) override; + bool AccelerateDisplay(const Tegra::FramebufferConfig& framebuffer, PAddr framebuffer_addr, + u32 pixel_stride, ScreenInfo& screen_info) override; bool AccelerateDrawBatch(bool is_indexed) override; /// OpenGL shader generated for a given Maxwell register state diff --git a/src/video_core/renderer_opengl/renderer_opengl.cpp b/src/video_core/renderer_opengl/renderer_opengl.cpp index 65d38ade58..2ea5e91e36 100644 --- a/src/video_core/renderer_opengl/renderer_opengl.cpp +++ b/src/video_core/renderer_opengl/renderer_opengl.cpp @@ -98,22 +98,22 @@ RendererOpenGL::RendererOpenGL() = default; RendererOpenGL::~RendererOpenGL() = default; /// Swap buffers (render frame) -void RendererOpenGL::SwapBuffers(boost::optional framebuffer_info) { +void RendererOpenGL::SwapBuffers(boost::optional framebuffer) { // Maintain the rasterizer's state as a priority OpenGLState prev_state = OpenGLState::GetCurState(); state.Apply(); - if (framebuffer_info != boost::none) { - // If framebuffer_info is provided, reload it from memory to a texture - 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) { + if (framebuffer != boost::none) { + // If framebuffer is provided, reload it from memory to a texture + if (screen_info.texture.width != (GLsizei)framebuffer->width || + screen_info.texture.height != (GLsizei)framebuffer->height || + screen_info.texture.pixel_format != framebuffer->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); + ConfigureFramebufferTexture(screen_info.texture, *framebuffer); } - LoadFBToScreenInfo(*framebuffer_info, screen_info); + LoadFBToScreenInfo(*framebuffer, screen_info); } DrawScreens(); @@ -245,43 +245,47 @@ 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 FramebufferInfo& framebuffer_info, +void RendererOpenGL::LoadFBToScreenInfo(const Tegra::FramebufferConfig& framebuffer, 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 u32 bpp{Tegra::FramebufferConfig::BytesPerPixel(framebuffer.pixel_format)}; + const u32 size_in_bytes{framebuffer.stride * framebuffer.height * bpp}; + const VAddr framebuffer_addr{framebuffer.address}; + const size_t pixel_stride{framebuffer.stride / bpp}; - MortonCopyPixels128(framebuffer_info.width, framebuffer_info.height, bpp, 4, - Memory::GetPointer(framebuffer_info.address), gl_framebuffer_data.data(), - true); + // OpenGL only supports specifying a stride in units of pixels, not bytes, unfortunately + ASSERT(pixel_stride * bpp == framebuffer.stride); + + MortonCopyPixels128(framebuffer.width, framebuffer.height, bpp, 4, + Memory::GetPointer(framebuffer.address), gl_framebuffer_data.data(), true); 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.pixel_format); + framebuffer.address, framebuffer.width, framebuffer.height, + (int)framebuffer.pixel_format); // Ensure no bad interactions with GL_UNPACK_ALIGNMENT, which by default // only allows rows to have a memory alignement of 4. - ASSERT(framebuffer_info.stride % 4 == 0); + ASSERT(framebuffer.stride % 4 == 0); - framebuffer_flip_vertical = framebuffer_info.flip_vertical; + framebuffer_flip_vertical = framebuffer.flip_vertical; // 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(0.f, 0.f, 1.f, 1.f); - // Memory::RasterizerFlushRegion(framebuffer_info.address, size_in_bytes); + Rasterizer()->FlushRegion(framebuffer.address, size_in_bytes); state.texture_units[0].texture_2d = screen_info.texture.resource.handle; state.Apply(); glActiveTexture(GL_TEXTURE0); - glPixelStorei(GL_UNPACK_ROW_LENGTH, (GLint)framebuffer_info.stride); + glPixelStorei(GL_UNPACK_ROW_LENGTH, (GLint)framebuffer.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_info.width, framebuffer_info.height, + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, framebuffer.width, framebuffer.height, screen_info.texture.gl_format, screen_info.texture.gl_type, gl_framebuffer_data.data()); @@ -372,14 +376,14 @@ void RendererOpenGL::InitOpenGLObjects() { } void RendererOpenGL::ConfigureFramebufferTexture(TextureInfo& texture, - const FramebufferInfo& framebuffer_info) { + const Tegra::FramebufferConfig& framebuffer) { - texture.width = framebuffer_info.width; - texture.height = framebuffer_info.height; + texture.width = framebuffer.width; + texture.height = framebuffer.height; GLint internal_format; - switch (framebuffer_info.pixel_format) { - case FramebufferInfo::PixelFormat::ABGR8: + switch (framebuffer.pixel_format) { + case Tegra::FramebufferConfig::PixelFormat::ABGR8: // Use RGBA8 and swap in the fragment shader internal_format = GL_RGBA; texture.gl_format = GL_RGBA; diff --git a/src/video_core/renderer_opengl/renderer_opengl.h b/src/video_core/renderer_opengl/renderer_opengl.h index 05bb3c5cf1..bd7c2510fc 100644 --- a/src/video_core/renderer_opengl/renderer_opengl.h +++ b/src/video_core/renderer_opengl/renderer_opengl.h @@ -21,7 +21,7 @@ struct TextureInfo { GLsizei height; GLenum gl_format; GLenum gl_type; - RendererBase::FramebufferInfo::PixelFormat pixel_format; + Tegra::FramebufferConfig::PixelFormat pixel_format; }; /// Structure used for storing information about the display target for each 3DS screen @@ -37,7 +37,7 @@ public: ~RendererOpenGL() override; /// Swap buffers (render frame) - void SwapBuffers(boost::optional framebuffer_info) override; + void SwapBuffers(boost::optional framebuffer) override; /** * Set the emulator window to use for renderer @@ -53,13 +53,14 @@ public: private: void InitOpenGLObjects(); - void ConfigureFramebufferTexture(TextureInfo& texture, const FramebufferInfo& framebuffer_info); + void ConfigureFramebufferTexture(TextureInfo& texture, + const Tegra::FramebufferConfig& framebuffer); 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 FramebufferInfo& framebuffer_info, ScreenInfo& screen_info); + void LoadFBToScreenInfo(const Tegra::FramebufferConfig& framebuffer, ScreenInfo& screen_info); // Fills active OpenGL texture with the given RGBA color. void LoadColorToActiveGLTexture(u8 color_r, u8 color_g, u8 color_b, u8 color_a, const TextureInfo& texture);