mirror of https://git.suyu.dev/suyu/suyu
video_core: Move FramebufferInfo to FramebufferConfig in GPU.
This commit is contained in:
parent
c6362543d4
commit
bfe45774f1
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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);
|
||||||
|
|
Loading…
Reference in New Issue