texture_cache: Remove execution context copies from the texture cache

This is done to simplify the OpenGL implementation, it is needed for
Vulkan.
This commit is contained in:
ReinUsesLisp 2019-04-25 13:41:57 -03:00
parent fa59a7b4d8
commit 6c410104f4
7 changed files with 59 additions and 168 deletions

View file

@ -9,7 +9,7 @@
#include "video_core/renderer_opengl/gl_resource_manager.h" #include "video_core/renderer_opengl/gl_resource_manager.h"
#include "video_core/renderer_opengl/gl_texture_cache.h" #include "video_core/renderer_opengl/gl_texture_cache.h"
#include "video_core/renderer_opengl/utils.h" #include "video_core/renderer_opengl/utils.h"
#include "video_core/texture_cache/texture_cache_contextless.h" #include "video_core/texture_cache/texture_cache.h"
#include "video_core/textures/convert.h" #include "video_core/textures/convert.h"
#include "video_core/textures/texture.h" #include "video_core/textures/texture.h"
@ -18,6 +18,10 @@ namespace OpenGL {
using Tegra::Texture::SwizzleSource; using Tegra::Texture::SwizzleSource;
using VideoCore::MortonSwizzleMode; using VideoCore::MortonSwizzleMode;
using VideoCore::Surface::ComponentType;
using VideoCore::Surface::PixelFormat;
using VideoCore::Surface::SurfaceTarget;
namespace { namespace {
struct FormatTuple { struct FormatTuple {
@ -209,8 +213,7 @@ OGLTexture CreateTexture(const SurfaceParams& params, GLenum target, GLenum inte
} // Anonymous namespace } // Anonymous namespace
CachedSurface::CachedSurface(TextureCacheOpenGL& texture_cache, const SurfaceParams& params) CachedSurface::CachedSurface(TextureCacheOpenGL& texture_cache, const SurfaceParams& params)
: VideoCommon::SurfaceBaseContextless<TextureCacheOpenGL, CachedSurfaceView>{texture_cache, : VideoCommon::SurfaceBase<TextureCacheOpenGL, CachedSurfaceView>{texture_cache, params} {
params} {
const auto& tuple{GetFormatTuple(params.GetPixelFormat(), params.GetComponentType())}; const auto& tuple{GetFormatTuple(params.GetPixelFormat(), params.GetComponentType())};
internal_format = tuple.internal_format; internal_format = tuple.internal_format;
format = tuple.format; format = tuple.format;
@ -222,7 +225,7 @@ CachedSurface::CachedSurface(TextureCacheOpenGL& texture_cache, const SurfacePar
CachedSurface::~CachedSurface() = default; CachedSurface::~CachedSurface() = default;
void CachedSurface::DownloadTextureImpl() { void CachedSurface::DownloadTexture() {
// TODO(Rodrigo): Optimize alignment // TODO(Rodrigo): Optimize alignment
glPixelStorei(GL_PACK_ALIGNMENT, 1); glPixelStorei(GL_PACK_ALIGNMENT, 1);
SCOPE_EXIT({ glPixelStorei(GL_PACK_ROW_LENGTH, 0); }); SCOPE_EXIT({ glPixelStorei(GL_PACK_ROW_LENGTH, 0); });
@ -241,7 +244,7 @@ void CachedSurface::DownloadTextureImpl() {
} }
} }
void CachedSurface::UploadTextureImpl() { void CachedSurface::UploadTexture() {
SCOPE_EXIT({ glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); }); SCOPE_EXIT({ glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); });
for (u32 level = 0; level < params.GetNumLevels(); ++level) { for (u32 level = 0; level < params.GetNumLevels(); ++level) {
UploadTextureMipmap(level); UploadTextureMipmap(level);
@ -321,7 +324,8 @@ void CachedSurface::UploadTextureMipmap(u32 level) {
} }
void CachedSurface::DecorateSurfaceName() { void CachedSurface::DecorateSurfaceName() {
LabelGLObject(GL_TEXTURE, texture.handle, GetGpuAddr()); LabelGLObject(GL_TEXTURE, texture.handle, GetGpuAddr(),
params.GetTarget() == SurfaceTarget::Texture3D ? "3D" : "");
} }
std::unique_ptr<CachedSurfaceView> CachedSurface::CreateView(const ViewKey& view_key) { std::unique_ptr<CachedSurfaceView> CachedSurface::CreateView(const ViewKey& view_key) {

View file

@ -14,32 +14,30 @@
#include "common/common_types.h" #include "common/common_types.h"
#include "video_core/engines/shader_bytecode.h" #include "video_core/engines/shader_bytecode.h"
#include "video_core/renderer_opengl/gl_resource_manager.h" #include "video_core/renderer_opengl/gl_resource_manager.h"
#include "video_core/texture_cache/texture_cache_contextless.h" #include "video_core/texture_cache/texture_cache.h"
namespace OpenGL { namespace OpenGL {
using VideoCommon::SurfaceParams; using VideoCommon::SurfaceParams;
using VideoCommon::ViewKey; using VideoCommon::ViewKey;
using VideoCore::Surface::ComponentType;
using VideoCore::Surface::PixelFormat;
using VideoCore::Surface::SurfaceTarget;
using VideoCore::Surface::SurfaceType;
class CachedSurfaceView; class CachedSurfaceView;
class CachedSurface; class CachedSurface;
class TextureCacheOpenGL; class TextureCacheOpenGL;
using Surface = std::shared_ptr<CachedSurface>; using Surface = std::shared_ptr<CachedSurface>;
using TextureCacheBase = VideoCommon::TextureCacheContextless<CachedSurface, CachedSurfaceView>; using TextureCacheBase = VideoCommon::TextureCache<CachedSurface, CachedSurfaceView>;
class CachedSurface final class CachedSurface final : public VideoCommon::SurfaceBase<TextureCacheOpenGL, CachedSurfaceView> {
: public VideoCommon::SurfaceBaseContextless<TextureCacheOpenGL, CachedSurfaceView> {
friend CachedSurfaceView; friend CachedSurfaceView;
public: public:
explicit CachedSurface(TextureCacheOpenGL& texture_cache, const SurfaceParams& params); explicit CachedSurface(TextureCacheOpenGL& texture_cache, const SurfaceParams& params);
~CachedSurface(); ~CachedSurface();
void UploadTexture();
void DownloadTexture();
GLenum GetTarget() const { GLenum GetTarget() const {
return target; return target;
} }
@ -53,9 +51,6 @@ protected:
std::unique_ptr<CachedSurfaceView> CreateView(const ViewKey& view_key); std::unique_ptr<CachedSurfaceView> CreateView(const ViewKey& view_key);
void UploadTextureImpl();
void DownloadTextureImpl();
private: private:
void UploadTextureMipmap(u32 level); void UploadTextureMipmap(u32 level);

View file

@ -18,7 +18,9 @@ namespace OpenGL {
using Tegra::Shader::TextureType; using Tegra::Shader::TextureType;
using Tegra::Texture::SwizzleSource; using Tegra::Texture::SwizzleSource;
using VideoCore::Surface::SurfaceTarget; using VideoCore::Surface::SurfaceTarget;
using VideoCore::Surface::SurfaceType;
BindBuffersRangePushBuffer::BindBuffersRangePushBuffer(GLenum target) : target{target} {} BindBuffersRangePushBuffer::BindBuffersRangePushBuffer(GLenum target) : target{target} {}

View file

@ -53,8 +53,8 @@ void SurfaceBaseImpl::LoadBuffer() {
ASSERT_MSG(params.GetBlockWidth() == 1, "Block width is defined as {} on texture target {}", ASSERT_MSG(params.GetBlockWidth() == 1, "Block width is defined as {} on texture target {}",
params.GetBlockWidth(), static_cast<u32>(params.GetTarget())); params.GetBlockWidth(), static_cast<u32>(params.GetTarget()));
for (u32 level = 0; level < params.GetNumLevels(); ++level) { for (u32 level = 0; level < params.GetNumLevels(); ++level) {
u8* const buffer{GetStagingBufferLevelData(level)}; SwizzleFunc(MortonSwizzleMode::MortonToLinear, host_ptr, params,
SwizzleFunc(MortonSwizzleMode::MortonToLinear, host_ptr, params, buffer, level); GetStagingBufferLevelData(level), level);
} }
} else { } else {
ASSERT_MSG(params.GetNumLevels() == 1, "Linear mipmap loading is not implemented"); ASSERT_MSG(params.GetNumLevels() == 1, "Linear mipmap loading is not implemented");
@ -89,8 +89,8 @@ void SurfaceBaseImpl::FlushBuffer() {
ASSERT_MSG(params.GetBlockWidth() == 1, "Block width is defined as {}", ASSERT_MSG(params.GetBlockWidth() == 1, "Block width is defined as {}",
params.GetBlockWidth()); params.GetBlockWidth());
for (u32 level = 0; level < params.GetNumLevels(); ++level) { for (u32 level = 0; level < params.GetNumLevels(); ++level) {
u8* const buffer = GetStagingBufferLevelData(level); SwizzleFunc(MortonSwizzleMode::LinearToMorton, GetHostPtr(), params,
SwizzleFunc(MortonSwizzleMode::LinearToMorton, GetHostPtr(), params, buffer, level); GetStagingBufferLevelData(level), level);
} }
} else { } else {
UNIMPLEMENTED(); UNIMPLEMENTED();

View file

@ -89,14 +89,12 @@ private:
std::vector<u8> staging_buffer; std::vector<u8> staging_buffer;
}; };
template <typename TTextureCache, typename TView, typename TExecutionContext> template <typename TTextureCache, typename TView>
class SurfaceBase : public SurfaceBaseImpl { class SurfaceBase : public SurfaceBaseImpl {
static_assert(std::is_trivially_copyable_v<TExecutionContext>);
public: public:
virtual TExecutionContext UploadTexture(TExecutionContext exctx) = 0; virtual void UploadTexture() = 0;
virtual TExecutionContext DownloadTexture(TExecutionContext exctx) = 0; virtual void DownloadTexture() = 0;
TView* TryGetView(GPUVAddr view_addr, const SurfaceParams& view_params) { TView* TryGetView(GPUVAddr view_addr, const SurfaceParams& view_params) {
if (view_addr < GetGpuAddr() || !params.IsFamiliar(view_params)) { if (view_addr < GetGpuAddr() || !params.IsFamiliar(view_params)) {

View file

@ -8,7 +8,6 @@
#include <memory> #include <memory>
#include <set> #include <set>
#include <tuple> #include <tuple>
#include <type_traits>
#include <unordered_map> #include <unordered_map>
#include <boost/icl/interval_map.hpp> #include <boost/icl/interval_map.hpp>
@ -41,11 +40,8 @@ class RasterizerInterface;
namespace VideoCommon { namespace VideoCommon {
template <typename TSurface, typename TView, typename TExecutionContext> template <typename TSurface, typename TView>
class TextureCache { class TextureCache {
static_assert(std::is_trivially_copyable_v<TExecutionContext>);
using ResultType = std::tuple<TView*, TExecutionContext>;
using IntervalMap = boost::icl::interval_map<CacheAddr, std::set<std::shared_ptr<TSurface>>>; using IntervalMap = boost::icl::interval_map<CacheAddr, std::set<std::shared_ptr<TSurface>>>;
using IntervalType = typename IntervalMap::interval_type; using IntervalType = typename IntervalMap::interval_type;
@ -60,37 +56,35 @@ public:
} }
} }
ResultType GetTextureSurface(TExecutionContext exctx, TView* GetTextureSurface(const Tegra::Texture::FullTextureInfo& config) {
const Tegra::Texture::FullTextureInfo& config) {
const auto gpu_addr{config.tic.Address()}; const auto gpu_addr{config.tic.Address()};
if (!gpu_addr) { if (!gpu_addr) {
return {{}, exctx}; return {};
} }
const auto params{SurfaceParams::CreateForTexture(system, config)}; const auto params{SurfaceParams::CreateForTexture(system, config)};
return GetSurfaceView(exctx, gpu_addr, params, true); return GetSurfaceView(gpu_addr, params, true);
} }
ResultType GetDepthBufferSurface(TExecutionContext exctx, bool preserve_contents) { TView* GetDepthBufferSurface(bool preserve_contents) {
const auto& regs{system.GPU().Maxwell3D().regs}; const auto& regs{system.GPU().Maxwell3D().regs};
const auto gpu_addr{regs.zeta.Address()}; const auto gpu_addr{regs.zeta.Address()};
if (!gpu_addr || !regs.zeta_enable) { if (!gpu_addr || !regs.zeta_enable) {
return {{}, exctx}; return {};
} }
const auto depth_params{SurfaceParams::CreateForDepthBuffer( const auto depth_params{SurfaceParams::CreateForDepthBuffer(
system, regs.zeta_width, regs.zeta_height, regs.zeta.format, system, regs.zeta_width, regs.zeta_height, regs.zeta.format,
regs.zeta.memory_layout.block_width, regs.zeta.memory_layout.block_height, regs.zeta.memory_layout.block_width, regs.zeta.memory_layout.block_height,
regs.zeta.memory_layout.block_depth, regs.zeta.memory_layout.type)}; regs.zeta.memory_layout.block_depth, regs.zeta.memory_layout.type)};
return GetSurfaceView(exctx, gpu_addr, depth_params, preserve_contents); return GetSurfaceView(gpu_addr, depth_params, preserve_contents);
} }
ResultType GetColorBufferSurface(TExecutionContext exctx, std::size_t index, TView* GetColorBufferSurface(std::size_t index, bool preserve_contents) {
bool preserve_contents) {
ASSERT(index < Tegra::Engines::Maxwell3D::Regs::NumRenderTargets); ASSERT(index < Tegra::Engines::Maxwell3D::Regs::NumRenderTargets);
const auto& regs{system.GPU().Maxwell3D().regs}; const auto& regs{system.GPU().Maxwell3D().regs};
if (index >= regs.rt_control.count || regs.rt[index].Address() == 0 || if (index >= regs.rt_control.count || regs.rt[index].Address() == 0 ||
regs.rt[index].format == Tegra::RenderTargetFormat::NONE) { regs.rt[index].format == Tegra::RenderTargetFormat::NONE) {
return {{}, exctx}; return {};
} }
auto& memory_manager{system.GPU().MemoryManager()}; auto& memory_manager{system.GPU().MemoryManager()};
@ -98,17 +92,16 @@ public:
const auto gpu_addr{config.Address() + const auto gpu_addr{config.Address() +
config.base_layer * config.layer_stride * sizeof(u32)}; config.base_layer * config.layer_stride * sizeof(u32)};
if (!gpu_addr) { if (!gpu_addr) {
return {{}, exctx}; return {};
} }
return GetSurfaceView(exctx, gpu_addr, SurfaceParams::CreateForFramebuffer(system, index), return GetSurfaceView(gpu_addr, SurfaceParams::CreateForFramebuffer(system, index),
preserve_contents); preserve_contents);
} }
ResultType GetFermiSurface(TExecutionContext exctx, TView* GetFermiSurface(const Tegra::Engines::Fermi2D::Regs::Surface& config) {
const Tegra::Engines::Fermi2D::Regs::Surface& config) { return GetSurfaceView(config.Address(), SurfaceParams::CreateForFermiCopySurface(config),
return GetSurfaceView(exctx, config.Address(), true);
SurfaceParams::CreateForFermiCopySurface(config), true);
} }
std::shared_ptr<TSurface> TryFindFramebufferSurface(const u8* host_ptr) const { std::shared_ptr<TSurface> TryFindFramebufferSurface(const u8* host_ptr) const {
@ -126,10 +119,9 @@ protected:
~TextureCache() = default; ~TextureCache() = default;
virtual ResultType TryFastGetSurfaceView( virtual TView* TryFastGetSurfaceView(
TExecutionContext exctx, GPUVAddr gpu_addr, VAddr cpu_addr, u8* host_ptr, GPUVAddr gpu_addr, VAddr cpu_addr, u8* host_ptr, const SurfaceParams& params,
const SurfaceParams& params, bool preserve_contents, bool preserve_contents, const std::vector<std::shared_ptr<TSurface>>& overlaps) = 0;
const std::vector<std::shared_ptr<TSurface>>& overlaps) = 0;
virtual std::shared_ptr<TSurface> CreateSurface(const SurfaceParams& params) = 0; virtual std::shared_ptr<TSurface> CreateSurface(const SurfaceParams& params) = 0;
@ -158,8 +150,7 @@ protected:
Core::System& system; Core::System& system;
private: private:
ResultType GetSurfaceView(TExecutionContext exctx, GPUVAddr gpu_addr, TView* GetSurfaceView(GPUVAddr gpu_addr, const SurfaceParams& params, bool preserve_contents) {
const SurfaceParams& params, bool preserve_contents) {
auto& memory_manager{system.GPU().MemoryManager()}; auto& memory_manager{system.GPU().MemoryManager()};
const auto cpu_addr{memory_manager.GpuToCpuAddress(gpu_addr)}; const auto cpu_addr{memory_manager.GpuToCpuAddress(gpu_addr)};
DEBUG_ASSERT(cpu_addr); DEBUG_ASSERT(cpu_addr);
@ -168,18 +159,17 @@ private:
const auto cache_addr{ToCacheAddr(host_ptr)}; const auto cache_addr{ToCacheAddr(host_ptr)};
auto overlaps{GetSurfacesInRegion(cache_addr, params.GetGuestSizeInBytes())}; auto overlaps{GetSurfacesInRegion(cache_addr, params.GetGuestSizeInBytes())};
if (overlaps.empty()) { if (overlaps.empty()) {
return LoadSurfaceView(exctx, gpu_addr, *cpu_addr, host_ptr, params, preserve_contents); return LoadSurfaceView(gpu_addr, *cpu_addr, host_ptr, params, preserve_contents);
} }
if (overlaps.size() == 1) { if (overlaps.size() == 1) {
if (TView* view = overlaps[0]->TryGetView(gpu_addr, params); view) { if (TView* view = overlaps[0]->TryGetView(gpu_addr, params); view) {
return {view, exctx}; return view;
} }
} }
TView* fast_view; const auto fast_view{TryFastGetSurfaceView(gpu_addr, *cpu_addr, host_ptr, params,
std::tie(fast_view, exctx) = TryFastGetSurfaceView(exctx, gpu_addr, *cpu_addr, host_ptr, preserve_contents, overlaps)};
params, preserve_contents, overlaps);
if (!fast_view) { if (!fast_view) {
std::sort(overlaps.begin(), overlaps.end(), [](const auto& lhs, const auto& rhs) { std::sort(overlaps.begin(), overlaps.end(), [](const auto& lhs, const auto& rhs) {
@ -191,44 +181,39 @@ private:
if (!fast_view) { if (!fast_view) {
// Flush even when we don't care about the contents, to preserve memory not // Flush even when we don't care about the contents, to preserve memory not
// written by the new surface. // written by the new surface.
exctx = FlushSurface(exctx, surface); FlushSurface(surface);
} }
Unregister(surface); Unregister(surface);
} }
if (fast_view) { if (fast_view) {
return {fast_view, exctx}; return fast_view;
} }
return LoadSurfaceView(exctx, gpu_addr, *cpu_addr, host_ptr, params, preserve_contents); return LoadSurfaceView(gpu_addr, *cpu_addr, host_ptr, params, preserve_contents);
} }
ResultType LoadSurfaceView(TExecutionContext exctx, GPUVAddr gpu_addr, VAddr cpu_addr, TView* LoadSurfaceView(GPUVAddr gpu_addr, VAddr cpu_addr, u8* host_ptr,
u8* host_ptr, const SurfaceParams& params, bool preserve_contents) { const SurfaceParams& params, bool preserve_contents) {
const auto new_surface{GetUncachedSurface(params)}; const auto new_surface{GetUncachedSurface(params)};
Register(new_surface, gpu_addr, cpu_addr, host_ptr); Register(new_surface, gpu_addr, cpu_addr, host_ptr);
if (preserve_contents) { if (preserve_contents) {
exctx = LoadSurface(exctx, new_surface); LoadSurface(new_surface);
} }
return {new_surface->GetView(gpu_addr, params), exctx}; return new_surface->GetView(gpu_addr, params);
} }
TExecutionContext LoadSurface(TExecutionContext exctx, void LoadSurface(const std::shared_ptr<TSurface>& surface) {
const std::shared_ptr<TSurface>& surface) {
surface->LoadBuffer(); surface->LoadBuffer();
exctx = surface->UploadTexture(exctx); surface->UploadTexture();
surface->MarkAsModified(false); surface->MarkAsModified(false);
return exctx;
} }
TExecutionContext FlushSurface(TExecutionContext exctx, void FlushSurface(const std::shared_ptr<TSurface>& surface) {
const std::shared_ptr<TSurface>& surface) {
if (!surface->IsModified()) { if (!surface->IsModified()) {
return exctx; return;
} }
exctx = surface->DownloadTexture(exctx); surface->DownloadTexture();
surface->FlushBuffer(); surface->FlushBuffer();
return exctx;
} }
std::vector<std::shared_ptr<TSurface>> GetSurfacesInRegion(CacheAddr cache_addr, std::vector<std::shared_ptr<TSurface>> GetSurfacesInRegion(CacheAddr cache_addr,

View file

@ -1,93 +0,0 @@
// Copyright 2019 yuzu Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include "video_core/texture_cache/texture_cache.h"
namespace VideoCommon {
struct DummyExecutionContext {};
template <typename TSurface, typename TView>
class TextureCacheContextless : protected TextureCache<TSurface, TView, DummyExecutionContext> {
using Base = TextureCache<TSurface, TView, DummyExecutionContext>;
public:
void InvalidateRegion(CacheAddr addr, std::size_t size) {
Base::InvalidateRegion(addr, size);
}
TView* GetTextureSurface(const Tegra::Texture::FullTextureInfo& config) {
return RemoveContext(Base::GetTextureSurface({}, config));
}
TView* GetDepthBufferSurface(bool preserve_contents) {
return RemoveContext(Base::GetDepthBufferSurface({}, preserve_contents));
}
TView* GetColorBufferSurface(std::size_t index, bool preserve_contents) {
return RemoveContext(Base::GetColorBufferSurface({}, index, preserve_contents));
}
TView* GetFermiSurface(const Tegra::Engines::Fermi2D::Regs::Surface& config) {
return RemoveContext(Base::GetFermiSurface({}, config));
}
std::shared_ptr<TSurface> TryFindFramebufferSurface(const u8* host_ptr) const {
return Base::TryFindFramebufferSurface(host_ptr);
}
u64 Tick() {
return Base::Tick();
}
protected:
explicit TextureCacheContextless(Core::System& system,
VideoCore::RasterizerInterface& rasterizer)
: TextureCache<TSurface, TView, DummyExecutionContext>{system, rasterizer} {}
virtual TView* TryFastGetSurfaceView(
GPUVAddr gpu_addr, VAddr cpu_addr, u8* host_ptr, const SurfaceParams& params,
bool preserve_contents, const std::vector<std::shared_ptr<TSurface>>& overlaps) = 0;
private:
std::tuple<TView*, DummyExecutionContext> TryFastGetSurfaceView(
DummyExecutionContext, GPUVAddr gpu_addr, VAddr cpu_addr, u8* host_ptr,
const SurfaceParams& params, bool preserve_contents,
const std::vector<std::shared_ptr<TSurface>>& overlaps) {
return {TryFastGetSurfaceView(gpu_addr, cpu_addr, host_ptr, params, preserve_contents,
overlaps),
{}};
}
TView* RemoveContext(std::tuple<TView*, DummyExecutionContext> return_value) {
const auto [view, exctx] = return_value;
return view;
}
};
template <typename TTextureCache, typename TView>
class SurfaceBaseContextless : public SurfaceBase<TTextureCache, TView, DummyExecutionContext> {
public:
DummyExecutionContext DownloadTexture(DummyExecutionContext) {
DownloadTextureImpl();
return {};
}
DummyExecutionContext UploadTexture(DummyExecutionContext) {
UploadTextureImpl();
return {};
}
protected:
explicit SurfaceBaseContextless(TTextureCache& texture_cache, const SurfaceParams& params)
: SurfaceBase<TTextureCache, TView, DummyExecutionContext>{texture_cache, params} {}
virtual void DownloadTextureImpl() = 0;
virtual void UploadTextureImpl() = 0;
};
} // namespace VideoCommon