gl_texture_cache: Initial implementation

This commit is contained in:
ReinUsesLisp 2019-04-11 17:14:55 -03:00
parent 80a8456af8
commit bab21e8cb3
9 changed files with 809 additions and 47 deletions

View file

@ -45,8 +45,6 @@ add_library(video_core STATIC
renderer_opengl/gl_global_cache.h renderer_opengl/gl_global_cache.h
renderer_opengl/gl_rasterizer.cpp renderer_opengl/gl_rasterizer.cpp
renderer_opengl/gl_rasterizer.h renderer_opengl/gl_rasterizer.h
renderer_opengl/gl_rasterizer_cache.cpp
renderer_opengl/gl_rasterizer_cache.h
renderer_opengl/gl_resource_manager.cpp renderer_opengl/gl_resource_manager.cpp
renderer_opengl/gl_resource_manager.h renderer_opengl/gl_resource_manager.h
renderer_opengl/gl_sampler_cache.cpp renderer_opengl/gl_sampler_cache.cpp
@ -67,6 +65,8 @@ add_library(video_core STATIC
renderer_opengl/gl_state.h renderer_opengl/gl_state.h
renderer_opengl/gl_stream_buffer.cpp renderer_opengl/gl_stream_buffer.cpp
renderer_opengl/gl_stream_buffer.h renderer_opengl/gl_stream_buffer.h
renderer_opengl/gl_texture_cache.cpp
renderer_opengl/gl_texture_cache.h
renderer_opengl/maxwell_to_gl.h renderer_opengl/maxwell_to_gl.h
renderer_opengl/renderer_opengl.cpp renderer_opengl/renderer_opengl.cpp
renderer_opengl/renderer_opengl.h renderer_opengl/renderer_opengl.h

View file

@ -100,7 +100,7 @@ struct FramebufferCacheKey {
RasterizerOpenGL::RasterizerOpenGL(Core::System& system, Core::Frontend::EmuWindow& emu_window, RasterizerOpenGL::RasterizerOpenGL(Core::System& system, Core::Frontend::EmuWindow& emu_window,
ScreenInfo& info) ScreenInfo& info)
: res_cache{*this}, shader_cache{*this, system, emu_window, device}, : texture_cache{system, *this}, shader_cache{*this, system, emu_window, device},
global_cache{*this}, system{system}, screen_info{info}, global_cache{*this}, system{system}, screen_info{info},
buffer_cache(*this, STREAM_BUFFER_SIZE) { buffer_cache(*this, STREAM_BUFFER_SIZE) {
OpenGLState::ApplyDefaultState(); OpenGLState::ApplyDefaultState();
@ -478,9 +478,9 @@ std::pair<bool, bool> RasterizerOpenGL::ConfigureFramebuffers(
} }
current_framebuffer_config_state = fb_config_state; current_framebuffer_config_state = fb_config_state;
Surface depth_surface; CachedSurfaceView* depth_surface{};
if (using_depth_fb) { if (using_depth_fb) {
depth_surface = res_cache.GetDepthBufferSurface(preserve_contents); depth_surface = texture_cache.GetDepthBufferSurface(preserve_contents);
} }
UNIMPLEMENTED_IF(regs.rt_separate_frag_data == 0); UNIMPLEMENTED_IF(regs.rt_separate_frag_data == 0);
@ -493,42 +493,43 @@ std::pair<bool, bool> RasterizerOpenGL::ConfigureFramebuffers(
if (using_color_fb) { if (using_color_fb) {
if (single_color_target) { if (single_color_target) {
// Used when just a single color attachment is enabled, e.g. for clearing a color buffer // Used when just a single color attachment is enabled, e.g. for clearing a color buffer
Surface color_surface = CachedSurfaceView* color_surface{
res_cache.GetColorBufferSurface(*single_color_target, preserve_contents); texture_cache.GetColorBufferSurface(*single_color_target, preserve_contents)};
if (color_surface) { if (color_surface) {
// Assume that a surface will be written to if it is used as a framebuffer, even if // Assume that a surface will be written to if it is used as a framebuffer, even if
// the shader doesn't actually write to it. // the shader doesn't actually write to it.
color_surface->MarkAsModified(true, res_cache); 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 |= color_surface->GetSurfaceParams().srgb_conversion; // state.framebuffer_srgb.enabled |=
// color_surface->GetSurfaceParams().srgb_conversion;
} }
fbkey.is_single_buffer = true; fbkey.is_single_buffer = true;
fbkey.color_attachments[0] = fbkey.color_attachments[0] =
GL_COLOR_ATTACHMENT0 + static_cast<GLenum>(*single_color_target); GL_COLOR_ATTACHMENT0 + static_cast<GLenum>(*single_color_target);
fbkey.colors[0] = color_surface != nullptr ? color_surface->Texture().handle : 0; fbkey.colors[0] = color_surface != nullptr ? color_surface->GetTexture() : 0;
} else { } else {
// Multiple color attachments are enabled // Multiple color attachments are enabled
for (std::size_t index = 0; index < Maxwell::NumRenderTargets; ++index) { for (std::size_t index = 0; index < Maxwell::NumRenderTargets; ++index) {
Surface color_surface = res_cache.GetColorBufferSurface(index, preserve_contents); CachedSurfaceView* color_surface{
texture_cache.GetColorBufferSurface(index, preserve_contents)};
if (color_surface) { if (color_surface) {
// Assume that a surface will be written to if it is used as a framebuffer, even // Assume that a surface will be written to if it is used as a framebuffer, even
// if the shader doesn't actually write to it. // if the shader doesn't actually write to it.
color_surface->MarkAsModified(true, res_cache); color_surface->MarkAsModified(true);
// 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().srgb_conversion;
} }
fbkey.color_attachments[index] = fbkey.color_attachments[index] =
GL_COLOR_ATTACHMENT0 + regs.rt_control.GetMap(index); GL_COLOR_ATTACHMENT0 + regs.rt_control.GetMap(index);
fbkey.colors[index] = fbkey.colors[index] = color_surface != nullptr ? color_surface->GetTexture() : 0;
color_surface != nullptr ? color_surface->Texture().handle : 0;
} }
fbkey.is_single_buffer = false; fbkey.is_single_buffer = false;
fbkey.colors_count = regs.rt_control.count; fbkey.colors_count = regs.rt_control.count;
@ -541,11 +542,11 @@ std::pair<bool, bool> RasterizerOpenGL::ConfigureFramebuffers(
if (depth_surface) { if (depth_surface) {
// Assume that a surface will be written to if it is used as a framebuffer, even if // Assume that a surface will be written to if it is used as a framebuffer, even if
// the shader doesn't actually write to it. // the shader doesn't actually write to it.
depth_surface->MarkAsModified(true, res_cache); depth_surface->MarkAsModified(true);
fbkey.zeta = depth_surface->Texture().handle; fbkey.zeta = depth_surface->GetTexture();
fbkey.stencil_enable = regs.stencil_enable && fbkey.stencil_enable = regs.stencil_enable && depth_surface->GetSurfaceParams().GetType() ==
depth_surface->GetSurfaceParams().type == SurfaceType::DepthStencil; SurfaceType::DepthStencil;
} }
SetupCachedFramebuffer(fbkey, current_state); SetupCachedFramebuffer(fbkey, current_state);
@ -704,9 +705,7 @@ void RasterizerOpenGL::DrawArrays() {
shader_program_manager->ApplyTo(state); shader_program_manager->ApplyTo(state);
state.Apply(); state.Apply();
res_cache.SignalPreDrawCall();
params.DispatchDraw(); params.DispatchDraw();
res_cache.SignalPostDrawCall();
accelerate_draw = AccelDraw::Disabled; accelerate_draw = AccelDraw::Disabled;
} }
@ -718,7 +717,7 @@ void RasterizerOpenGL::FlushRegion(CacheAddr addr, u64 size) {
if (!addr || !size) { if (!addr || !size) {
return; return;
} }
res_cache.FlushRegion(addr, size); // texture_cache.FlushRegion(addr, size);
global_cache.FlushRegion(addr, size); global_cache.FlushRegion(addr, size);
} }
@ -727,7 +726,7 @@ void RasterizerOpenGL::InvalidateRegion(CacheAddr addr, u64 size) {
if (!addr || !size) { if (!addr || !size) {
return; return;
} }
res_cache.InvalidateRegion(addr, size); texture_cache.InvalidateRegion(addr, size);
shader_cache.InvalidateRegion(addr, size); shader_cache.InvalidateRegion(addr, size);
global_cache.InvalidateRegion(addr, size); global_cache.InvalidateRegion(addr, size);
buffer_cache.InvalidateRegion(addr, size); buffer_cache.InvalidateRegion(addr, size);
@ -743,7 +742,8 @@ bool RasterizerOpenGL::AccelerateSurfaceCopy(const Tegra::Engines::Fermi2D::Regs
const Common::Rectangle<u32>& src_rect, const Common::Rectangle<u32>& src_rect,
const Common::Rectangle<u32>& dst_rect) { const Common::Rectangle<u32>& dst_rect) {
MICROPROFILE_SCOPE(OpenGL_Blits); MICROPROFILE_SCOPE(OpenGL_Blits);
res_cache.FermiCopySurface(src, dst, src_rect, dst_rect); UNIMPLEMENTED();
// texture_cache.FermiCopySurface(src, dst, src_rect, dst_rect);
return true; return true;
} }
@ -755,7 +755,8 @@ bool RasterizerOpenGL::AccelerateDisplay(const Tegra::FramebufferConfig& config,
MICROPROFILE_SCOPE(OpenGL_CacheManagement); MICROPROFILE_SCOPE(OpenGL_CacheManagement);
const auto& surface{res_cache.TryFindFramebufferSurface(Memory::GetPointer(framebuffer_addr))}; const auto surface{
texture_cache.TryFindFramebufferSurface(Memory::GetPointer(framebuffer_addr))};
if (!surface) { if (!surface) {
return {}; return {};
} }
@ -764,14 +765,14 @@ bool RasterizerOpenGL::AccelerateDisplay(const Tegra::FramebufferConfig& config,
const auto& params{surface->GetSurfaceParams()}; const auto& params{surface->GetSurfaceParams()};
const auto& pixel_format{ const auto& pixel_format{
VideoCore::Surface::PixelFormatFromGPUPixelFormat(config.pixel_format)}; VideoCore::Surface::PixelFormatFromGPUPixelFormat(config.pixel_format)};
ASSERT_MSG(params.width == config.width, "Framebuffer width is different"); ASSERT_MSG(params.GetWidth() == config.width, "Framebuffer width is different");
ASSERT_MSG(params.height == config.height, "Framebuffer height is different"); ASSERT_MSG(params.GetHeight() == config.height, "Framebuffer height is different");
if (params.pixel_format != pixel_format) { if (params.GetPixelFormat() != pixel_format) {
LOG_WARNING(Render_OpenGL, "Framebuffer pixel_format is different"); LOG_WARNING(Render_OpenGL, "Framebuffer pixel_format is different");
} }
screen_info.display_texture = surface->Texture().handle; screen_info.display_texture = surface->GetTexture();
return true; return true;
} }
@ -862,11 +863,10 @@ void RasterizerOpenGL::SetupTextures(Maxwell::ShaderStage stage, const Shader& s
state.texture_units[current_bindpoint].sampler = sampler_cache.GetSampler(texture.tsc); state.texture_units[current_bindpoint].sampler = sampler_cache.GetSampler(texture.tsc);
if (Surface surface = res_cache.GetTextureSurface(texture, entry); surface) { if (const auto surface{texture_cache.GetTextureSurface(texture)}; surface) {
state.texture_units[current_bindpoint].texture = state.texture_units[current_bindpoint].texture = surface->GetTexture(
surface->Texture(entry.IsArray()).handle; entry.GetType(), entry.IsArray(), texture.tic.x_source, texture.tic.y_source,
surface->UpdateSwizzle(texture.tic.x_source, texture.tic.y_source, texture.tic.z_source, texture.tic.z_source, texture.tic.w_source);
texture.tic.w_source);
} else { } else {
// Can occur when texture addr is null or its memory is unmapped/invalid // Can occur when texture addr is null or its memory is unmapped/invalid
state.texture_units[current_bindpoint].texture = 0; state.texture_units[current_bindpoint].texture = 0;

View file

@ -24,13 +24,13 @@
#include "video_core/renderer_opengl/gl_buffer_cache.h" #include "video_core/renderer_opengl/gl_buffer_cache.h"
#include "video_core/renderer_opengl/gl_device.h" #include "video_core/renderer_opengl/gl_device.h"
#include "video_core/renderer_opengl/gl_global_cache.h" #include "video_core/renderer_opengl/gl_global_cache.h"
#include "video_core/renderer_opengl/gl_rasterizer_cache.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_sampler_cache.h" #include "video_core/renderer_opengl/gl_sampler_cache.h"
#include "video_core/renderer_opengl/gl_shader_cache.h" #include "video_core/renderer_opengl/gl_shader_cache.h"
#include "video_core/renderer_opengl/gl_shader_decompiler.h" #include "video_core/renderer_opengl/gl_shader_decompiler.h"
#include "video_core/renderer_opengl/gl_shader_manager.h" #include "video_core/renderer_opengl/gl_shader_manager.h"
#include "video_core/renderer_opengl/gl_state.h" #include "video_core/renderer_opengl/gl_state.h"
#include "video_core/renderer_opengl/gl_texture_cache.h"
#include "video_core/renderer_opengl/utils.h" #include "video_core/renderer_opengl/utils.h"
namespace Core { namespace Core {
@ -181,7 +181,7 @@ private:
const Device device; const Device device;
OpenGLState state; OpenGLState state;
RasterizerCacheOpenGL res_cache; TextureCacheOpenGL texture_cache;
ShaderCacheOpenGL shader_cache; ShaderCacheOpenGL shader_cache;
GlobalRegionCacheOpenGL global_cache; GlobalRegionCacheOpenGL global_cache;
SamplerCacheOpenGL sampler_cache; SamplerCacheOpenGL sampler_cache;

View file

@ -0,0 +1,514 @@
// Copyright 2019 yuzu Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include "common/assert.h"
#include "common/common_types.h"
#include "common/scope_exit.h"
#include "video_core/morton.h"
#include "video_core/renderer_opengl/gl_resource_manager.h"
#include "video_core/renderer_opengl/gl_texture_cache.h"
#include "video_core/texture_cache.h"
#include "video_core/textures/convert.h"
#include "video_core/textures/texture.h"
namespace OpenGL {
using Tegra::Texture::ConvertFromGuestToHost;
using Tegra::Texture::SwizzleSource;
using VideoCore::MortonSwizzleMode;
namespace {
struct FormatTuple {
GLint internal_format;
GLenum format;
GLenum type;
ComponentType component_type;
bool compressed;
};
constexpr std::array<FormatTuple, VideoCore::Surface::MaxPixelFormat> tex_format_tuples = {{
{GL_RGBA8, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, ComponentType::UNorm, false}, // ABGR8U
{GL_RGBA8, GL_RGBA, GL_BYTE, ComponentType::SNorm, false}, // ABGR8S
{GL_RGBA8UI, GL_RGBA_INTEGER, GL_UNSIGNED_BYTE, ComponentType::UInt, false}, // ABGR8UI
{GL_RGB565, GL_RGB, GL_UNSIGNED_SHORT_5_6_5_REV, ComponentType::UNorm, false}, // B5G6R5U
{GL_RGB10_A2, GL_RGBA, GL_UNSIGNED_INT_2_10_10_10_REV, ComponentType::UNorm,
false}, // A2B10G10R10U
{GL_RGB5_A1, GL_RGBA, GL_UNSIGNED_SHORT_1_5_5_5_REV, ComponentType::UNorm, false}, // A1B5G5R5U
{GL_R8, GL_RED, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // R8U
{GL_R8UI, GL_RED_INTEGER, GL_UNSIGNED_BYTE, ComponentType::UInt, false}, // R8UI
{GL_RGBA16F, GL_RGBA, GL_HALF_FLOAT, ComponentType::Float, false}, // RGBA16F
{GL_RGBA16, GL_RGBA, GL_UNSIGNED_SHORT, ComponentType::UNorm, false}, // RGBA16U
{GL_RGBA16UI, GL_RGBA_INTEGER, GL_UNSIGNED_SHORT, ComponentType::UInt, false}, // RGBA16UI
{GL_R11F_G11F_B10F, GL_RGB, GL_UNSIGNED_INT_10F_11F_11F_REV, ComponentType::Float,
false}, // R11FG11FB10F
{GL_RGBA32UI, GL_RGBA_INTEGER, GL_UNSIGNED_INT, ComponentType::UInt, false}, // RGBA32UI
{GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, ComponentType::UNorm,
true}, // DXT1
{GL_COMPRESSED_RGBA_S3TC_DXT3_EXT, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, ComponentType::UNorm,
true}, // DXT23
{GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, ComponentType::UNorm,
true}, // DXT45
{GL_COMPRESSED_RED_RGTC1, GL_RED, GL_UNSIGNED_INT_8_8_8_8, ComponentType::UNorm, true}, // DXN1
{GL_COMPRESSED_RG_RGTC2, GL_RG, GL_UNSIGNED_INT_8_8_8_8, ComponentType::UNorm,
true}, // DXN2UNORM
{GL_COMPRESSED_SIGNED_RG_RGTC2, GL_RG, GL_INT, ComponentType::SNorm, true}, // DXN2SNORM
{GL_COMPRESSED_RGBA_BPTC_UNORM, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, ComponentType::UNorm,
true}, // BC7U
{GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT, GL_RGB, GL_UNSIGNED_INT_8_8_8_8, ComponentType::Float,
true}, // BC6H_UF16
{GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT, GL_RGB, GL_UNSIGNED_INT_8_8_8_8, ComponentType::Float,
true}, // BC6H_SF16
{GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // ASTC_2D_4X4
{GL_RGBA8, GL_BGRA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // BGRA8
{GL_RGBA32F, GL_RGBA, GL_FLOAT, ComponentType::Float, false}, // RGBA32F
{GL_RG32F, GL_RG, GL_FLOAT, ComponentType::Float, false}, // RG32F
{GL_R32F, GL_RED, GL_FLOAT, ComponentType::Float, false}, // R32F
{GL_R16F, GL_RED, GL_HALF_FLOAT, ComponentType::Float, false}, // R16F
{GL_R16, GL_RED, GL_UNSIGNED_SHORT, ComponentType::UNorm, false}, // R16U
{GL_R16_SNORM, GL_RED, GL_SHORT, ComponentType::SNorm, false}, // R16S
{GL_R16UI, GL_RED_INTEGER, GL_UNSIGNED_SHORT, ComponentType::UInt, false}, // R16UI
{GL_R16I, GL_RED_INTEGER, GL_SHORT, ComponentType::SInt, false}, // R16I
{GL_RG16, GL_RG, GL_UNSIGNED_SHORT, ComponentType::UNorm, false}, // RG16
{GL_RG16F, GL_RG, GL_HALF_FLOAT, ComponentType::Float, false}, // RG16F
{GL_RG16UI, GL_RG_INTEGER, GL_UNSIGNED_SHORT, ComponentType::UInt, false}, // RG16UI
{GL_RG16I, GL_RG_INTEGER, GL_SHORT, ComponentType::SInt, false}, // RG16I
{GL_RG16_SNORM, GL_RG, GL_SHORT, ComponentType::SNorm, false}, // RG16S
{GL_RGB32F, GL_RGB, GL_FLOAT, ComponentType::Float, false}, // RGB32F
{GL_SRGB8_ALPHA8, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, ComponentType::UNorm,
false}, // RGBA8_SRGB
{GL_RG8, GL_RG, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // RG8U
{GL_RG8, GL_RG, GL_BYTE, ComponentType::SNorm, false}, // RG8S
{GL_RG32UI, GL_RG_INTEGER, GL_UNSIGNED_INT, ComponentType::UInt, false}, // RG32UI
{GL_R32UI, GL_RED_INTEGER, GL_UNSIGNED_INT, ComponentType::UInt, false}, // R32UI
{GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // ASTC_2D_8X8
{GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // ASTC_2D_8X5
{GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // ASTC_2D_5X4
{GL_SRGB8_ALPHA8, GL_BGRA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // BGRA8
// Compressed sRGB formats
{GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, ComponentType::UNorm,
true}, // DXT1_SRGB
{GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, ComponentType::UNorm,
true}, // DXT23_SRGB
{GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, ComponentType::UNorm,
true}, // DXT45_SRGB
{GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, ComponentType::UNorm,
true}, // BC7U_SRGB
{GL_SRGB8_ALPHA8, GL_RGBA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // ASTC_2D_4X4_SRGB
{GL_SRGB8_ALPHA8, GL_RGBA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // ASTC_2D_8X8_SRGB
{GL_SRGB8_ALPHA8, GL_RGBA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // ASTC_2D_8X5_SRGB
{GL_SRGB8_ALPHA8, GL_RGBA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // ASTC_2D_5X4_SRGB
{GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // ASTC_2D_5X5
{GL_SRGB8_ALPHA8, GL_RGBA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // ASTC_2D_5X5_SRGB
{GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // ASTC_2D_10X8
{GL_SRGB8_ALPHA8, GL_RGBA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // ASTC_2D_10X8_SRGB
// Depth formats
{GL_DEPTH_COMPONENT32F, GL_DEPTH_COMPONENT, GL_FLOAT, ComponentType::Float, false}, // Z32F
{GL_DEPTH_COMPONENT16, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT, ComponentType::UNorm,
false}, // Z16
// DepthStencil formats
{GL_DEPTH24_STENCIL8, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, ComponentType::UNorm,
false}, // Z24S8
{GL_DEPTH24_STENCIL8, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, ComponentType::UNorm,
false}, // S8Z24
{GL_DEPTH32F_STENCIL8, GL_DEPTH_STENCIL, GL_FLOAT_32_UNSIGNED_INT_24_8_REV,
ComponentType::Float, false}, // Z32FS8
}};
const FormatTuple& GetFormatTuple(PixelFormat pixel_format, ComponentType component_type) {
ASSERT(static_cast<std::size_t>(pixel_format) < tex_format_tuples.size());
const auto& format{tex_format_tuples[static_cast<std::size_t>(pixel_format)]};
ASSERT(component_type == format.component_type);
return format;
}
GLenum GetTextureTarget(const SurfaceParams& params) {
switch (params.GetTarget()) {
case SurfaceTarget::Texture1D:
return GL_TEXTURE_1D;
case SurfaceTarget::Texture2D:
return GL_TEXTURE_2D;
case SurfaceTarget::Texture3D:
return GL_TEXTURE_3D;
case SurfaceTarget::Texture1DArray:
return GL_TEXTURE_1D_ARRAY;
case SurfaceTarget::Texture2DArray:
return GL_TEXTURE_2D_ARRAY;
case SurfaceTarget::TextureCubemap:
return GL_TEXTURE_CUBE_MAP;
case SurfaceTarget::TextureCubeArray:
return GL_TEXTURE_CUBE_MAP_ARRAY;
}
UNREACHABLE();
return {};
}
GLint GetSwizzleSource(SwizzleSource source) {
switch (source) {
case SwizzleSource::Zero:
return GL_ZERO;
case SwizzleSource::R:
return GL_RED;
case SwizzleSource::G:
return GL_GREEN;
case SwizzleSource::B:
return GL_BLUE;
case SwizzleSource::A:
return GL_ALPHA;
case SwizzleSource::OneInt:
case SwizzleSource::OneFloat:
return GL_ONE;
}
UNREACHABLE();
return GL_NONE;
}
void ApplyTextureDefaults(const SurfaceParams& params, GLuint texture) {
glTextureParameteri(texture, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTextureParameteri(texture, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTextureParameteri(texture, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTextureParameteri(texture, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTextureParameteri(texture, GL_TEXTURE_MAX_LEVEL, params.GetNumLevels() - 1);
if (params.GetNumLevels() == 1) {
glTextureParameterf(texture, GL_TEXTURE_LOD_BIAS, 1000.0f);
}
}
OGLTexture CreateTexture(const SurfaceParams& params, GLenum internal_format) {
OGLTexture texture;
texture.Create(GetTextureTarget(params));
switch (params.GetTarget()) {
case SurfaceTarget::Texture1D:
glTextureStorage1D(texture.handle, params.GetNumLevels(), internal_format,
params.GetWidth());
break;
case SurfaceTarget::Texture2D:
case SurfaceTarget::TextureCubemap:
glTextureStorage2D(texture.handle, params.GetNumLevels(), internal_format,
params.GetWidth(), params.GetHeight());
break;
case SurfaceTarget::Texture3D:
case SurfaceTarget::Texture2DArray:
case SurfaceTarget::TextureCubeArray:
glTextureStorage3D(texture.handle, params.GetNumLevels(), internal_format,
params.GetWidth(), params.GetHeight(), params.GetDepth());
break;
default:
UNREACHABLE();
}
ApplyTextureDefaults(params, texture.handle);
return texture;
}
void SwizzleFunc(MortonSwizzleMode mode, u8* memory, const SurfaceParams& params, u8* buffer,
u32 level) {
const u32 width{params.GetMipWidth(level)};
const u32 height{params.GetMipHeight(level)};
const u32 block_height{params.GetMipBlockHeight(level)};
const u32 block_depth{params.GetMipBlockDepth(level)};
std::size_t guest_offset{params.GetGuestMipmapLevelOffset(level)};
if (params.IsLayered()) {
std::size_t host_offset{0};
const std::size_t guest_stride = params.GetGuestLayerSize();
const std::size_t host_stride = params.GetHostLayerSize(level);
for (u32 layer = 0; layer < params.GetNumLayers(); layer++) {
MortonSwizzle(mode, params.GetPixelFormat(), width, block_height, height, block_depth,
1, params.GetTileWidthSpacing(), buffer + host_offset,
memory + guest_offset);
guest_offset += guest_stride;
host_offset += host_stride;
}
} else {
MortonSwizzle(mode, params.GetPixelFormat(), width, block_height, height, block_depth,
params.GetMipDepth(level), params.GetTileWidthSpacing(), buffer,
memory + guest_offset);
}
}
} // Anonymous namespace
CachedSurface::CachedSurface(const SurfaceParams& params)
: VideoCommon::SurfaceBaseContextless<CachedSurfaceView>{params} {
const auto& tuple{GetFormatTuple(params.GetPixelFormat(), params.GetComponentType())};
internal_format = tuple.internal_format;
format = tuple.format;
type = tuple.type;
is_compressed = tuple.compressed;
texture = CreateTexture(params, internal_format);
staging_buffer.resize(params.GetHostSizeInBytes());
}
CachedSurface::~CachedSurface() = default;
void CachedSurface::LoadBuffer() {
if (params.IsTiled()) {
ASSERT_MSG(params.GetBlockWidth() == 1, "Block width is defined as {} on texture target {}",
params.GetBlockWidth(), static_cast<u32>(params.GetTarget()));
for (u32 level = 0; level < params.GetNumLevels(); ++level) {
u8* const buffer{staging_buffer.data() + params.GetHostMipmapLevelOffset(level)};
SwizzleFunc(MortonSwizzleMode::MortonToLinear, GetHostPtr(), params, buffer, level);
}
} else {
ASSERT_MSG(params.GetNumLevels() == 1, "Linear mipmap loading is not implemented");
const u32 bpp{GetFormatBpp(params.GetPixelFormat()) / CHAR_BIT};
const u32 block_width{VideoCore::Surface::GetDefaultBlockWidth(params.GetPixelFormat())};
const u32 block_height{VideoCore::Surface::GetDefaultBlockHeight(params.GetPixelFormat())};
const u32 width{(params.GetWidth() + block_width - 1) / block_width};
const u32 height{(params.GetHeight() + block_height - 1) / block_height};
const u32 copy_size{width * bpp};
if (params.GetPitch() == copy_size) {
std::memcpy(staging_buffer.data(), GetHostPtr(), params.GetHostSizeInBytes());
} else {
const u8* start{GetHostPtr()};
u8* write_to{staging_buffer.data()};
for (u32 h = height; h > 0; --h) {
std::memcpy(write_to, start, copy_size);
start += params.GetPitch();
write_to += copy_size;
}
}
}
for (u32 level = 0; level < params.GetNumLevels(); ++level) {
ConvertFromGuestToHost(staging_buffer.data() + params.GetHostMipmapLevelOffset(level),
params.GetPixelFormat(), params.GetMipWidth(level),
params.GetMipHeight(level), params.GetMipDepth(level), true, true);
}
}
void CachedSurface::FlushBufferImpl() {
if (!IsModified()) {
return;
}
// TODO(Rodrigo): Optimize alignment
glPixelStorei(GL_PACK_ALIGNMENT, 1);
SCOPE_EXIT({ glPixelStorei(GL_PACK_ROW_LENGTH, 0); });
for (u32 level = 0; level < params.GetNumLevels(); ++level) {
glPixelStorei(GL_PACK_ROW_LENGTH, static_cast<GLint>(params.GetMipWidth(level)));
if (is_compressed) {
glGetCompressedTextureImage(
texture.handle, level, static_cast<GLsizei>(params.GetHostMipmapSize(level)),
staging_buffer.data() + params.GetHostMipmapLevelOffset(level));
} else {
glGetTextureImage(texture.handle, level, format, type,
static_cast<GLsizei>(params.GetHostMipmapSize(level)),
staging_buffer.data() + params.GetHostMipmapLevelOffset(level));
}
}
if (params.IsTiled()) {
ASSERT_MSG(params.GetBlockWidth() == 1, "Block width is defined as {}",
params.GetBlockWidth());
for (u32 level = 0; level < params.GetNumLevels(); ++level) {
u8* const buffer = staging_buffer.data() + params.GetHostMipmapLevelOffset(level);
SwizzleFunc(MortonSwizzleMode::LinearToMorton, GetHostPtr(), params, buffer, level);
}
} else {
UNIMPLEMENTED();
/*
ASSERT(params.GetTarget() == SurfaceTarget::Texture2D);
ASSERT(params.GetNumLevels() == 1);
const u32 bpp{params.GetFormatBpp() / 8};
const u32 copy_size{params.GetWidth() * bpp};
if (params.GetPitch() == copy_size) {
std::memcpy(host_ptr, staging_buffer.data(), GetSizeInBytes());
} else {
u8* start{host_ptr};
const u8* read_to{staging_buffer.data()};
for (u32 h = params.GetHeight(); h > 0; --h) {
std::memcpy(start, read_to, copy_size);
start += params.GetPitch();
read_to += copy_size;
}
}
*/
}
}
void CachedSurface::UploadTextureImpl() {
for (u32 level = 0; level < params.GetNumLevels(); ++level) {
UploadTextureMipmap(level);
}
}
void CachedSurface::UploadTextureMipmap(u32 level) {
u8* buffer{staging_buffer.data() + params.GetHostMipmapLevelOffset(level)};
// TODO(Rodrigo): Optimize alignment
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glPixelStorei(GL_UNPACK_ROW_LENGTH, static_cast<GLint>(params.GetMipWidth(level)));
SCOPE_EXIT({ glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); });
if (is_compressed) {
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()) {
case SurfaceTarget::Texture2D:
glCompressedTextureSubImage2D(texture.handle, level, 0, 0,
static_cast<GLsizei>(params.GetMipWidth(level)),
static_cast<GLsizei>(params.GetMipHeight(level)),
internal_format, image_size, buffer);
break;
case SurfaceTarget::Texture3D:
case SurfaceTarget::Texture2DArray:
case SurfaceTarget::TextureCubeArray:
glCompressedTextureSubImage3D(texture.handle, level, 0, 0, 0,
static_cast<GLsizei>(params.GetMipWidth(level)),
static_cast<GLsizei>(params.GetMipHeight(level)),
static_cast<GLsizei>(params.GetMipDepth(level)),
internal_format, image_size, buffer);
break;
case SurfaceTarget::TextureCubemap: {
const std::size_t layer_size{params.GetHostLayerSize(level)};
for (std::size_t face = 0; face < params.GetDepth(); ++face) {
glCompressedTextureSubImage3D(texture.handle, level, 0, 0, static_cast<GLint>(face),
static_cast<GLsizei>(params.GetMipWidth(level)),
static_cast<GLsizei>(params.GetMipHeight(level)), 1,
internal_format, static_cast<GLsizei>(layer_size),
buffer);
buffer += layer_size;
}
break;
}
default:
UNREACHABLE();
}
} else {
switch (params.GetTarget()) {
case SurfaceTarget::Texture1D:
glTextureSubImage1D(texture.handle, level, 0, params.GetMipWidth(level), format, type,
buffer);
break;
case SurfaceTarget::Texture1DArray:
case SurfaceTarget::Texture2D:
glTextureSubImage2D(texture.handle, level, 0, 0, params.GetMipWidth(level),
params.GetMipHeight(level), format, type, buffer);
break;
case SurfaceTarget::Texture3D:
case SurfaceTarget::Texture2DArray:
case SurfaceTarget::TextureCubeArray:
glTextureSubImage3D(
texture.handle, level, 0, 0, 0, static_cast<GLsizei>(params.GetMipWidth(level)),
static_cast<GLsizei>(params.GetMipHeight(level)),
static_cast<GLsizei>(params.GetMipDepth(level)), format, type, buffer);
break;
case SurfaceTarget::TextureCubemap:
for (std::size_t face = 0; face < params.GetDepth(); ++face) {
glTextureSubImage3D(texture.handle, level, 0, 0, static_cast<GLint>(face),
params.GetMipWidth(level), params.GetMipHeight(level), 1,
format, type, buffer);
buffer += params.GetHostLayerSize(level);
}
break;
default:
UNREACHABLE();
}
}
}
std::unique_ptr<CachedSurfaceView> CachedSurface::CreateView(const ViewKey& view_key) {
return std::make_unique<CachedSurfaceView>(*this, view_key);
}
CachedSurfaceView::CachedSurfaceView(CachedSurface& surface, ViewKey key)
: surface{surface}, key{key}, params{surface.GetSurfaceParams()} {}
CachedSurfaceView::~CachedSurfaceView() = default;
GLuint CachedSurfaceView::GetTexture() {
// TODO(Rodrigo): Remove this entry and attach the super texture to the framebuffer through
// legacy API (also dropping Intel driver issues).
if (texture_view_2d.texture.handle == 0) {
texture_view_2d = CreateTextureView(GL_TEXTURE_2D);
}
return texture_view_2d.texture.handle;
}
GLuint CachedSurfaceView::GetTexture(Tegra::Shader::TextureType texture_type, bool is_array,
SwizzleSource x_source, SwizzleSource y_source,
SwizzleSource z_source, SwizzleSource w_source) {
const auto [texture_view, target] = GetTextureView(texture_type, is_array);
if (texture_view.get().texture.handle == 0) {
texture_view.get() = std::move(CreateTextureView(target));
}
ApplySwizzle(texture_view, x_source, y_source, z_source, w_source);
return texture_view.get().texture.handle;
}
void CachedSurfaceView::ApplySwizzle(TextureView& texture_view, SwizzleSource x_source,
SwizzleSource y_source, SwizzleSource z_source,
SwizzleSource w_source) {
const std::array<SwizzleSource, 4> swizzle = {x_source, y_source, z_source, w_source};
if (swizzle == texture_view.swizzle) {
return;
}
const std::array<GLint, 4> gl_swizzle = {GetSwizzleSource(x_source), GetSwizzleSource(y_source),
GetSwizzleSource(z_source),
GetSwizzleSource(w_source)};
glTextureParameteriv(texture_view.texture.handle, GL_TEXTURE_SWIZZLE_RGBA, gl_swizzle.data());
texture_view.swizzle = swizzle;
}
CachedSurfaceView::TextureView CachedSurfaceView::CreateTextureView(GLenum target) const {
TextureView texture_view;
glGenTextures(1, &texture_view.texture.handle);
const GLuint handle{texture_view.texture.handle};
const FormatTuple& tuple{GetFormatTuple(params.GetPixelFormat(), params.GetComponentType())};
glTextureView(handle, target, surface.texture.handle, tuple.internal_format, key.base_level,
key.num_levels, key.base_layer, key.num_layers);
ApplyTextureDefaults(params, handle);
return texture_view;
}
std::pair<std::reference_wrapper<CachedSurfaceView::TextureView>, GLenum>
CachedSurfaceView::GetTextureView(Tegra::Shader::TextureType texture_type, bool is_array) {
using Pair = std::pair<std::reference_wrapper<TextureView>, GLenum>;
switch (texture_type) {
case Tegra::Shader::TextureType::Texture1D:
return is_array ? Pair{texture_view_1d_array, GL_TEXTURE_1D_ARRAY}
: Pair{texture_view_1d, GL_TEXTURE_1D};
case Tegra::Shader::TextureType::Texture2D:
return is_array ? Pair{texture_view_2d_array, GL_TEXTURE_2D_ARRAY}
: Pair{texture_view_2d, GL_TEXTURE_2D};
case Tegra::Shader::TextureType::Texture3D:
ASSERT(!is_array);
return {texture_view_3d, GL_TEXTURE_3D};
case Tegra::Shader::TextureType::TextureCube:
return is_array ? Pair{texture_view_cube_array, GL_TEXTURE_CUBE_MAP_ARRAY}
: Pair{texture_view_cube, GL_TEXTURE_CUBE_MAP};
}
UNREACHABLE();
}
TextureCacheOpenGL::TextureCacheOpenGL(Core::System& system,
VideoCore::RasterizerInterface& rasterizer)
: TextureCacheBase{system, rasterizer} {}
TextureCacheOpenGL::~TextureCacheOpenGL() = default;
CachedSurfaceView* TextureCacheOpenGL::TryFastGetSurfaceView(
VAddr cpu_addr, u8* host_ptr, const SurfaceParams& params, bool preserve_contents,
const std::vector<CachedSurface*>& overlaps) {
return nullptr;
}
std::unique_ptr<CachedSurface> TextureCacheOpenGL::CreateSurface(const SurfaceParams& params) {
return std::make_unique<CachedSurface>(params);
}
} // namespace OpenGL

View file

@ -0,0 +1,131 @@
// Copyright 2019 yuzu Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include <array>
#include <functional>
#include <utility>
#include <vector>
#include <glad/glad.h>
#include "common/common_types.h"
#include "video_core/engines/shader_bytecode.h"
#include "video_core/texture_cache.h"
namespace OpenGL {
using VideoCommon::SurfaceParams;
using VideoCommon::ViewKey;
using VideoCore::Surface::ComponentType;
using VideoCore::Surface::PixelFormat;
using VideoCore::Surface::SurfaceTarget;
using VideoCore::Surface::SurfaceType;
class CachedSurfaceView;
class CachedSurface;
using TextureCacheBase = VideoCommon::TextureCacheContextless<CachedSurface, CachedSurfaceView>;
class CachedSurface final : public VideoCommon::SurfaceBaseContextless<CachedSurfaceView> {
friend CachedSurfaceView;
public:
explicit CachedSurface(const SurfaceParams& params);
~CachedSurface();
void LoadBuffer();
GLuint GetTexture() const {
return texture.handle;
}
protected:
std::unique_ptr<CachedSurfaceView> CreateView(const ViewKey& view_key);
void FlushBufferImpl();
void UploadTextureImpl();
private:
void UploadTextureMipmap(u32 level);
GLenum internal_format{};
GLenum format{};
GLenum type{};
bool is_compressed{};
OGLTexture texture;
std::vector<u8> staging_buffer;
u8* host_ptr{};
};
class CachedSurfaceView final {
public:
explicit CachedSurfaceView(CachedSurface& surface, ViewKey key);
~CachedSurfaceView();
GLuint GetTexture();
GLuint GetTexture(Tegra::Shader::TextureType texture_type, bool is_array,
Tegra::Texture::SwizzleSource x_source,
Tegra::Texture::SwizzleSource y_source,
Tegra::Texture::SwizzleSource z_source,
Tegra::Texture::SwizzleSource w_source);
void MarkAsModified(bool is_modified) {
surface.MarkAsModified(is_modified);
}
const SurfaceParams& GetSurfaceParams() const {
return params;
}
private:
struct TextureView {
OGLTexture texture;
std::array<Tegra::Texture::SwizzleSource, 4> swizzle{
Tegra::Texture::SwizzleSource::R, Tegra::Texture::SwizzleSource::G,
Tegra::Texture::SwizzleSource::B, Tegra::Texture::SwizzleSource::A};
};
void ApplySwizzle(TextureView& texture_view, Tegra::Texture::SwizzleSource x_source,
Tegra::Texture::SwizzleSource y_source,
Tegra::Texture::SwizzleSource z_source,
Tegra::Texture::SwizzleSource w_source);
TextureView CreateTextureView(GLenum target) const;
std::pair<std::reference_wrapper<TextureView>, GLenum> GetTextureView(
Tegra::Shader::TextureType texture_type, bool is_array);
CachedSurface& surface;
const ViewKey key;
const SurfaceParams params;
TextureView texture_view_1d;
TextureView texture_view_1d_array;
TextureView texture_view_2d;
TextureView texture_view_2d_array;
TextureView texture_view_3d;
TextureView texture_view_cube;
TextureView texture_view_cube_array;
};
class TextureCacheOpenGL final : public TextureCacheBase {
public:
explicit TextureCacheOpenGL(Core::System& system, VideoCore::RasterizerInterface& rasterizer);
~TextureCacheOpenGL();
protected:
CachedSurfaceView* TryFastGetSurfaceView(VAddr cpu_addr, u8* host_ptr,
const SurfaceParams& params, bool preserve_contents,
const std::vector<CachedSurface*>& overlaps);
std::unique_ptr<CachedSurface> CreateSurface(const SurfaceParams& params);
};
} // namespace OpenGL

View file

@ -460,6 +460,7 @@ static void APIENTRY DebugHandler(GLenum source, GLenum type, GLuint id, GLenum
switch (severity) { switch (severity) {
case GL_DEBUG_SEVERITY_HIGH: case GL_DEBUG_SEVERITY_HIGH:
LOG_CRITICAL(Render_OpenGL, format, str_source, str_type, id, message); LOG_CRITICAL(Render_OpenGL, format, str_source, str_type, id, message);
__debugbreak();
break; break;
case GL_DEBUG_SEVERITY_MEDIUM: case GL_DEBUG_SEVERITY_MEDIUM:
LOG_WARNING(Render_OpenGL, format, str_source, str_type, id, message); LOG_WARNING(Render_OpenGL, format, str_source, str_type, id, message);

View file

@ -163,7 +163,7 @@ u32 SurfaceParams::GetMipBlockHeight(u32 level) const {
return block_height; return block_height;
} }
const u32 height{GetMipHeight(level)}; const u32 height{GetMipHeight(level)};
const u32 default_block_height{GetDefaultBlockHeight(pixel_format)}; 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};
u32 block_height = 16; u32 block_height = 16;
while (block_height > 1 && blocks_in_y <= block_height * 4) { while (block_height > 1 && blocks_in_y <= block_height * 4) {
@ -205,6 +205,10 @@ std::size_t SurfaceParams::GetHostMipmapLevelOffset(u32 level) const {
return offset; return offset;
} }
std::size_t SurfaceParams::GetHostMipmapSize(u32 level) const {
return GetInnerMipmapMemorySize(level, true, true, false) * GetNumLayers();
}
std::size_t SurfaceParams::GetGuestLayerSize() const { std::size_t SurfaceParams::GetGuestLayerSize() const {
return GetInnerMemorySize(false, true, false); return GetInnerMemorySize(false, true, false);
} }
@ -213,6 +217,22 @@ std::size_t SurfaceParams::GetHostLayerSize(u32 level) const {
return GetInnerMipmapMemorySize(level, true, IsLayered(), false); return GetInnerMipmapMemorySize(level, true, IsLayered(), false);
} }
u32 SurfaceParams::GetDefaultBlockWidth() const {
return VideoCore::Surface::GetDefaultBlockWidth(pixel_format);
}
u32 SurfaceParams::GetDefaultBlockHeight() const {
return VideoCore::Surface::GetDefaultBlockHeight(pixel_format);
}
u32 SurfaceParams::GetBitsPerPixel() const {
return VideoCore::Surface::GetFormatBpp(pixel_format);
}
u32 SurfaceParams::GetBytesPerPixel() const {
return VideoCore::Surface::GetBytesPerPixel(pixel_format);
}
bool SurfaceParams::IsFamiliar(const SurfaceParams& view_params) const { bool SurfaceParams::IsFamiliar(const SurfaceParams& view_params) const {
if (std::tie(is_tiled, tile_width_spacing, pixel_format, component_type, type) != if (std::tie(is_tiled, tile_width_spacing, pixel_format, component_type, type) !=
std::tie(view_params.is_tiled, view_params.tile_width_spacing, view_params.pixel_format, std::tie(view_params.is_tiled, view_params.tile_width_spacing, view_params.pixel_format,
@ -257,7 +277,7 @@ void SurfaceParams::CalculateCachedValues() {
// ASTC is uncompressed in software, in emulated as RGBA8 // ASTC is uncompressed in software, in emulated as RGBA8
if (IsPixelFormatASTC(pixel_format)) { if (IsPixelFormatASTC(pixel_format)) {
host_size_in_bytes = width * height * depth * 4; host_size_in_bytes = static_cast<std::size_t>(width * height * depth) * 4ULL;
} else { } else {
host_size_in_bytes = GetInnerMemorySize(true, false, false); host_size_in_bytes = GetInnerMemorySize(true, false, false);
} }
@ -282,13 +302,11 @@ void SurfaceParams::CalculateCachedValues() {
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 layer_only,
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 tile_x{GetDefaultBlockWidth(pixel_format)}; const u32 width{GetMipmapSize(uncompressed, GetMipWidth(level), GetDefaultBlockWidth())};
const u32 tile_y{GetDefaultBlockHeight(pixel_format)}; const u32 height{GetMipmapSize(uncompressed, GetMipHeight(level), GetDefaultBlockHeight())};
const u32 width{GetMipmapSize(uncompressed, GetMipWidth(level), tile_x)};
const u32 height{GetMipmapSize(uncompressed, GetMipHeight(level), tile_y)};
const u32 depth{layer_only ? 1U : GetMipDepth(level)}; const u32 depth{layer_only ? 1U : GetMipDepth(level)};
return Tegra::Texture::CalculateSize(tiled, GetBytesPerPixel(pixel_format), width, height, return Tegra::Texture::CalculateSize(tiled, GetBytesPerPixel(), width, height, depth,
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,
@ -297,7 +315,7 @@ std::size_t SurfaceParams::GetInnerMemorySize(bool as_host_size, bool layer_only
for (u32 level = 0; level < num_levels; ++level) { for (u32 level = 0; level < num_levels; ++level) {
size += GetInnerMipmapMemorySize(level, as_host_size, layer_only, uncompressed); size += GetInnerMipmapMemorySize(level, as_host_size, layer_only, uncompressed);
} }
if (!as_host_size && is_tiled) { if (is_tiled && !as_host_size) {
size = Common::AlignUp(size, Tegra::Texture::GetGOBSize() * block_height * block_depth); size = Common::AlignUp(size, Tegra::Texture::GetGOBSize() * block_height * block_depth);
} }
return size; return size;
@ -309,6 +327,7 @@ std::map<u64, std::pair<u32, u32>> SurfaceParams::CreateViewOffsetMap() const {
case SurfaceTarget::Texture1D: case SurfaceTarget::Texture1D:
case SurfaceTarget::Texture2D: case SurfaceTarget::Texture2D:
case SurfaceTarget::Texture3D: { case SurfaceTarget::Texture3D: {
// TODO(Rodrigo): Add layer iterations for 3D textures
constexpr u32 layer = 0; constexpr u32 layer = 0;
for (u32 level = 0; level < num_levels; ++level) { for (u32 level = 0; level < num_levels; ++level) {
const std::size_t offset{GetGuestMipmapLevelOffset(level)}; const std::size_t offset{GetGuestMipmapLevelOffset(level)};

View file

@ -20,6 +20,7 @@
#include "video_core/engines/fermi_2d.h" #include "video_core/engines/fermi_2d.h"
#include "video_core/engines/maxwell_3d.h" #include "video_core/engines/maxwell_3d.h"
#include "video_core/gpu.h" #include "video_core/gpu.h"
#include "video_core/memory_manager.h"
#include "video_core/rasterizer_interface.h" #include "video_core/rasterizer_interface.h"
#include "video_core/surface.h" #include "video_core/surface.h"
@ -43,6 +44,10 @@ public:
bool operator==(const HasheableSurfaceParams& rhs) const; bool operator==(const HasheableSurfaceParams& rhs) const;
bool operator!=(const HasheableSurfaceParams& rhs) const {
return !operator==(rhs);
}
protected: protected:
// Avoid creation outside of a managed environment. // Avoid creation outside of a managed environment.
HasheableSurfaceParams() = default; HasheableSurfaceParams() = default;
@ -167,12 +172,27 @@ public:
/// Returns the offset in bytes in host memory (linear) of a given mipmap level. /// Returns the offset in bytes in host memory (linear) of a given mipmap level.
std::size_t GetHostMipmapLevelOffset(u32 level) const; std::size_t GetHostMipmapLevelOffset(u32 level) const;
/// Returns the size in bytes in host memory (linear) of a given mipmap level.
std::size_t GetHostMipmapSize(u32 level) const;
/// Returns the size of a layer in bytes in guest memory. /// Returns the size of a layer in bytes in guest memory.
std::size_t GetGuestLayerSize() const; std::size_t GetGuestLayerSize() const;
/// Returns the size of a layer in bytes in host memory for a given mipmap level. /// Returns the size of a layer in bytes in host memory for a given mipmap level.
std::size_t GetHostLayerSize(u32 level) const; std::size_t GetHostLayerSize(u32 level) const;
/// Returns the default block width.
u32 GetDefaultBlockWidth() const;
/// Returns the default block height.
u32 GetDefaultBlockHeight() const;
/// Returns the bits per pixel.
u32 GetBitsPerPixel() const;
/// Returns the bytes per pixel.
u32 GetBytesPerPixel() const;
/// Returns true if another surface can be familiar with this. This is a loosely defined term /// Returns true if another surface can be familiar with this. This is a loosely defined term
/// that reflects the possibility of these two surface parameters potentially being part of a /// that reflects the possibility of these two surface parameters potentially being part of a
/// bigger superset. /// bigger superset.
@ -370,6 +390,7 @@ private:
template <typename TSurface, typename TView, typename TExecutionContext> template <typename TSurface, typename TView, typename TExecutionContext>
class TextureCache { 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<TSurface*>>;
using IntervalType = typename IntervalMap::interval_type; using IntervalType = typename IntervalMap::interval_type;
@ -583,4 +604,79 @@ private:
std::unordered_map<SurfaceParams, std::list<std::unique_ptr<TSurface>>> surface_reserve; std::unordered_map<SurfaceParams, std::list<std::unique_ptr<TSurface>>> surface_reserve;
}; };
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));
}
TSurface* TryFindFramebufferSurface(const u8* host_ptr) const {
return Base::TryFindFramebufferSurface(host_ptr);
}
protected:
explicit TextureCacheContextless(Core::System& system,
VideoCore::RasterizerInterface& rasterizer)
: TextureCache<TSurface, TView, DummyExecutionContext>{system, rasterizer} {}
virtual TView* TryFastGetSurfaceView(VAddr cpu_addr, u8* host_ptr, const SurfaceParams& params,
bool preserve_contents,
const std::vector<TSurface*>& overlaps) = 0;
private:
std::tuple<TView*, DummyExecutionContext> TryFastGetSurfaceView(
DummyExecutionContext, VAddr cpu_addr, u8* host_ptr, const SurfaceParams& params,
bool preserve_contents, const std::vector<TSurface*>& overlaps) {
return {TryFastGetSurfaceView(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 TView>
class SurfaceBaseContextless : public SurfaceBase<TView, DummyExecutionContext> {
public:
DummyExecutionContext FlushBuffer(DummyExecutionContext) {
FlushBufferImpl();
return {};
}
DummyExecutionContext UploadTexture(DummyExecutionContext) {
UploadTextureImpl();
return {};
}
protected:
explicit SurfaceBaseContextless(const SurfaceParams& params)
: SurfaceBase<TView, DummyExecutionContext>{params} {}
virtual void FlushBufferImpl() = 0;
virtual void UploadTextureImpl() = 0;
};
} // namespace VideoCommon } // namespace VideoCommon

View file

@ -359,7 +359,8 @@ std::size_t CalculateSize(bool tiled, u32 bytes_per_pixel, u32 width, u32 height
const u32 aligned_width = Common::AlignUp(width * bytes_per_pixel, gob_size_x); const u32 aligned_width = Common::AlignUp(width * bytes_per_pixel, gob_size_x);
const u32 aligned_height = Common::AlignUp(height, gob_size_y * block_height); const u32 aligned_height = Common::AlignUp(height, gob_size_y * block_height);
const u32 aligned_depth = Common::AlignUp(depth, gob_size_z * block_depth); const u32 aligned_depth = Common::AlignUp(depth, gob_size_z * block_depth);
return aligned_width * aligned_height * aligned_depth; const u32 size = aligned_width * aligned_height * aligned_depth;
return size;
} else { } else {
return width * height * depth * bytes_per_pixel; return width * height * depth * bytes_per_pixel;
} }