mirror of https://git.suyu.dev/suyu/suyu
gl_texture_cache: Minor changes
This commit is contained in:
parent
0cefb7bcb4
commit
4b396f375c
|
@ -498,8 +498,8 @@ std::pair<bool, bool> RasterizerOpenGL::ConfigureFramebuffers(
|
||||||
color_surface->MarkAsModified(true);
|
color_surface->MarkAsModified(true);
|
||||||
// Workaround for and issue in nvidia drivers
|
// Workaround for and issue in nvidia drivers
|
||||||
// https://devtalk.nvidia.com/default/topic/776591/opengl/gl_framebuffer_srgb-functions-incorrectly/
|
// https://devtalk.nvidia.com/default/topic/776591/opengl/gl_framebuffer_srgb-functions-incorrectly/
|
||||||
// state.framebuffer_srgb.enabled |=
|
state.framebuffer_srgb.enabled |=
|
||||||
// color_surface->GetSurfaceParams().srgb_conversion;
|
color_surface->GetSurfaceParams().GetSrgbConversion();
|
||||||
}
|
}
|
||||||
|
|
||||||
fbkey.is_single_buffer = true;
|
fbkey.is_single_buffer = true;
|
||||||
|
@ -519,8 +519,8 @@ std::pair<bool, bool> RasterizerOpenGL::ConfigureFramebuffers(
|
||||||
// Enable sRGB only for supported formats
|
// Enable sRGB only for supported formats
|
||||||
// Workaround for and issue in nvidia drivers
|
// Workaround for and issue in nvidia drivers
|
||||||
// https://devtalk.nvidia.com/default/topic/776591/opengl/gl_framebuffer_srgb-functions-incorrectly/
|
// https://devtalk.nvidia.com/default/topic/776591/opengl/gl_framebuffer_srgb-functions-incorrectly/
|
||||||
// state.framebuffer_srgb.enabled |=
|
state.framebuffer_srgb.enabled |=
|
||||||
// color_surface->GetSurfaceParams().srgb_conversion;
|
color_surface->GetSurfaceParams().GetSrgbConversion();
|
||||||
}
|
}
|
||||||
|
|
||||||
fbkey.color_attachments[index] =
|
fbkey.color_attachments[index] =
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
#include "video_core/morton.h"
|
#include "video_core/morton.h"
|
||||||
#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/texture_cache.h"
|
#include "video_core/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"
|
||||||
|
@ -285,6 +286,8 @@ void CachedSurface::LoadBuffer() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void CachedSurface::FlushBufferImpl() {
|
void CachedSurface::FlushBufferImpl() {
|
||||||
|
LOG_CRITICAL(Render_OpenGL, "Flushing");
|
||||||
|
|
||||||
if (!IsModified()) {
|
if (!IsModified()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -352,9 +355,6 @@ void CachedSurface::UploadTextureMipmap(u32 level) {
|
||||||
|
|
||||||
if (is_compressed) {
|
if (is_compressed) {
|
||||||
const auto image_size{static_cast<GLsizei>(params.GetHostMipmapSize(level))};
|
const auto image_size{static_cast<GLsizei>(params.GetHostMipmapSize(level))};
|
||||||
GLint expected_size;
|
|
||||||
glGetTextureLevelParameteriv(texture.handle, level, GL_TEXTURE_COMPRESSED_IMAGE_SIZE,
|
|
||||||
&expected_size);
|
|
||||||
switch (params.GetTarget()) {
|
switch (params.GetTarget()) {
|
||||||
case SurfaceTarget::Texture2D:
|
case SurfaceTarget::Texture2D:
|
||||||
glCompressedTextureSubImage2D(texture.handle, level, 0, 0,
|
glCompressedTextureSubImage2D(texture.handle, level, 0, 0,
|
||||||
|
@ -419,6 +419,10 @@ void CachedSurface::UploadTextureMipmap(u32 level) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CachedSurface::DecorateSurfaceName() {
|
||||||
|
LabelGLObject(GL_TEXTURE, texture.handle, GetGpuAddr());
|
||||||
|
}
|
||||||
|
|
||||||
std::unique_ptr<CachedSurfaceView> CachedSurface::CreateView(const ViewKey& view_key) {
|
std::unique_ptr<CachedSurfaceView> CachedSurface::CreateView(const ViewKey& view_key) {
|
||||||
return std::make_unique<CachedSurfaceView>(*this, view_key);
|
return std::make_unique<CachedSurfaceView>(*this, view_key);
|
||||||
}
|
}
|
||||||
|
@ -517,11 +521,13 @@ TextureCacheOpenGL::TextureCacheOpenGL(Core::System& system,
|
||||||
|
|
||||||
TextureCacheOpenGL::~TextureCacheOpenGL() = default;
|
TextureCacheOpenGL::~TextureCacheOpenGL() = default;
|
||||||
|
|
||||||
CachedSurfaceView* TextureCacheOpenGL::TryFastGetSurfaceView(
|
CachedSurfaceView* TextureCacheOpenGL::TryFastGetSurfaceView(GPUVAddr gpu_addr, VAddr cpu_addr,
|
||||||
VAddr cpu_addr, u8* host_ptr, const SurfaceParams& new_params, bool preserve_contents,
|
u8* host_ptr,
|
||||||
const std::vector<CachedSurface*>& overlaps) {
|
const SurfaceParams& new_params,
|
||||||
|
bool preserve_contents,
|
||||||
|
const std::vector<Surface>& overlaps) {
|
||||||
if (overlaps.size() > 1) {
|
if (overlaps.size() > 1) {
|
||||||
return TryCopyAsViews(cpu_addr, host_ptr, new_params, overlaps);
|
return TryCopyAsViews(gpu_addr, cpu_addr, host_ptr, new_params, overlaps);
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto& old_surface{overlaps[0]};
|
const auto& old_surface{overlaps[0]};
|
||||||
|
@ -530,18 +536,18 @@ CachedSurfaceView* TextureCacheOpenGL::TryFastGetSurfaceView(
|
||||||
old_params.GetDepth() == new_params.GetDepth() && old_params.GetDepth() == 1 &&
|
old_params.GetDepth() == new_params.GetDepth() && old_params.GetDepth() == 1 &&
|
||||||
old_params.GetNumLevels() == new_params.GetNumLevels() &&
|
old_params.GetNumLevels() == new_params.GetNumLevels() &&
|
||||||
old_params.GetPixelFormat() == new_params.GetPixelFormat()) {
|
old_params.GetPixelFormat() == new_params.GetPixelFormat()) {
|
||||||
return SurfaceCopy(cpu_addr, host_ptr, new_params, old_surface, old_params);
|
return SurfaceCopy(gpu_addr, cpu_addr, host_ptr, new_params, old_surface, old_params);
|
||||||
}
|
}
|
||||||
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
CachedSurfaceView* TextureCacheOpenGL::SurfaceCopy(VAddr cpu_addr, u8* host_ptr,
|
CachedSurfaceView* TextureCacheOpenGL::SurfaceCopy(GPUVAddr gpu_addr, VAddr cpu_addr, u8* host_ptr,
|
||||||
const SurfaceParams& new_params,
|
const SurfaceParams& new_params,
|
||||||
CachedSurface* old_surface,
|
const Surface& old_surface,
|
||||||
const SurfaceParams& old_params) {
|
const SurfaceParams& old_params) {
|
||||||
CachedSurface* const new_surface{GetUncachedSurface(new_params)};
|
const auto new_surface{GetUncachedSurface(new_params)};
|
||||||
Register(new_surface, cpu_addr, host_ptr);
|
Register(new_surface, gpu_addr, cpu_addr, host_ptr);
|
||||||
|
|
||||||
const u32 min_width{
|
const u32 min_width{
|
||||||
std::max(old_params.GetDefaultBlockWidth(), new_params.GetDefaultBlockWidth())};
|
std::max(old_params.GetDefaultBlockWidth(), new_params.GetDefaultBlockWidth())};
|
||||||
|
@ -562,12 +568,12 @@ CachedSurfaceView* TextureCacheOpenGL::SurfaceCopy(VAddr cpu_addr, u8* host_ptr,
|
||||||
new_surface->MarkAsModified(true);
|
new_surface->MarkAsModified(true);
|
||||||
|
|
||||||
// TODO(Rodrigo): Add an entry to directly get the superview
|
// TODO(Rodrigo): Add an entry to directly get the superview
|
||||||
return new_surface->GetView(cpu_addr, new_params);
|
return new_surface->GetView(gpu_addr, new_params);
|
||||||
}
|
}
|
||||||
|
|
||||||
CachedSurfaceView* TextureCacheOpenGL::TryCopyAsViews(VAddr cpu_addr, u8* host_ptr,
|
CachedSurfaceView* TextureCacheOpenGL::TryCopyAsViews(GPUVAddr gpu_addr, VAddr cpu_addr,
|
||||||
const SurfaceParams& new_params,
|
u8* host_ptr, const SurfaceParams& new_params,
|
||||||
const std::vector<CachedSurface*>& overlaps) {
|
const std::vector<Surface>& overlaps) {
|
||||||
if (new_params.GetTarget() == SurfaceTarget::Texture1D ||
|
if (new_params.GetTarget() == SurfaceTarget::Texture1D ||
|
||||||
new_params.GetTarget() == SurfaceTarget::Texture1DArray ||
|
new_params.GetTarget() == SurfaceTarget::Texture1DArray ||
|
||||||
new_params.GetTarget() == SurfaceTarget::Texture3D) {
|
new_params.GetTarget() == SurfaceTarget::Texture3D) {
|
||||||
|
@ -575,16 +581,16 @@ CachedSurfaceView* TextureCacheOpenGL::TryCopyAsViews(VAddr cpu_addr, u8* host_p
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
CachedSurface* const new_surface{GetUncachedSurface(new_params)};
|
const auto new_surface{GetUncachedSurface(new_params)};
|
||||||
// TODO(Rodrigo): Move this down
|
// TODO(Rodrigo): Move this down
|
||||||
Register(new_surface, cpu_addr, host_ptr);
|
Register(new_surface, gpu_addr, cpu_addr, host_ptr);
|
||||||
|
|
||||||
// TODO(Rodrigo): Find a way to avoid heap allocations here.
|
// TODO(Rodrigo): Find a way to avoid heap allocations here.
|
||||||
std::vector<CachedSurfaceView*> views;
|
std::vector<CachedSurfaceView*> views;
|
||||||
views.reserve(overlaps.size());
|
views.reserve(overlaps.size());
|
||||||
for (const auto& overlap : overlaps) {
|
for (const auto& overlap : overlaps) {
|
||||||
const auto view{
|
const auto view{
|
||||||
new_surface->TryGetView(overlap->GetCpuAddr(), overlap->GetSurfaceParams())};
|
new_surface->TryGetView(overlap->GetGpuAddr(), overlap->GetSurfaceParams())};
|
||||||
if (!view) {
|
if (!view) {
|
||||||
// TODO(Rodrigo): Remove this
|
// TODO(Rodrigo): Remove this
|
||||||
Unregister(new_surface);
|
Unregister(new_surface);
|
||||||
|
@ -610,11 +616,11 @@ CachedSurfaceView* TextureCacheOpenGL::TryCopyAsViews(VAddr cpu_addr, u8* host_p
|
||||||
new_surface->MarkAsModified(true);
|
new_surface->MarkAsModified(true);
|
||||||
|
|
||||||
// TODO(Rodrigo): Add an entry to directly get the superview
|
// TODO(Rodrigo): Add an entry to directly get the superview
|
||||||
return new_surface->GetView(cpu_addr, new_params);
|
return new_surface->GetView(gpu_addr, new_params);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<CachedSurface> TextureCacheOpenGL::CreateSurface(const SurfaceParams& params) {
|
Surface TextureCacheOpenGL::CreateSurface(const SurfaceParams& params) {
|
||||||
return std::make_unique<CachedSurface>(params);
|
return std::make_unique<CachedSurface>(*this, params);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace OpenGL
|
} // namespace OpenGL
|
||||||
|
|
|
@ -27,6 +27,7 @@ using VideoCore::Surface::SurfaceType;
|
||||||
class CachedSurfaceView;
|
class CachedSurfaceView;
|
||||||
class CachedSurface;
|
class CachedSurface;
|
||||||
|
|
||||||
|
using Surface = std::shared_ptr<CachedSurface>;
|
||||||
using TextureCacheBase = VideoCommon::TextureCacheContextless<CachedSurface, CachedSurfaceView>;
|
using TextureCacheBase = VideoCommon::TextureCacheContextless<CachedSurface, CachedSurfaceView>;
|
||||||
|
|
||||||
class CachedSurface final : public VideoCommon::SurfaceBaseContextless<CachedSurfaceView> {
|
class CachedSurface final : public VideoCommon::SurfaceBaseContextless<CachedSurfaceView> {
|
||||||
|
@ -47,6 +48,8 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
void DecorateSurfaceName();
|
||||||
|
|
||||||
std::unique_ptr<CachedSurfaceView> CreateView(const ViewKey& view_key);
|
std::unique_ptr<CachedSurfaceView> CreateView(const ViewKey& view_key);
|
||||||
|
|
||||||
void FlushBufferImpl();
|
void FlushBufferImpl();
|
||||||
|
@ -65,7 +68,6 @@ private:
|
||||||
OGLTexture texture;
|
OGLTexture texture;
|
||||||
|
|
||||||
std::vector<u8> staging_buffer;
|
std::vector<u8> staging_buffer;
|
||||||
u8* host_ptr{};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class CachedSurfaceView final {
|
class CachedSurfaceView final {
|
||||||
|
@ -155,19 +157,21 @@ public:
|
||||||
~TextureCacheOpenGL();
|
~TextureCacheOpenGL();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
CachedSurfaceView* TryFastGetSurfaceView(VAddr cpu_addr, u8* host_ptr,
|
CachedSurfaceView* TryFastGetSurfaceView(GPUVAddr gpu_addr, VAddr cpu_addr, u8* host_ptr,
|
||||||
const SurfaceParams& new_params,
|
const SurfaceParams& new_params,
|
||||||
bool preserve_contents,
|
bool preserve_contents,
|
||||||
const std::vector<CachedSurface*>& overlaps);
|
const std::vector<Surface>& overlaps);
|
||||||
|
|
||||||
std::unique_ptr<CachedSurface> CreateSurface(const SurfaceParams& params);
|
Surface CreateSurface(const SurfaceParams& params);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
CachedSurfaceView* SurfaceCopy(VAddr cpu_addr, u8* host_ptr, const SurfaceParams& new_params,
|
CachedSurfaceView* SurfaceCopy(GPUVAddr gpu_addr, VAddr cpu_addr, u8* host_ptr,
|
||||||
CachedSurface* old_surface, const SurfaceParams& old_params);
|
const SurfaceParams& new_params, const Surface& old_surface,
|
||||||
|
const SurfaceParams& old_params);
|
||||||
|
|
||||||
CachedSurfaceView* TryCopyAsViews(VAddr cpu_addr, u8* host_ptr, const SurfaceParams& new_params,
|
CachedSurfaceView* TryCopyAsViews(GPUVAddr gpu_addr, VAddr cpu_addr, u8* host_ptr,
|
||||||
const std::vector<CachedSurface*>& overlaps);
|
const SurfaceParams& new_params,
|
||||||
|
const std::vector<Surface>& overlaps);
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace OpenGL
|
} // namespace OpenGL
|
||||||
|
|
|
@ -32,12 +32,13 @@ SurfaceParams SurfaceParams::CreateForTexture(Core::System& system,
|
||||||
const Tegra::Texture::FullTextureInfo& config) {
|
const Tegra::Texture::FullTextureInfo& config) {
|
||||||
SurfaceParams params;
|
SurfaceParams params;
|
||||||
params.is_tiled = config.tic.IsTiled();
|
params.is_tiled = config.tic.IsTiled();
|
||||||
|
params.srgb_conversion = config.tic.IsSrgbConversionEnabled();
|
||||||
params.block_width = params.is_tiled ? config.tic.BlockWidth() : 0,
|
params.block_width = params.is_tiled ? config.tic.BlockWidth() : 0,
|
||||||
params.block_height = params.is_tiled ? config.tic.BlockHeight() : 0,
|
params.block_height = params.is_tiled ? config.tic.BlockHeight() : 0,
|
||||||
params.block_depth = params.is_tiled ? config.tic.BlockDepth() : 0,
|
params.block_depth = params.is_tiled ? config.tic.BlockDepth() : 0,
|
||||||
params.tile_width_spacing = params.is_tiled ? (1 << config.tic.tile_width_spacing.Value()) : 1;
|
params.tile_width_spacing = params.is_tiled ? (1 << config.tic.tile_width_spacing.Value()) : 1;
|
||||||
params.pixel_format =
|
params.pixel_format = PixelFormatFromTextureFormat(config.tic.format, config.tic.r_type.Value(),
|
||||||
PixelFormatFromTextureFormat(config.tic.format, config.tic.r_type.Value(), false);
|
params.srgb_conversion);
|
||||||
params.component_type = ComponentTypeFromTexture(config.tic.r_type.Value());
|
params.component_type = ComponentTypeFromTexture(config.tic.r_type.Value());
|
||||||
params.type = GetFormatType(params.pixel_format);
|
params.type = GetFormatType(params.pixel_format);
|
||||||
params.target = SurfaceTargetFromTextureType(config.tic.texture_type);
|
params.target = SurfaceTargetFromTextureType(config.tic.texture_type);
|
||||||
|
@ -62,6 +63,7 @@ SurfaceParams SurfaceParams::CreateForDepthBuffer(
|
||||||
Tegra::Engines::Maxwell3D::Regs::InvMemoryLayout type) {
|
Tegra::Engines::Maxwell3D::Regs::InvMemoryLayout type) {
|
||||||
SurfaceParams params;
|
SurfaceParams params;
|
||||||
params.is_tiled = type == Tegra::Engines::Maxwell3D::Regs::InvMemoryLayout::BlockLinear;
|
params.is_tiled = type == Tegra::Engines::Maxwell3D::Regs::InvMemoryLayout::BlockLinear;
|
||||||
|
params.srgb_conversion = false;
|
||||||
params.block_width = 1 << std::min(block_width, 5U);
|
params.block_width = 1 << std::min(block_width, 5U);
|
||||||
params.block_height = 1 << std::min(block_height, 5U);
|
params.block_height = 1 << std::min(block_height, 5U);
|
||||||
params.block_depth = 1 << std::min(block_depth, 5U);
|
params.block_depth = 1 << std::min(block_depth, 5U);
|
||||||
|
@ -85,6 +87,8 @@ SurfaceParams SurfaceParams::CreateForFramebuffer(Core::System& system, std::siz
|
||||||
SurfaceParams params;
|
SurfaceParams params;
|
||||||
params.is_tiled =
|
params.is_tiled =
|
||||||
config.memory_layout.type == Tegra::Engines::Maxwell3D::Regs::InvMemoryLayout::BlockLinear;
|
config.memory_layout.type == Tegra::Engines::Maxwell3D::Regs::InvMemoryLayout::BlockLinear;
|
||||||
|
params.srgb_conversion = config.format == Tegra::RenderTargetFormat::BGRA8_SRGB ||
|
||||||
|
config.format == Tegra::RenderTargetFormat::RGBA8_SRGB;
|
||||||
params.block_width = 1 << config.memory_layout.block_width;
|
params.block_width = 1 << config.memory_layout.block_width;
|
||||||
params.block_height = 1 << config.memory_layout.block_height;
|
params.block_height = 1 << config.memory_layout.block_height;
|
||||||
params.block_depth = 1 << config.memory_layout.block_depth;
|
params.block_depth = 1 << config.memory_layout.block_depth;
|
||||||
|
@ -113,6 +117,8 @@ SurfaceParams SurfaceParams::CreateForFermiCopySurface(
|
||||||
const Tegra::Engines::Fermi2D::Regs::Surface& config) {
|
const Tegra::Engines::Fermi2D::Regs::Surface& config) {
|
||||||
SurfaceParams params{};
|
SurfaceParams params{};
|
||||||
params.is_tiled = !config.linear;
|
params.is_tiled = !config.linear;
|
||||||
|
params.srgb_conversion = config.format == Tegra::RenderTargetFormat::BGRA8_SRGB ||
|
||||||
|
config.format == Tegra::RenderTargetFormat::RGBA8_SRGB;
|
||||||
params.block_width = params.is_tiled ? std::min(config.BlockWidth(), 32U) : 0,
|
params.block_width = params.is_tiled ? std::min(config.BlockWidth(), 32U) : 0,
|
||||||
params.block_height = params.is_tiled ? std::min(config.BlockHeight(), 32U) : 0,
|
params.block_height = params.is_tiled ? std::min(config.BlockHeight(), 32U) : 0,
|
||||||
params.block_depth = params.is_tiled ? std::min(config.BlockDepth(), 32U) : 0,
|
params.block_depth = params.is_tiled ? std::min(config.BlockDepth(), 32U) : 0,
|
||||||
|
@ -162,6 +168,7 @@ u32 SurfaceParams::GetMipBlockHeight(u32 level) const {
|
||||||
if (level == 0) {
|
if (level == 0) {
|
||||||
return this->block_height;
|
return this->block_height;
|
||||||
}
|
}
|
||||||
|
|
||||||
const u32 height{GetMipHeight(level)};
|
const u32 height{GetMipHeight(level)};
|
||||||
const u32 default_block_height{GetDefaultBlockHeight()};
|
const u32 default_block_height{GetDefaultBlockHeight()};
|
||||||
const u32 blocks_in_y{(height + default_block_height - 1) / default_block_height};
|
const u32 blocks_in_y{(height + default_block_height - 1) / default_block_height};
|
||||||
|
@ -173,10 +180,12 @@ u32 SurfaceParams::GetMipBlockHeight(u32 level) const {
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 SurfaceParams::GetMipBlockDepth(u32 level) const {
|
u32 SurfaceParams::GetMipBlockDepth(u32 level) const {
|
||||||
if (level == 0)
|
if (level == 0) {
|
||||||
return block_depth;
|
return this->block_depth;
|
||||||
if (target != SurfaceTarget::Texture3D)
|
}
|
||||||
|
if (IsLayered()) {
|
||||||
return 1;
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
const u32 depth{GetMipDepth(level)};
|
const u32 depth{GetMipDepth(level)};
|
||||||
u32 block_depth = 32;
|
u32 block_depth = 32;
|
||||||
|
@ -192,7 +201,7 @@ u32 SurfaceParams::GetMipBlockDepth(u32 level) const {
|
||||||
std::size_t SurfaceParams::GetGuestMipmapLevelOffset(u32 level) const {
|
std::size_t SurfaceParams::GetGuestMipmapLevelOffset(u32 level) const {
|
||||||
std::size_t offset = 0;
|
std::size_t offset = 0;
|
||||||
for (u32 i = 0; i < level; i++) {
|
for (u32 i = 0; i < level; i++) {
|
||||||
offset += GetInnerMipmapMemorySize(i, false, IsLayered(), false);
|
offset += GetInnerMipmapMemorySize(i, false, false);
|
||||||
}
|
}
|
||||||
return offset;
|
return offset;
|
||||||
}
|
}
|
||||||
|
@ -200,21 +209,33 @@ std::size_t SurfaceParams::GetGuestMipmapLevelOffset(u32 level) const {
|
||||||
std::size_t SurfaceParams::GetHostMipmapLevelOffset(u32 level) const {
|
std::size_t SurfaceParams::GetHostMipmapLevelOffset(u32 level) const {
|
||||||
std::size_t offset = 0;
|
std::size_t offset = 0;
|
||||||
for (u32 i = 0; i < level; i++) {
|
for (u32 i = 0; i < level; i++) {
|
||||||
offset += GetInnerMipmapMemorySize(i, true, false, false);
|
offset += GetInnerMipmapMemorySize(i, true, false) * GetNumLayers();
|
||||||
}
|
}
|
||||||
return offset;
|
return offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::size_t SurfaceParams::GetHostMipmapSize(u32 level) const {
|
std::size_t SurfaceParams::GetHostMipmapSize(u32 level) const {
|
||||||
return GetInnerMipmapMemorySize(level, true, true, false) * GetNumLayers();
|
return GetInnerMipmapMemorySize(level, true, false) * GetNumLayers();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::size_t SurfaceParams::GetGuestLayerSize() const {
|
std::size_t SurfaceParams::GetGuestLayerSize() const {
|
||||||
return GetInnerMemorySize(false, true, false);
|
return GetLayerSize(false, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::size_t SurfaceParams::GetLayerSize(bool as_host_size, bool uncompressed) const {
|
||||||
|
std::size_t size = 0;
|
||||||
|
for (u32 level = 0; level < num_levels; ++level) {
|
||||||
|
size += GetInnerMipmapMemorySize(level, as_host_size, uncompressed);
|
||||||
|
}
|
||||||
|
if (is_tiled && IsLayered()) {
|
||||||
|
return Common::AlignUp(size, Tegra::Texture::GetGOBSize() * block_height * block_depth);
|
||||||
|
}
|
||||||
|
return size;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::size_t SurfaceParams::GetHostLayerSize(u32 level) const {
|
std::size_t SurfaceParams::GetHostLayerSize(u32 level) const {
|
||||||
return GetInnerMipmapMemorySize(level, true, IsLayered(), false);
|
ASSERT(target != SurfaceTarget::Texture3D);
|
||||||
|
return GetInnerMipmapMemorySize(level, true, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 SurfaceParams::GetDefaultBlockWidth() const {
|
u32 SurfaceParams::GetDefaultBlockWidth() const {
|
||||||
|
@ -273,15 +294,6 @@ bool SurfaceParams::IsPixelFormatZeta() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
void SurfaceParams::CalculateCachedValues() {
|
void SurfaceParams::CalculateCachedValues() {
|
||||||
guest_size_in_bytes = GetInnerMemorySize(false, false, false);
|
|
||||||
|
|
||||||
// ASTC is uncompressed in software, in emulated as RGBA8
|
|
||||||
if (IsPixelFormatASTC(pixel_format)) {
|
|
||||||
host_size_in_bytes = static_cast<std::size_t>(width * height * depth) * 4ULL;
|
|
||||||
} else {
|
|
||||||
host_size_in_bytes = GetInnerMemorySize(true, false, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (target) {
|
switch (target) {
|
||||||
case SurfaceTarget::Texture1D:
|
case SurfaceTarget::Texture1D:
|
||||||
case SurfaceTarget::Texture2D:
|
case SurfaceTarget::Texture2D:
|
||||||
|
@ -297,28 +309,30 @@ void SurfaceParams::CalculateCachedValues() {
|
||||||
default:
|
default:
|
||||||
UNREACHABLE();
|
UNREACHABLE();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
guest_size_in_bytes = GetInnerMemorySize(false, false, false);
|
||||||
|
|
||||||
|
// ASTC is uncompressed in software, in emulated as RGBA8
|
||||||
|
if (IsPixelFormatASTC(pixel_format)) {
|
||||||
|
host_size_in_bytes = static_cast<std::size_t>(width * height * depth * 4U);
|
||||||
|
} else {
|
||||||
|
host_size_in_bytes = GetInnerMemorySize(true, false, false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::size_t SurfaceParams::GetInnerMipmapMemorySize(u32 level, bool as_host_size, bool layer_only,
|
std::size_t SurfaceParams::GetInnerMipmapMemorySize(u32 level, bool as_host_size,
|
||||||
bool uncompressed) const {
|
bool uncompressed) const {
|
||||||
const bool tiled{as_host_size ? false : is_tiled};
|
const bool tiled{as_host_size ? false : is_tiled};
|
||||||
const u32 width{GetMipmapSize(uncompressed, GetMipWidth(level), GetDefaultBlockWidth())};
|
const u32 width{GetMipmapSize(uncompressed, GetMipWidth(level), GetDefaultBlockWidth())};
|
||||||
const u32 height{GetMipmapSize(uncompressed, GetMipHeight(level), GetDefaultBlockHeight())};
|
const u32 height{GetMipmapSize(uncompressed, GetMipHeight(level), GetDefaultBlockHeight())};
|
||||||
const u32 depth{layer_only ? 1U : GetMipDepth(level)};
|
const u32 depth{target == SurfaceTarget::Texture3D ? GetMipDepth(level) : 1U};
|
||||||
return Tegra::Texture::CalculateSize(tiled, GetBytesPerPixel(), width, height, depth,
|
return Tegra::Texture::CalculateSize(tiled, GetBytesPerPixel(), width, height, depth,
|
||||||
GetMipBlockHeight(level), GetMipBlockDepth(level));
|
GetMipBlockHeight(level), GetMipBlockDepth(level));
|
||||||
}
|
}
|
||||||
|
|
||||||
std::size_t SurfaceParams::GetInnerMemorySize(bool as_host_size, bool layer_only,
|
std::size_t SurfaceParams::GetInnerMemorySize(bool as_host_size, bool layer_only,
|
||||||
bool uncompressed) const {
|
bool uncompressed) const {
|
||||||
std::size_t size = 0;
|
return GetLayerSize(as_host_size, uncompressed) * (layer_only ? 1U : num_layers);
|
||||||
for (u32 level = 0; level < num_levels; ++level) {
|
|
||||||
size += GetInnerMipmapMemorySize(level, as_host_size, layer_only, uncompressed);
|
|
||||||
}
|
|
||||||
if (is_tiled && !as_host_size) {
|
|
||||||
size = Common::AlignUp(size, Tegra::Texture::GetGOBSize() * block_height * block_depth);
|
|
||||||
}
|
|
||||||
return size;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::map<u64, std::pair<u32, u32>> SurfaceParams::CreateViewOffsetMap() const {
|
std::map<u64, std::pair<u32, u32>> SurfaceParams::CreateViewOffsetMap() const {
|
||||||
|
|
|
@ -53,6 +53,7 @@ protected:
|
||||||
HasheableSurfaceParams() = default;
|
HasheableSurfaceParams() = default;
|
||||||
|
|
||||||
bool is_tiled;
|
bool is_tiled;
|
||||||
|
bool srgb_conversion;
|
||||||
u32 block_width;
|
u32 block_width;
|
||||||
u32 block_height;
|
u32 block_height;
|
||||||
u32 block_depth;
|
u32 block_depth;
|
||||||
|
@ -92,6 +93,10 @@ public:
|
||||||
return is_tiled;
|
return is_tiled;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool GetSrgbConversion() const {
|
||||||
|
return srgb_conversion;
|
||||||
|
}
|
||||||
|
|
||||||
u32 GetBlockWidth() const {
|
u32 GetBlockWidth() const {
|
||||||
return block_width;
|
return block_width;
|
||||||
}
|
}
|
||||||
|
@ -211,13 +216,15 @@ private:
|
||||||
/// Calculates values that can be deduced from HasheableSurfaceParams.
|
/// Calculates values that can be deduced from HasheableSurfaceParams.
|
||||||
void CalculateCachedValues();
|
void CalculateCachedValues();
|
||||||
|
|
||||||
/// Returns the size of a given mipmap level.
|
/// Returns the size of a given mipmap level inside a layer.
|
||||||
std::size_t GetInnerMipmapMemorySize(u32 level, bool as_host_size, bool layer_only,
|
std::size_t GetInnerMipmapMemorySize(u32 level, bool as_host_size, bool uncompressed) const;
|
||||||
bool uncompressed) const;
|
|
||||||
|
|
||||||
/// Returns the size of all mipmap levels and aligns as needed.
|
/// Returns the size of all mipmap levels and aligns as needed.
|
||||||
std::size_t GetInnerMemorySize(bool as_host_size, bool layer_only, bool uncompressed) const;
|
std::size_t GetInnerMemorySize(bool as_host_size, bool layer_only, bool uncompressed) const;
|
||||||
|
|
||||||
|
/// Returns the size of a layer
|
||||||
|
std::size_t GetLayerSize(bool as_host_size, bool uncompressed) const;
|
||||||
|
|
||||||
/// Returns true if the passed view width and height match the size of this params in a given
|
/// Returns true if the passed view width and height match the size of this params in a given
|
||||||
/// mipmap level.
|
/// mipmap level.
|
||||||
bool IsDimensionValid(const SurfaceParams& view_params, u32 level) const;
|
bool IsDimensionValid(const SurfaceParams& view_params, u32 level) const;
|
||||||
|
@ -277,13 +284,13 @@ public:
|
||||||
|
|
||||||
virtual TExecutionContext UploadTexture(TExecutionContext exctx) = 0;
|
virtual TExecutionContext UploadTexture(TExecutionContext exctx) = 0;
|
||||||
|
|
||||||
TView* TryGetView(VAddr view_addr, const SurfaceParams& view_params) {
|
TView* TryGetView(GPUVAddr view_addr, const SurfaceParams& view_params) {
|
||||||
if (view_addr < cpu_addr || !params.IsFamiliar(view_params)) {
|
if (view_addr < gpu_addr || !params.IsFamiliar(view_params)) {
|
||||||
// It can't be a view if it's in a prior address.
|
// It can't be a view if it's in a prior address.
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto relative_offset{static_cast<u64>(view_addr - cpu_addr)};
|
const auto relative_offset{static_cast<u64>(view_addr - gpu_addr)};
|
||||||
const auto it{view_offset_map.find(relative_offset)};
|
const auto it{view_offset_map.find(relative_offset)};
|
||||||
if (it == view_offset_map.end()) {
|
if (it == view_offset_map.end()) {
|
||||||
// Couldn't find an aligned view.
|
// Couldn't find an aligned view.
|
||||||
|
@ -298,6 +305,11 @@ public:
|
||||||
return GetView(layer, view_params.GetNumLayers(), level, view_params.GetNumLevels());
|
return GetView(layer, view_params.GetNumLayers(), level, view_params.GetNumLevels());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GPUVAddr GetGpuAddr() const {
|
||||||
|
ASSERT(is_registered);
|
||||||
|
return gpu_addr;
|
||||||
|
}
|
||||||
|
|
||||||
VAddr GetCpuAddr() const {
|
VAddr GetCpuAddr() const {
|
||||||
ASSERT(is_registered);
|
ASSERT(is_registered);
|
||||||
return cpu_addr;
|
return cpu_addr;
|
||||||
|
@ -325,22 +337,20 @@ public:
|
||||||
return params;
|
return params;
|
||||||
}
|
}
|
||||||
|
|
||||||
TView* GetView(VAddr view_addr, const SurfaceParams& view_params) {
|
TView* GetView(GPUVAddr view_addr, const SurfaceParams& view_params) {
|
||||||
TView* view{TryGetView(view_addr, view_params)};
|
TView* view{TryGetView(view_addr, view_params)};
|
||||||
ASSERT(view != nullptr);
|
ASSERT(view != nullptr);
|
||||||
return view;
|
return view;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Register(VAddr cpu_addr_, u8* host_ptr_) {
|
void Register(GPUVAddr gpu_addr_, VAddr cpu_addr_, u8* host_ptr_) {
|
||||||
ASSERT(!is_registered);
|
ASSERT(!is_registered);
|
||||||
is_registered = true;
|
is_registered = true;
|
||||||
|
gpu_addr = gpu_addr_;
|
||||||
cpu_addr = cpu_addr_;
|
cpu_addr = cpu_addr_;
|
||||||
host_ptr = host_ptr_;
|
host_ptr = host_ptr_;
|
||||||
cache_addr = ToCacheAddr(host_ptr_);
|
cache_addr = ToCacheAddr(host_ptr_);
|
||||||
}
|
DecorateSurfaceName();
|
||||||
|
|
||||||
void Register(VAddr cpu_addr_) {
|
|
||||||
Register(cpu_addr_, Memory::GetPointer(cpu_addr_));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Unregister() {
|
void Unregister() {
|
||||||
|
@ -358,6 +368,8 @@ protected:
|
||||||
|
|
||||||
~SurfaceBase() = default;
|
~SurfaceBase() = default;
|
||||||
|
|
||||||
|
virtual void DecorateSurfaceName() = 0;
|
||||||
|
|
||||||
virtual std::unique_ptr<TView> CreateView(const ViewKey& view_key) = 0;
|
virtual std::unique_ptr<TView> CreateView(const ViewKey& view_key) = 0;
|
||||||
|
|
||||||
bool IsModified() const {
|
bool IsModified() const {
|
||||||
|
@ -379,6 +391,7 @@ private:
|
||||||
|
|
||||||
const std::map<u64, std::pair<u32, u32>> view_offset_map;
|
const std::map<u64, std::pair<u32, u32>> view_offset_map;
|
||||||
|
|
||||||
|
GPUVAddr gpu_addr{};
|
||||||
VAddr cpu_addr{};
|
VAddr cpu_addr{};
|
||||||
u8* host_ptr{};
|
u8* host_ptr{};
|
||||||
CacheAddr cache_addr{};
|
CacheAddr cache_addr{};
|
||||||
|
@ -392,12 +405,12 @@ class TextureCache {
|
||||||
static_assert(std::is_trivially_copyable_v<TExecutionContext>);
|
static_assert(std::is_trivially_copyable_v<TExecutionContext>);
|
||||||
|
|
||||||
using ResultType = std::tuple<TView*, TExecutionContext>;
|
using ResultType = std::tuple<TView*, TExecutionContext>;
|
||||||
using IntervalMap = boost::icl::interval_map<CacheAddr, std::set<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;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void InvalidateRegion(CacheAddr addr, std::size_t size) {
|
void InvalidateRegion(CacheAddr addr, std::size_t size) {
|
||||||
for (TSurface* surface : GetSurfacesInRegion(addr, size)) {
|
for (const auto& surface : GetSurfacesInRegion(addr, size)) {
|
||||||
if (!surface->IsRegistered()) {
|
if (!surface->IsRegistered()) {
|
||||||
// Skip duplicates
|
// Skip duplicates
|
||||||
continue;
|
continue;
|
||||||
|
@ -408,32 +421,25 @@ public:
|
||||||
|
|
||||||
ResultType GetTextureSurface(TExecutionContext exctx,
|
ResultType GetTextureSurface(TExecutionContext exctx,
|
||||||
const Tegra::Texture::FullTextureInfo& config) {
|
const Tegra::Texture::FullTextureInfo& config) {
|
||||||
auto& memory_manager{system.GPU().MemoryManager()};
|
const auto gpu_addr{config.tic.Address()};
|
||||||
const auto cpu_addr{memory_manager.GpuToCpuAddress(config.tic.Address())};
|
if (!gpu_addr) {
|
||||||
if (!cpu_addr) {
|
|
||||||
return {{}, exctx};
|
return {{}, exctx};
|
||||||
}
|
}
|
||||||
const auto params{SurfaceParams::CreateForTexture(system, config)};
|
const auto params{SurfaceParams::CreateForTexture(system, config)};
|
||||||
return GetSurfaceView(exctx, *cpu_addr, params, true);
|
return GetSurfaceView(exctx, gpu_addr, params, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultType GetDepthBufferSurface(TExecutionContext exctx, bool preserve_contents) {
|
ResultType GetDepthBufferSurface(TExecutionContext exctx, bool preserve_contents) {
|
||||||
const auto& regs{system.GPU().Maxwell3D().regs};
|
const auto& regs{system.GPU().Maxwell3D().regs};
|
||||||
if (!regs.zeta.Address() || !regs.zeta_enable) {
|
const auto gpu_addr{regs.zeta.Address()};
|
||||||
|
if (!gpu_addr || !regs.zeta_enable) {
|
||||||
return {{}, exctx};
|
return {{}, exctx};
|
||||||
}
|
}
|
||||||
|
|
||||||
auto& memory_manager{system.GPU().MemoryManager()};
|
|
||||||
const auto cpu_addr{memory_manager.GpuToCpuAddress(regs.zeta.Address())};
|
|
||||||
if (!cpu_addr) {
|
|
||||||
return {{}, exctx};
|
|
||||||
}
|
|
||||||
|
|
||||||
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, *cpu_addr, depth_params, preserve_contents);
|
return GetSurfaceView(exctx, gpu_addr, depth_params, preserve_contents);
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultType GetColorBufferSurface(TExecutionContext exctx, std::size_t index,
|
ResultType GetColorBufferSurface(TExecutionContext exctx, std::size_t index,
|
||||||
|
@ -448,25 +454,23 @@ public:
|
||||||
|
|
||||||
auto& memory_manager{system.GPU().MemoryManager()};
|
auto& memory_manager{system.GPU().MemoryManager()};
|
||||||
const auto& config{system.GPU().Maxwell3D().regs.rt[index]};
|
const auto& config{system.GPU().Maxwell3D().regs.rt[index]};
|
||||||
const auto cpu_addr{memory_manager.GpuToCpuAddress(
|
const auto gpu_addr{config.Address() +
|
||||||
config.Address() + config.base_layer * config.layer_stride * sizeof(u32))};
|
config.base_layer * config.layer_stride * sizeof(u32)};
|
||||||
if (!cpu_addr) {
|
if (!gpu_addr) {
|
||||||
return {{}, exctx};
|
return {{}, exctx};
|
||||||
}
|
}
|
||||||
|
|
||||||
return GetSurfaceView(exctx, *cpu_addr, SurfaceParams::CreateForFramebuffer(system, index),
|
return GetSurfaceView(exctx, gpu_addr, SurfaceParams::CreateForFramebuffer(system, index),
|
||||||
preserve_contents);
|
preserve_contents);
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultType GetFermiSurface(TExecutionContext exctx,
|
ResultType GetFermiSurface(TExecutionContext exctx,
|
||||||
const Tegra::Engines::Fermi2D::Regs::Surface& config) {
|
const Tegra::Engines::Fermi2D::Regs::Surface& config) {
|
||||||
const auto cpu_addr{system.GPU().MemoryManager().GpuToCpuAddress(config.Address())};
|
return GetSurfaceView(exctx, config.Address(),
|
||||||
ASSERT(cpu_addr);
|
SurfaceParams::CreateForFermiCopySurface(config), true);
|
||||||
return GetSurfaceView(exctx, *cpu_addr, SurfaceParams::CreateForFermiCopySurface(config),
|
|
||||||
true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TSurface* TryFindFramebufferSurface(const u8* host_ptr) const {
|
std::shared_ptr<TSurface> TryFindFramebufferSurface(const u8* host_ptr) const {
|
||||||
const auto it{registered_surfaces.find(ToCacheAddr(host_ptr))};
|
const auto it{registered_surfaces.find(ToCacheAddr(host_ptr))};
|
||||||
return it != registered_surfaces.end() ? *it->second.begin() : nullptr;
|
return it != registered_surfaces.end() ? *it->second.begin() : nullptr;
|
||||||
}
|
}
|
||||||
|
@ -477,56 +481,68 @@ protected:
|
||||||
|
|
||||||
~TextureCache() = default;
|
~TextureCache() = default;
|
||||||
|
|
||||||
virtual ResultType TryFastGetSurfaceView(TExecutionContext exctx, VAddr cpu_addr, u8* host_ptr,
|
virtual ResultType TryFastGetSurfaceView(
|
||||||
const SurfaceParams& params, bool preserve_contents,
|
TExecutionContext exctx, GPUVAddr gpu_addr, VAddr cpu_addr, u8* host_ptr,
|
||||||
const std::vector<TSurface*>& overlaps) = 0;
|
const SurfaceParams& params, bool preserve_contents,
|
||||||
|
const std::vector<std::shared_ptr<TSurface>>& overlaps) = 0;
|
||||||
|
|
||||||
virtual std::unique_ptr<TSurface> CreateSurface(const SurfaceParams& params) = 0;
|
virtual std::shared_ptr<TSurface> CreateSurface(const SurfaceParams& params) = 0;
|
||||||
|
|
||||||
void Register(TSurface* surface, VAddr cpu_addr, u8* host_ptr) {
|
void Register(std::shared_ptr<TSurface> surface, GPUVAddr gpu_addr, VAddr cpu_addr,
|
||||||
surface->Register(cpu_addr, host_ptr);
|
u8* host_ptr) {
|
||||||
|
surface->Register(gpu_addr, cpu_addr, host_ptr);
|
||||||
registered_surfaces.add({GetSurfaceInterval(surface), {surface}});
|
registered_surfaces.add({GetSurfaceInterval(surface), {surface}});
|
||||||
rasterizer.UpdatePagesCachedCount(surface->GetCpuAddr(), surface->GetSizeInBytes(), 1);
|
rasterizer.UpdatePagesCachedCount(surface->GetCpuAddr(), surface->GetSizeInBytes(), 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Unregister(TSurface* surface) {
|
void Unregister(std::shared_ptr<TSurface> surface) {
|
||||||
registered_surfaces.subtract({GetSurfaceInterval(surface), {surface}});
|
registered_surfaces.subtract({GetSurfaceInterval(surface), {surface}});
|
||||||
rasterizer.UpdatePagesCachedCount(surface->GetCpuAddr(), surface->GetSizeInBytes(), -1);
|
rasterizer.UpdatePagesCachedCount(surface->GetCpuAddr(), surface->GetSizeInBytes(), -1);
|
||||||
surface->Unregister();
|
surface->Unregister();
|
||||||
}
|
}
|
||||||
|
|
||||||
TSurface* GetUncachedSurface(const SurfaceParams& params) {
|
std::shared_ptr<TSurface> GetUncachedSurface(const SurfaceParams& params) {
|
||||||
if (TSurface* surface = TryGetReservedSurface(params); surface)
|
if (const auto surface = TryGetReservedSurface(params); surface)
|
||||||
return surface;
|
return surface;
|
||||||
// No reserved surface available, create a new one and reserve it
|
// No reserved surface available, create a new one and reserve it
|
||||||
auto new_surface{CreateSurface(params)};
|
auto new_surface{CreateSurface(params)};
|
||||||
TSurface* surface{new_surface.get()};
|
ReserveSurface(params, new_surface);
|
||||||
ReserveSurface(params, std::move(new_surface));
|
return new_surface;
|
||||||
return surface;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Core::System& system;
|
Core::System& system;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ResultType GetSurfaceView(TExecutionContext exctx, VAddr cpu_addr, const SurfaceParams& params,
|
ResultType GetSurfaceView(TExecutionContext exctx, GPUVAddr gpu_addr,
|
||||||
bool preserve_contents) {
|
const SurfaceParams& params, bool preserve_contents) {
|
||||||
const auto host_ptr{Memory::GetPointer(cpu_addr)};
|
auto& memory_manager{system.GPU().MemoryManager()};
|
||||||
|
const auto cpu_addr{memory_manager.GpuToCpuAddress(gpu_addr)};
|
||||||
|
DEBUG_ASSERT(cpu_addr);
|
||||||
|
|
||||||
|
const auto host_ptr{memory_manager.GetPointer(gpu_addr)};
|
||||||
const auto cache_addr{ToCacheAddr(host_ptr)};
|
const auto cache_addr{ToCacheAddr(host_ptr)};
|
||||||
const auto overlaps{GetSurfacesInRegion(cache_addr, params.GetGuestSizeInBytes())};
|
const auto overlaps{GetSurfacesInRegion(cache_addr, params.GetGuestSizeInBytes())};
|
||||||
if (overlaps.empty()) {
|
if (overlaps.empty()) {
|
||||||
return LoadSurfaceView(exctx, cpu_addr, host_ptr, params, preserve_contents);
|
return LoadSurfaceView(exctx, gpu_addr, *cpu_addr, host_ptr, params, preserve_contents);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (overlaps.size() == 1) {
|
if (overlaps.size() == 1) {
|
||||||
if (TView* view = overlaps[0]->TryGetView(cpu_addr, params); view)
|
if (TView* view = overlaps[0]->TryGetView(gpu_addr, params); view) {
|
||||||
return {view, exctx};
|
return {view, exctx};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TView* fast_view;
|
TView* fast_view;
|
||||||
std::tie(fast_view, exctx) =
|
std::tie(fast_view, exctx) = TryFastGetSurfaceView(exctx, gpu_addr, *cpu_addr, host_ptr,
|
||||||
TryFastGetSurfaceView(exctx, cpu_addr, host_ptr, params, preserve_contents, overlaps);
|
params, preserve_contents, overlaps);
|
||||||
|
|
||||||
for (TSurface* surface : overlaps) {
|
if (!fast_view) {
|
||||||
|
std::sort(overlaps.begin(), overlaps.end(), [](const auto& lhs, const auto& rhs) {
|
||||||
|
return lhs->GetModificationTick() < rhs->GetModificationTick();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const auto& surface : overlaps) {
|
||||||
if (!fast_view) {
|
if (!fast_view) {
|
||||||
// Flush even when we don't care about the contents, to preserve memory not written
|
// Flush even when we don't care about the contents, to preserve memory not written
|
||||||
// by the new surface.
|
// by the new surface.
|
||||||
|
@ -539,57 +555,59 @@ private:
|
||||||
return {fast_view, exctx};
|
return {fast_view, exctx};
|
||||||
}
|
}
|
||||||
|
|
||||||
return LoadSurfaceView(exctx, cpu_addr, host_ptr, params, preserve_contents);
|
return LoadSurfaceView(exctx, gpu_addr, *cpu_addr, host_ptr, params, preserve_contents);
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultType LoadSurfaceView(TExecutionContext exctx, VAddr cpu_addr, u8* host_ptr,
|
ResultType LoadSurfaceView(TExecutionContext exctx, GPUVAddr gpu_addr, VAddr cpu_addr,
|
||||||
const SurfaceParams& params, bool preserve_contents) {
|
u8* host_ptr, const SurfaceParams& params, bool preserve_contents) {
|
||||||
TSurface* new_surface{GetUncachedSurface(params)};
|
const auto new_surface{GetUncachedSurface(params)};
|
||||||
Register(new_surface, cpu_addr, host_ptr);
|
Register(new_surface, gpu_addr, cpu_addr, host_ptr);
|
||||||
if (preserve_contents) {
|
if (preserve_contents) {
|
||||||
exctx = LoadSurface(exctx, new_surface);
|
exctx = LoadSurface(exctx, new_surface);
|
||||||
}
|
}
|
||||||
return {new_surface->GetView(cpu_addr, params), exctx};
|
return {new_surface->GetView(gpu_addr, params), exctx};
|
||||||
}
|
}
|
||||||
|
|
||||||
TExecutionContext LoadSurface(TExecutionContext exctx, TSurface* surface) {
|
TExecutionContext LoadSurface(TExecutionContext exctx,
|
||||||
|
const std::shared_ptr<TSurface>& surface) {
|
||||||
surface->LoadBuffer();
|
surface->LoadBuffer();
|
||||||
exctx = surface->UploadTexture(exctx);
|
exctx = surface->UploadTexture(exctx);
|
||||||
surface->MarkAsModified(false);
|
surface->MarkAsModified(false);
|
||||||
return exctx;
|
return exctx;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<TSurface*> GetSurfacesInRegion(CacheAddr cache_addr, std::size_t size) const {
|
std::vector<std::shared_ptr<TSurface>> GetSurfacesInRegion(CacheAddr cache_addr,
|
||||||
|
std::size_t size) const {
|
||||||
if (size == 0) {
|
if (size == 0) {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
const IntervalType interval{cache_addr, cache_addr + size};
|
const IntervalType interval{cache_addr, cache_addr + size};
|
||||||
|
|
||||||
std::vector<TSurface*> surfaces;
|
std::vector<std::shared_ptr<TSurface>> surfaces;
|
||||||
for (auto& pair : boost::make_iterator_range(registered_surfaces.equal_range(interval))) {
|
for (auto& pair : boost::make_iterator_range(registered_surfaces.equal_range(interval))) {
|
||||||
surfaces.push_back(*pair.second.begin());
|
surfaces.push_back(*pair.second.begin());
|
||||||
}
|
}
|
||||||
return surfaces;
|
return surfaces;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ReserveSurface(const SurfaceParams& params, std::unique_ptr<TSurface> surface) {
|
void ReserveSurface(const SurfaceParams& params, std::shared_ptr<TSurface> surface) {
|
||||||
surface_reserve[params].push_back(std::move(surface));
|
surface_reserve[params].push_back(std::move(surface));
|
||||||
}
|
}
|
||||||
|
|
||||||
TSurface* TryGetReservedSurface(const SurfaceParams& params) {
|
std::shared_ptr<TSurface> TryGetReservedSurface(const SurfaceParams& params) {
|
||||||
auto search{surface_reserve.find(params)};
|
auto search{surface_reserve.find(params)};
|
||||||
if (search == surface_reserve.end()) {
|
if (search == surface_reserve.end()) {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
for (auto& surface : search->second) {
|
for (auto& surface : search->second) {
|
||||||
if (!surface->IsRegistered()) {
|
if (!surface->IsRegistered()) {
|
||||||
return surface.get();
|
return surface;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
IntervalType GetSurfaceInterval(TSurface* surface) const {
|
IntervalType GetSurfaceInterval(std::shared_ptr<TSurface> surface) const {
|
||||||
return IntervalType::right_open(surface->GetCacheAddr(),
|
return IntervalType::right_open(surface->GetCacheAddr(),
|
||||||
surface->GetCacheAddr() + surface->GetSizeInBytes());
|
surface->GetCacheAddr() + surface->GetSizeInBytes());
|
||||||
}
|
}
|
||||||
|
@ -601,7 +619,7 @@ private:
|
||||||
/// The surface reserve is a "backup" cache, this is where we put unique surfaces that have
|
/// The surface reserve is a "backup" cache, this is where we put unique surfaces that have
|
||||||
/// previously been used. This is to prevent surfaces from being constantly created and
|
/// previously been used. This is to prevent surfaces from being constantly created and
|
||||||
/// destroyed when used with different surface parameters.
|
/// destroyed when used with different surface parameters.
|
||||||
std::unordered_map<SurfaceParams, std::list<std::unique_ptr<TSurface>>> surface_reserve;
|
std::unordered_map<SurfaceParams, std::list<std::shared_ptr<TSurface>>> surface_reserve;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct DummyExecutionContext {};
|
struct DummyExecutionContext {};
|
||||||
|
@ -631,7 +649,7 @@ public:
|
||||||
return RemoveContext(Base::GetFermiSurface({}, config));
|
return RemoveContext(Base::GetFermiSurface({}, config));
|
||||||
}
|
}
|
||||||
|
|
||||||
TSurface* TryFindFramebufferSurface(const u8* host_ptr) const {
|
std::shared_ptr<TSurface> TryFindFramebufferSurface(const u8* host_ptr) const {
|
||||||
return Base::TryFindFramebufferSurface(host_ptr);
|
return Base::TryFindFramebufferSurface(host_ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -640,15 +658,18 @@ protected:
|
||||||
VideoCore::RasterizerInterface& rasterizer)
|
VideoCore::RasterizerInterface& rasterizer)
|
||||||
: TextureCache<TSurface, TView, DummyExecutionContext>{system, rasterizer} {}
|
: TextureCache<TSurface, TView, DummyExecutionContext>{system, rasterizer} {}
|
||||||
|
|
||||||
virtual TView* TryFastGetSurfaceView(VAddr cpu_addr, u8* host_ptr, const SurfaceParams& params,
|
virtual TView* TryFastGetSurfaceView(
|
||||||
bool preserve_contents,
|
GPUVAddr gpu_addr, VAddr cpu_addr, u8* host_ptr, const SurfaceParams& params,
|
||||||
const std::vector<TSurface*>& overlaps) = 0;
|
bool preserve_contents, const std::vector<std::shared_ptr<TSurface>>& overlaps) = 0;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::tuple<TView*, DummyExecutionContext> TryFastGetSurfaceView(
|
std::tuple<TView*, DummyExecutionContext> TryFastGetSurfaceView(
|
||||||
DummyExecutionContext, VAddr cpu_addr, u8* host_ptr, const SurfaceParams& params,
|
DummyExecutionContext, GPUVAddr gpu_addr, VAddr cpu_addr, u8* host_ptr,
|
||||||
bool preserve_contents, const std::vector<TSurface*>& overlaps) {
|
const SurfaceParams& params, bool preserve_contents,
|
||||||
return {TryFastGetSurfaceView(cpu_addr, host_ptr, params, preserve_contents, overlaps), {}};
|
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) {
|
TView* RemoveContext(std::tuple<TView*, DummyExecutionContext> return_value) {
|
||||||
|
|
Loading…
Reference in New Issue