Compare commits

...

2 Commits

10 changed files with 231 additions and 80 deletions

View File

@@ -36,6 +36,8 @@ add_library(video_core STATIC
renderer_base.h
renderer_opengl/gl_buffer_cache.cpp
renderer_opengl/gl_buffer_cache.h
renderer_opengl/gl_framebuffer_cache.cpp
renderer_opengl/gl_framebuffer_cache.h
renderer_opengl/gl_global_cache.cpp
renderer_opengl/gl_global_cache.h
renderer_opengl/gl_primitive_assembler.cpp

View File

@@ -0,0 +1,97 @@
// Copyright 2019 yuzu Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include <tuple>
#include "common/cityhash.h"
#include "common/scope_exit.h"
#include "video_core/engines/maxwell_3d.h"
#include "video_core/renderer_opengl/gl_framebuffer_cache.h"
#include "video_core/renderer_opengl/gl_state.h"
namespace OpenGL {
using Maxwell = Tegra::Engines::Maxwell3D::Regs;
std::size_t FramebufferCacheKey::Hash() const {
static_assert(sizeof(*this) % sizeof(u64) == 0, "Unaligned struct");
return static_cast<std::size_t>(
Common::CityHash64(reinterpret_cast<const char*>(this), sizeof(*this)));
}
bool FramebufferCacheKey::operator==(const FramebufferCacheKey& rhs) const {
return std::tie(is_single_buffer, stencil_enable, color_attachments, colors, colors_count,
zeta) == std::tie(rhs.is_single_buffer, rhs.stencil_enable,
rhs.color_attachments, rhs.colors, rhs.colors_count,
rhs.zeta);
}
FramebufferCacheOpenGLImpl::FramebufferCacheOpenGLImpl() = default;
FramebufferCacheOpenGLImpl::~FramebufferCacheOpenGLImpl() = default;
GLuint FramebufferCacheOpenGLImpl::GetFramebuffer(const FramebufferCacheKey& key) {
const auto [entry, is_cache_miss] = cache.try_emplace(key);
auto& framebuffer{entry->second};
if (is_cache_miss) {
framebuffer = CreateFramebuffer(key);
}
return framebuffer.handle;
}
void FramebufferCacheOpenGLImpl::InvalidateTexture(GLuint texture) {
for (auto it = cache.begin(); it != cache.end();) {
it = TryTextureInvalidation(texture, it);
}
}
OGLFramebuffer FramebufferCacheOpenGLImpl::CreateFramebuffer(const FramebufferCacheKey& key) {
OGLFramebuffer framebuffer;
framebuffer.Create();
// TODO(Rodrigo): Use DSA here after Nvidia fixes their framebuffer DSA bugs.
local_state.draw.draw_framebuffer = framebuffer.handle;
local_state.ApplyFramebufferState();
if (key.is_single_buffer) {
if (key.color_attachments[0] != GL_NONE) {
glFramebufferTexture(GL_DRAW_FRAMEBUFFER, key.color_attachments[0], key.colors[0], 0);
}
glDrawBuffer(key.color_attachments[0]);
} else {
for (std::size_t index = 0; index < Maxwell::NumRenderTargets; ++index) {
if (key.colors[index]) {
glFramebufferTexture(GL_DRAW_FRAMEBUFFER,
GL_COLOR_ATTACHMENT0 + static_cast<GLenum>(index),
key.colors[index], 0);
}
}
glDrawBuffers(key.colors_count, key.color_attachments.data());
}
if (key.zeta) {
const GLenum zeta_attachment =
key.stencil_enable ? GL_DEPTH_STENCIL_ATTACHMENT : GL_DEPTH_ATTACHMENT;
glFramebufferTexture(GL_DRAW_FRAMEBUFFER, zeta_attachment, key.zeta, 0);
}
return framebuffer;
}
FramebufferCacheOpenGLImpl::CacheType::iterator FramebufferCacheOpenGLImpl::TryTextureInvalidation(
GLuint texture, CacheType::iterator it) {
const auto& [key, framebuffer] = *it;
const std::size_t count = key.is_single_buffer ? 1 : static_cast<std::size_t>(key.colors_count);
for (std::size_t i = 0; i < count; ++i) {
if (texture == key.colors[i]) {
return cache.erase(it);
}
}
if (texture == key.zeta) {
return cache.erase(it);
}
return ++it;
}
} // namespace OpenGL

View File

@@ -0,0 +1,82 @@
// Copyright 2019 yuzu Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include <array>
#include <cstddef>
#include <memory>
#include <unordered_map>
#include <glad/glad.h>
#include "common/common_types.h"
#include "video_core/engines/maxwell_3d.h"
#include "video_core/renderer_opengl/gl_resource_manager.h"
#include "video_core/renderer_opengl/gl_state.h"
namespace OpenGL {
class FramebufferCacheOpenGLImpl;
using FramebufferCacheOpenGL = std::shared_ptr<FramebufferCacheOpenGLImpl>;
struct alignas(sizeof(u64)) FramebufferCacheKey {
bool is_single_buffer = false;
bool stencil_enable = false;
std::array<GLenum, Tegra::Engines::Maxwell3D::Regs::NumRenderTargets> color_attachments{};
std::array<GLuint, Tegra::Engines::Maxwell3D::Regs::NumRenderTargets> colors{};
u32 colors_count = 0;
GLuint zeta = 0;
std::size_t Hash() const;
bool operator==(const FramebufferCacheKey& rhs) const;
bool operator!=(const FramebufferCacheKey& rhs) const {
return !operator==(rhs);
}
};
} // namespace OpenGL
namespace std {
template <>
struct hash<OpenGL::FramebufferCacheKey> {
std::size_t operator()(const OpenGL::FramebufferCacheKey& k) const noexcept {
return k.Hash();
}
};
} // namespace std
namespace OpenGL {
class FramebufferCacheOpenGLImpl {
public:
FramebufferCacheOpenGLImpl();
~FramebufferCacheOpenGLImpl();
/// Returns and caches a framebuffer with the passed arguments.
GLuint GetFramebuffer(const FramebufferCacheKey& key);
/// Invalidates a texture inside the cache.
void InvalidateTexture(GLuint texture);
private:
using CacheType = std::unordered_map<FramebufferCacheKey, OGLFramebuffer>;
/// Returns a new framebuffer from the passed arguments.
OGLFramebuffer CreateFramebuffer(const FramebufferCacheKey& key);
/// Attempts to destroy the framebuffer cache entry in `it` and returns the next one.
CacheType::iterator TryTextureInvalidation(GLuint texture, CacheType::iterator it);
OpenGLState local_state;
CacheType cache;
};
} // namespace OpenGL

View File

@@ -80,29 +80,11 @@ struct DrawParameters {
}
};
struct FramebufferCacheKey {
bool is_single_buffer = false;
bool stencil_enable = false;
std::array<GLenum, Maxwell::NumRenderTargets> color_attachments{};
std::array<GLuint, Tegra::Engines::Maxwell3D::Regs::NumRenderTargets> colors{};
u32 colors_count = 0;
GLuint zeta = 0;
auto Tie() const {
return std::tie(is_single_buffer, stencil_enable, color_attachments, colors, colors_count,
zeta);
}
bool operator<(const FramebufferCacheKey& rhs) const {
return Tie() < rhs.Tie();
}
};
RasterizerOpenGL::RasterizerOpenGL(Core::System& system, ScreenInfo& info)
: res_cache{*this}, shader_cache{*this, system}, global_cache{*this}, system{system},
screen_info{info}, buffer_cache(*this, STREAM_BUFFER_SIZE) {
: framebuffer_cache{std::make_shared<FramebufferCacheOpenGLImpl>()},
res_cache{*this, framebuffer_cache}, shader_cache{*this, system},
global_cache{*this}, system{system}, screen_info{info},
buffer_cache(*this, STREAM_BUFFER_SIZE) {
// Create sampler objects
for (std::size_t i = 0; i < texture_samplers.size(); ++i) {
texture_samplers[i].Create();
@@ -373,44 +355,6 @@ void RasterizerOpenGL::SetupShaders(GLenum primitive_mode) {
gpu.dirty_flags.shaders = false;
}
void RasterizerOpenGL::SetupCachedFramebuffer(const FramebufferCacheKey& fbkey,
OpenGLState& current_state) {
const auto [entry, is_cache_miss] = framebuffer_cache.try_emplace(fbkey);
auto& framebuffer = entry->second;
if (is_cache_miss)
framebuffer.Create();
current_state.draw.draw_framebuffer = framebuffer.handle;
current_state.ApplyFramebufferState();
if (!is_cache_miss)
return;
if (fbkey.is_single_buffer) {
if (fbkey.color_attachments[0] != GL_NONE) {
glFramebufferTexture(GL_DRAW_FRAMEBUFFER, fbkey.color_attachments[0], fbkey.colors[0],
0);
}
glDrawBuffer(fbkey.color_attachments[0]);
} else {
for (std::size_t index = 0; index < Maxwell::NumRenderTargets; ++index) {
if (fbkey.colors[index]) {
glFramebufferTexture(GL_DRAW_FRAMEBUFFER,
GL_COLOR_ATTACHMENT0 + static_cast<GLenum>(index),
fbkey.colors[index], 0);
}
}
glDrawBuffers(fbkey.colors_count, fbkey.color_attachments.data());
}
if (fbkey.zeta) {
GLenum zeta_attachment =
fbkey.stencil_enable ? GL_DEPTH_STENCIL_ATTACHMENT : GL_DEPTH_ATTACHMENT;
glFramebufferTexture(GL_DRAW_FRAMEBUFFER, zeta_attachment, fbkey.zeta, 0);
}
}
std::size_t RasterizerOpenGL::CalculateVertexArraysSize() const {
const auto& regs = system.GPU().Maxwell3D().regs;
@@ -570,7 +514,7 @@ std::pair<bool, bool> RasterizerOpenGL::ConfigureFramebuffers(
depth_surface->GetSurfaceParams().type == SurfaceType::DepthStencil;
}
SetupCachedFramebuffer(fbkey, current_state);
current_state.draw.draw_framebuffer = framebuffer_cache->GetFramebuffer(fbkey);
SyncViewport(current_state);
return current_depth_stencil_usage = {static_cast<bool>(depth_surface), fbkey.stencil_enable};

View File

@@ -24,6 +24,7 @@
#include "video_core/rasterizer_cache.h"
#include "video_core/rasterizer_interface.h"
#include "video_core/renderer_opengl/gl_buffer_cache.h"
#include "video_core/renderer_opengl/gl_framebuffer_cache.h"
#include "video_core/renderer_opengl/gl_global_cache.h"
#include "video_core/renderer_opengl/gl_primitive_assembler.h"
#include "video_core/renderer_opengl/gl_rasterizer_cache.h"
@@ -46,7 +47,6 @@ namespace OpenGL {
struct ScreenInfo;
struct DrawParameters;
struct FramebufferCacheKey;
class RasterizerOpenGL : public VideoCore::RasterizerInterface {
public:
@@ -209,6 +209,7 @@ private:
OpenGLState state;
FramebufferCacheOpenGL framebuffer_cache;
RasterizerCacheOpenGL res_cache;
ShaderCacheOpenGL shader_cache;
GlobalRegionCacheOpenGL global_cache;
@@ -223,7 +224,6 @@ private:
OGLVertexArray>
vertex_array_cache;
std::map<FramebufferCacheKey, OGLFramebuffer> framebuffer_cache;
FramebufferConfigState current_framebuffer_config_state;
std::pair<bool, bool> current_depth_stencil_usage{};
@@ -247,8 +247,6 @@ private:
void SetupShaders(GLenum primitive_mode);
void SetupCachedFramebuffer(const FramebufferCacheKey& fbkey, OpenGLState& current_state);
enum class AccelDraw { Disabled, Arrays, Indexed };
AccelDraw accelerate_draw = AccelDraw::Disabled;

View File

@@ -561,8 +561,9 @@ void RasterizerCacheOpenGL::CopySurface(const Surface& src_surface, const Surfac
dst_surface->MarkAsModified(true, *this);
}
CachedSurface::CachedSurface(const SurfaceParams& params)
: RasterizerCacheObject{params.host_ptr}, params{params},
CachedSurface::CachedSurface(const SurfaceParams& params, FramebufferCacheOpenGL framebuffer_cache_)
: RasterizerCacheObject{params.host_ptr}, framebuffer_cache{std::move(framebuffer_cache_)},
texture{framebuffer_cache}, discrepant_view{framebuffer_cache}, params{params},
gl_target{SurfaceTargetToGL(params.target)}, cached_size_in_bytes{params.size_in_bytes} {
const auto optional_cpu_addr{
@@ -611,6 +612,8 @@ CachedSurface::CachedSurface(const SurfaceParams& params)
OpenGL::LabelGLObject(GL_TEXTURE, texture.handle, params.gpu_addr, params.IdentityString());
}
CachedSurface::~CachedSurface() = default;
MICROPROFILE_DEFINE(OpenGL_SurfaceLoad, "OpenGL", "Surface Load", MP_RGB(128, 192, 64));
void CachedSurface::LoadGLBuffer() {
MICROPROFILE_SCOPE(OpenGL_SurfaceLoad);
@@ -852,8 +855,9 @@ void CachedSurface::UpdateSwizzle(Tegra::Texture::SwizzleSource swizzle_x,
}
}
RasterizerCacheOpenGL::RasterizerCacheOpenGL(RasterizerOpenGL& rasterizer)
: RasterizerCache{rasterizer} {
RasterizerCacheOpenGL::RasterizerCacheOpenGL(RasterizerOpenGL& rasterizer,
FramebufferCacheOpenGL framebuffer_cache)
: RasterizerCache{rasterizer}, framebuffer_cache{std::move(framebuffer_cache)} {
read_framebuffer.Create();
draw_framebuffer.Create();
copy_pbo.Create();
@@ -961,7 +965,7 @@ Surface RasterizerCacheOpenGL::GetUncachedSurface(const SurfaceParams& params) {
Surface surface{TryGetReservedSurface(params)};
if (!surface) {
// No reserved surface available, create a new one and reserve it
surface = std::make_shared<CachedSurface>(params);
surface = std::make_shared<CachedSurface>(params, framebuffer_cache);
ReserveSurface(surface);
}
return surface;

View File

@@ -18,6 +18,7 @@
#include "video_core/engines/fermi_2d.h"
#include "video_core/engines/maxwell_3d.h"
#include "video_core/rasterizer_cache.h"
#include "video_core/renderer_opengl/gl_framebuffer_cache.h"
#include "video_core/renderer_opengl/gl_resource_manager.h"
#include "video_core/renderer_opengl/gl_shader_gen.h"
#include "video_core/surface.h"
@@ -350,7 +351,8 @@ class RasterizerOpenGL;
class CachedSurface final : public RasterizerCacheObject {
public:
explicit CachedSurface(const SurfaceParams& params);
explicit CachedSurface(const SurfaceParams& params, FramebufferCacheOpenGL framebuffer_cache_);
~CachedSurface();
VAddr GetCpuAddr() const override {
return cpu_addr;
@@ -426,6 +428,7 @@ private:
void EnsureTextureDiscrepantView();
FramebufferCacheOpenGL framebuffer_cache;
OGLTexture texture;
OGLTexture discrepant_view;
std::vector<std::vector<u8>> gl_buffer;
@@ -434,7 +437,7 @@ private:
GLenum gl_internal_format{};
std::size_t cached_size_in_bytes{};
std::array<GLenum, 4> swizzle{GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA};
std::size_t memory_size;
std::size_t memory_size{};
bool reinterpreted = false;
bool must_reload = false;
VAddr cpu_addr{};
@@ -442,7 +445,8 @@ private:
class RasterizerCacheOpenGL final : public RasterizerCache<Surface> {
public:
explicit RasterizerCacheOpenGL(RasterizerOpenGL& rasterizer);
explicit RasterizerCacheOpenGL(RasterizerOpenGL& rasterizer,
FramebufferCacheOpenGL framebuffer_cache);
/// Get a surface based on the texture configuration
Surface GetTextureSurface(const Tegra::Texture::FullTextureInfo& config,
@@ -499,6 +503,8 @@ private:
/// destroyed when used with different surface parameters.
std::unordered_map<SurfaceReserveKey, Surface> surface_reserve;
FramebufferCacheOpenGL framebuffer_cache;
OGLFramebuffer read_framebuffer;
OGLFramebuffer draw_framebuffer;

View File

@@ -6,6 +6,7 @@
#include <glad/glad.h>
#include "common/common_types.h"
#include "common/microprofile.h"
#include "video_core/renderer_opengl/gl_framebuffer_cache.h"
#include "video_core/renderer_opengl/gl_resource_manager.h"
#include "video_core/renderer_opengl/gl_shader_util.h"
#include "video_core/renderer_opengl/gl_state.h"
@@ -15,6 +16,16 @@ MICROPROFILE_DEFINE(OpenGL_ResourceDeletion, "OpenGL", "Resource Deletion", MP_R
namespace OpenGL {
OGLTexture::OGLTexture(FramebufferCacheOpenGL framebuffer_cache)
: framebuffer_cache{std::move(framebuffer_cache)} {}
OGLTexture::OGLTexture(OGLTexture&& o) noexcept
: handle{std::exchange(o.handle, 0)}, framebuffer_cache{std::move(o.framebuffer_cache)} {}
OGLTexture::~OGLTexture() {
Release();
}
void OGLTexture::Create(GLenum target) {
if (handle != 0)
return;
@@ -28,6 +39,9 @@ void OGLTexture::Release() {
return;
MICROPROFILE_SCOPE(OpenGL_ResourceDeletion);
if (framebuffer_cache) {
framebuffer_cache->InvalidateTexture(handle);
}
glDeleteTextures(1, &handle);
OpenGLState::GetCurState().UnbindTexture(handle).Apply();
handle = 0;

View File

@@ -4,6 +4,7 @@
#pragma once
#include <memory>
#include <utility>
#include <glad/glad.h>
#include "common/common_types.h"
@@ -11,15 +12,15 @@
namespace OpenGL {
class FramebufferCacheOpenGLImpl;
using FramebufferCacheOpenGL = std::shared_ptr<FramebufferCacheOpenGLImpl>;
class OGLTexture : private NonCopyable {
public:
OGLTexture() = default;
explicit OGLTexture(FramebufferCacheOpenGL framebuffer_cache);
OGLTexture(OGLTexture&& o) noexcept;
OGLTexture(OGLTexture&& o) noexcept : handle(std::exchange(o.handle, 0)) {}
~OGLTexture() {
Release();
}
~OGLTexture();
OGLTexture& operator=(OGLTexture&& o) noexcept {
Release();
@@ -34,6 +35,9 @@ public:
void Release();
GLuint handle = 0;
private:
FramebufferCacheOpenGL framebuffer_cache;
};
class OGLSampler : private NonCopyable {

View File

@@ -28,7 +28,7 @@ namespace OpenGL {
/// Structure used for storing information about the textures for the Switch screen
struct TextureInfo {
OGLTexture resource;
OGLTexture resource{nullptr};
GLsizei width;
GLsizei height;
GLenum gl_format;