video_core: Move FramebufferInfo to FramebufferConfig in GPU.

This commit is contained in:
bunnei 2018-03-22 21:04:30 -04:00
parent c6362543d4
commit bfe45774f1
8 changed files with 77 additions and 69 deletions

View File

@ -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, "Drawing from address %lx offset %08X Width %u Height %u Stride %u Format %u", addr,
offset, width, height, stride, format); offset, width, height, stride, format);
using PixelFormat = RendererBase::FramebufferInfo::PixelFormat; using PixelFormat = Tegra::FramebufferConfig::PixelFormat;
using Flags = NVFlinger::BufferQueue::BufferTransformFlags; using Flags = NVFlinger::BufferQueue::BufferTransformFlags;
const bool flip_vertical = static_cast<u32>(transform) & static_cast<u32>(Flags::FlipV); const bool flip_vertical = static_cast<u32>(transform) & static_cast<u32>(Flags::FlipV);
const RendererBase::FramebufferInfo framebuffer_info{ const Tegra::FramebufferConfig framebuffer{
addr, offset, width, height, stride, static_cast<PixelFormat>(format), flip_vertical}; addr, offset, width, height, stride, static_cast<PixelFormat>(format), flip_vertical};
Core::System::GetInstance().perf_stats.EndGameFrame(); Core::System::GetInstance().perf_stats.EndGameFrame();
VideoCore::g_renderer->SwapBuffers(framebuffer_info); VideoCore::g_renderer->SwapBuffers(framebuffer);
} }
} // namespace Devices } // namespace Devices

View File

@ -12,6 +12,35 @@
namespace Tegra { 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 { namespace Engines {
class Fermi2D; class Fermi2D;
class Maxwell3D; class Maxwell3D;

View File

@ -5,6 +5,7 @@
#pragma once #pragma once
#include "common/common_types.h" #include "common/common_types.h"
#include "video_core/gpu.h"
struct ScreenInfo; struct ScreenInfo;
@ -49,7 +50,8 @@ public:
} }
/// Attempt to use a faster method to display the framebuffer to screen /// 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) { ScreenInfo& screen_info) {
return false; return false;
} }

View File

@ -8,6 +8,7 @@
#include <boost/optional.hpp> #include <boost/optional.hpp>
#include "common/assert.h" #include "common/assert.h"
#include "common/common_types.h" #include "common/common_types.h"
#include "video_core/gpu.h"
#include "video_core/rasterizer_interface.h" #include "video_core/rasterizer_interface.h"
class EmuWindow; class EmuWindow;
@ -17,40 +18,10 @@ public:
/// Used to reference a framebuffer /// Used to reference a framebuffer
enum kFramebuffer { kFramebuffer_VirtualXFB = 0, kFramebuffer_EFB, kFramebuffer_Texture }; 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() {} virtual ~RendererBase() {}
/// Swap buffers (render frame) /// Swap buffers (render frame)
virtual void SwapBuffers(boost::optional<const FramebufferInfo&> framebuffer_info) = 0; virtual void SwapBuffers(boost::optional<const Tegra::FramebufferConfig&> framebuffer) = 0;
/** /**
* Set the emulator window to use for renderer * Set the emulator window to use for renderer

View File

@ -226,8 +226,9 @@ bool RasterizerOpenGL::AccelerateFill(const void* config) {
return true; return true;
} }
bool RasterizerOpenGL::AccelerateDisplay(const void* config, PAddr framebuffer_addr, bool RasterizerOpenGL::AccelerateDisplay(const Tegra::FramebufferConfig& framebuffer,
u32 pixel_stride, ScreenInfo& screen_info) { PAddr framebuffer_addr, u32 pixel_stride,
ScreenInfo& screen_info) {
ASSERT_MSG(false, "Unimplemented"); ASSERT_MSG(false, "Unimplemented");
return true; return true;
} }

View File

@ -38,8 +38,8 @@ public:
bool AccelerateDisplayTransfer(const void* config) override; bool AccelerateDisplayTransfer(const void* config) override;
bool AccelerateTextureCopy(const void* config) override; bool AccelerateTextureCopy(const void* config) override;
bool AccelerateFill(const void* config) override; bool AccelerateFill(const void* config) override;
bool AccelerateDisplay(const void* config, PAddr framebuffer_addr, u32 pixel_stride, bool AccelerateDisplay(const Tegra::FramebufferConfig& framebuffer, PAddr framebuffer_addr,
ScreenInfo& screen_info) override; u32 pixel_stride, ScreenInfo& screen_info) override;
bool AccelerateDrawBatch(bool is_indexed) override; bool AccelerateDrawBatch(bool is_indexed) override;
/// OpenGL shader generated for a given Maxwell register state /// OpenGL shader generated for a given Maxwell register state

View File

@ -98,22 +98,22 @@ RendererOpenGL::RendererOpenGL() = default;
RendererOpenGL::~RendererOpenGL() = default; RendererOpenGL::~RendererOpenGL() = default;
/// Swap buffers (render frame) /// Swap buffers (render frame)
void RendererOpenGL::SwapBuffers(boost::optional<const FramebufferInfo&> framebuffer_info) { void RendererOpenGL::SwapBuffers(boost::optional<const Tegra::FramebufferConfig&> framebuffer) {
// Maintain the rasterizer's state as a priority // Maintain the rasterizer's state as a priority
OpenGLState prev_state = OpenGLState::GetCurState(); OpenGLState prev_state = OpenGLState::GetCurState();
state.Apply(); state.Apply();
if (framebuffer_info != boost::none) { if (framebuffer != boost::none) {
// If framebuffer_info is provided, reload it from memory to a texture // If framebuffer is provided, reload it from memory to a texture
if (screen_info.texture.width != (GLsizei)framebuffer_info->width || if (screen_info.texture.width != (GLsizei)framebuffer->width ||
screen_info.texture.height != (GLsizei)framebuffer_info->height || screen_info.texture.height != (GLsizei)framebuffer->height ||
screen_info.texture.pixel_format != framebuffer_info->pixel_format) { screen_info.texture.pixel_format != framebuffer->pixel_format) {
// Reallocate texture if the framebuffer size has changed. // Reallocate texture if the framebuffer size has changed.
// This is expected to not happen very often and hence should not be a // This is expected to not happen very often and hence should not be a
// performance problem. // performance problem.
ConfigureFramebufferTexture(screen_info.texture, *framebuffer_info); ConfigureFramebufferTexture(screen_info.texture, *framebuffer);
} }
LoadFBToScreenInfo(*framebuffer_info, screen_info); LoadFBToScreenInfo(*framebuffer, screen_info);
} }
DrawScreens(); 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. * 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) { ScreenInfo& screen_info) {
const u32 bpp{FramebufferInfo::BytesPerPixel(framebuffer_info.pixel_format)}; const u32 bpp{Tegra::FramebufferConfig::BytesPerPixel(framebuffer.pixel_format)};
const u32 size_in_bytes{framebuffer_info.stride * framebuffer_info.height * bpp}; 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, // OpenGL only supports specifying a stride in units of pixels, not bytes, unfortunately
Memory::GetPointer(framebuffer_info.address), gl_framebuffer_data.data(), ASSERT(pixel_stride * bpp == framebuffer.stride);
true);
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, 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, framebuffer.address, framebuffer.width, framebuffer.height,
(int)framebuffer_info.pixel_format); (int)framebuffer.pixel_format);
// Ensure no bad interactions with GL_UNPACK_ALIGNMENT, which by default // Ensure no bad interactions with GL_UNPACK_ALIGNMENT, which by default
// only allows rows to have a memory alignement of 4. // 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 // Reset the screen info's display texture to its own permanent texture
screen_info.display_texture = screen_info.texture.resource.handle; screen_info.display_texture = screen_info.texture.resource.handle;
screen_info.display_texcoords = MathUtil::Rectangle<float>(0.f, 0.f, 1.f, 1.f); screen_info.display_texcoords = MathUtil::Rectangle<float>(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.texture_units[0].texture_2d = screen_info.texture.resource.handle;
state.Apply(); state.Apply();
glActiveTexture(GL_TEXTURE0); glActiveTexture(GL_TEXTURE0);
glPixelStorei(GL_UNPACK_ROW_LENGTH, (GLint)framebuffer_info.stride); glPixelStorei(GL_UNPACK_ROW_LENGTH, (GLint)framebuffer.stride);
// Update existing texture // Update existing texture
// TODO: Test what happens on hardware when you change the framebuffer dimensions so that // TODO: Test what happens on hardware when you change the framebuffer dimensions so that
// they differ from the LCD resolution. // they differ from the LCD resolution.
// 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_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, screen_info.texture.gl_format, screen_info.texture.gl_type,
gl_framebuffer_data.data()); gl_framebuffer_data.data());
@ -372,14 +376,14 @@ void RendererOpenGL::InitOpenGLObjects() {
} }
void RendererOpenGL::ConfigureFramebufferTexture(TextureInfo& texture, void RendererOpenGL::ConfigureFramebufferTexture(TextureInfo& texture,
const FramebufferInfo& framebuffer_info) { const Tegra::FramebufferConfig& framebuffer) {
texture.width = framebuffer_info.width; texture.width = framebuffer.width;
texture.height = framebuffer_info.height; texture.height = framebuffer.height;
GLint internal_format; GLint internal_format;
switch (framebuffer_info.pixel_format) { switch (framebuffer.pixel_format) {
case FramebufferInfo::PixelFormat::ABGR8: case Tegra::FramebufferConfig::PixelFormat::ABGR8:
// Use RGBA8 and swap in the fragment shader // Use RGBA8 and swap in the fragment shader
internal_format = GL_RGBA; internal_format = GL_RGBA;
texture.gl_format = GL_RGBA; texture.gl_format = GL_RGBA;

View File

@ -21,7 +21,7 @@ struct TextureInfo {
GLsizei height; GLsizei height;
GLenum gl_format; GLenum gl_format;
GLenum gl_type; 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 /// Structure used for storing information about the display target for each 3DS screen
@ -37,7 +37,7 @@ public:
~RendererOpenGL() override; ~RendererOpenGL() override;
/// Swap buffers (render frame) /// Swap buffers (render frame)
void SwapBuffers(boost::optional<const FramebufferInfo&> framebuffer_info) override; void SwapBuffers(boost::optional<const Tegra::FramebufferConfig&> framebuffer) override;
/** /**
* Set the emulator window to use for renderer * Set the emulator window to use for renderer
@ -53,13 +53,14 @@ public:
private: private:
void InitOpenGLObjects(); void InitOpenGLObjects();
void ConfigureFramebufferTexture(TextureInfo& texture, const FramebufferInfo& framebuffer_info); void ConfigureFramebufferTexture(TextureInfo& texture,
const Tegra::FramebufferConfig& framebuffer);
void DrawScreens(); void DrawScreens();
void DrawSingleScreen(const ScreenInfo& screen_info, float x, float y, float w, float h); void DrawSingleScreen(const ScreenInfo& screen_info, float x, float y, float w, float h);
void UpdateFramerate(); void UpdateFramerate();
// Loads framebuffer from emulated memory into the display information structure // 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. // Fills active OpenGL texture with the given RGBA color.
void LoadColorToActiveGLTexture(u8 color_r, u8 color_g, u8 color_b, u8 color_a, void LoadColorToActiveGLTexture(u8 color_r, u8 color_g, u8 color_b, u8 color_a,
const TextureInfo& texture); const TextureInfo& texture);