summaryrefslogtreecommitdiffstats
path: root/src/video_core/renderer_opengl
diff options
context:
space:
mode:
Diffstat (limited to 'src/video_core/renderer_opengl')
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.cpp66
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.h4
-rw-r--r--src/video_core/renderer_opengl/gl_texture_cache.cpp514
-rw-r--r--src/video_core/renderer_opengl/gl_texture_cache.h131
-rw-r--r--src/video_core/renderer_opengl/renderer_opengl.cpp1
5 files changed, 681 insertions, 35 deletions
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp
index d77426067..cea268f1e 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp
@@ -100,7 +100,7 @@ struct FramebufferCacheKey {
RasterizerOpenGL::RasterizerOpenGL(Core::System& system, Core::Frontend::EmuWindow& emu_window,
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},
buffer_cache(*this, STREAM_BUFFER_SIZE) {
OpenGLState::ApplyDefaultState();
@@ -478,9 +478,9 @@ std::pair<bool, bool> RasterizerOpenGL::ConfigureFramebuffers(
}
current_framebuffer_config_state = fb_config_state;
- Surface depth_surface;
+ CachedSurfaceView* depth_surface{};
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);
@@ -493,42 +493,43 @@ std::pair<bool, bool> RasterizerOpenGL::ConfigureFramebuffers(
if (using_color_fb) {
if (single_color_target) {
// Used when just a single color attachment is enabled, e.g. for clearing a color buffer
- Surface color_surface =
- res_cache.GetColorBufferSurface(*single_color_target, preserve_contents);
+ CachedSurfaceView* color_surface{
+ texture_cache.GetColorBufferSurface(*single_color_target, preserve_contents)};
if (color_surface) {
// 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.
- color_surface->MarkAsModified(true, res_cache);
+ color_surface->MarkAsModified(true);
// Workaround for and issue in nvidia drivers
// 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.color_attachments[0] =
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 {
// Multiple color attachments are enabled
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) {
// 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.
- color_surface->MarkAsModified(true, res_cache);
+ color_surface->MarkAsModified(true);
// Enable sRGB only for supported formats
// Workaround for and issue in nvidia drivers
// 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.color_attachments[index] =
GL_COLOR_ATTACHMENT0 + regs.rt_control.GetMap(index);
- fbkey.colors[index] =
- color_surface != nullptr ? color_surface->Texture().handle : 0;
+ fbkey.colors[index] = color_surface != nullptr ? color_surface->GetTexture() : 0;
}
fbkey.is_single_buffer = false;
fbkey.colors_count = regs.rt_control.count;
@@ -541,11 +542,11 @@ std::pair<bool, bool> RasterizerOpenGL::ConfigureFramebuffers(
if (depth_surface) {
// 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.
- depth_surface->MarkAsModified(true, res_cache);
+ depth_surface->MarkAsModified(true);
- fbkey.zeta = depth_surface->Texture().handle;
- fbkey.stencil_enable = regs.stencil_enable &&
- depth_surface->GetSurfaceParams().type == SurfaceType::DepthStencil;
+ fbkey.zeta = depth_surface->GetTexture();
+ fbkey.stencil_enable = regs.stencil_enable && depth_surface->GetSurfaceParams().GetType() ==
+ SurfaceType::DepthStencil;
}
SetupCachedFramebuffer(fbkey, current_state);
@@ -704,9 +705,7 @@ void RasterizerOpenGL::DrawArrays() {
shader_program_manager->ApplyTo(state);
state.Apply();
- res_cache.SignalPreDrawCall();
params.DispatchDraw();
- res_cache.SignalPostDrawCall();
accelerate_draw = AccelDraw::Disabled;
}
@@ -718,7 +717,7 @@ void RasterizerOpenGL::FlushRegion(CacheAddr addr, u64 size) {
if (!addr || !size) {
return;
}
- res_cache.FlushRegion(addr, size);
+ // texture_cache.FlushRegion(addr, size);
global_cache.FlushRegion(addr, size);
}
@@ -727,7 +726,7 @@ void RasterizerOpenGL::InvalidateRegion(CacheAddr addr, u64 size) {
if (!addr || !size) {
return;
}
- res_cache.InvalidateRegion(addr, size);
+ texture_cache.InvalidateRegion(addr, size);
shader_cache.InvalidateRegion(addr, size);
global_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>& dst_rect) {
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;
}
@@ -755,7 +755,8 @@ bool RasterizerOpenGL::AccelerateDisplay(const Tegra::FramebufferConfig& config,
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) {
return {};
}
@@ -764,14 +765,14 @@ bool RasterizerOpenGL::AccelerateDisplay(const Tegra::FramebufferConfig& config,
const auto& params{surface->GetSurfaceParams()};
const auto& pixel_format{
VideoCore::Surface::PixelFormatFromGPUPixelFormat(config.pixel_format)};
- ASSERT_MSG(params.width == config.width, "Framebuffer width is different");
- ASSERT_MSG(params.height == config.height, "Framebuffer height is different");
+ ASSERT_MSG(params.GetWidth() == config.width, "Framebuffer width 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");
}
- screen_info.display_texture = surface->Texture().handle;
+ screen_info.display_texture = surface->GetTexture();
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);
- if (Surface surface = res_cache.GetTextureSurface(texture, entry); surface) {
- state.texture_units[current_bindpoint].texture =
- surface->Texture(entry.IsArray()).handle;
- surface->UpdateSwizzle(texture.tic.x_source, texture.tic.y_source, texture.tic.z_source,
- texture.tic.w_source);
+ if (const auto surface{texture_cache.GetTextureSurface(texture)}; surface) {
+ state.texture_units[current_bindpoint].texture = surface->GetTexture(
+ entry.GetType(), entry.IsArray(), texture.tic.x_source, texture.tic.y_source,
+ texture.tic.z_source, texture.tic.w_source);
} else {
// Can occur when texture addr is null or its memory is unmapped/invalid
state.texture_units[current_bindpoint].texture = 0;
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h
index f7671ff5d..921e9fc31 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.h
+++ b/src/video_core/renderer_opengl/gl_rasterizer.h
@@ -24,13 +24,13 @@
#include "video_core/renderer_opengl/gl_buffer_cache.h"
#include "video_core/renderer_opengl/gl_device.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_sampler_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_manager.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"
namespace Core {
@@ -181,7 +181,7 @@ private:
const Device device;
OpenGLState state;
- RasterizerCacheOpenGL res_cache;
+ TextureCacheOpenGL texture_cache;
ShaderCacheOpenGL shader_cache;
GlobalRegionCacheOpenGL global_cache;
SamplerCacheOpenGL sampler_cache;
diff --git a/src/video_core/renderer_opengl/gl_texture_cache.cpp b/src/video_core/renderer_opengl/gl_texture_cache.cpp
new file mode 100644
index 000000000..3a456995e
--- /dev/null
+++ b/src/video_core/renderer_opengl/gl_texture_cache.cpp
@@ -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
diff --git a/src/video_core/renderer_opengl/gl_texture_cache.h b/src/video_core/renderer_opengl/gl_texture_cache.h
new file mode 100644
index 000000000..f0a524882
--- /dev/null
+++ b/src/video_core/renderer_opengl/gl_texture_cache.h
@@ -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
diff --git a/src/video_core/renderer_opengl/renderer_opengl.cpp b/src/video_core/renderer_opengl/renderer_opengl.cpp
index aafd6f31b..710bf8303 100644
--- a/src/video_core/renderer_opengl/renderer_opengl.cpp
+++ b/src/video_core/renderer_opengl/renderer_opengl.cpp
@@ -460,6 +460,7 @@ static void APIENTRY DebugHandler(GLenum source, GLenum type, GLuint id, GLenum
switch (severity) {
case GL_DEBUG_SEVERITY_HIGH:
LOG_CRITICAL(Render_OpenGL, format, str_source, str_type, id, message);
+ __debugbreak();
break;
case GL_DEBUG_SEVERITY_MEDIUM:
LOG_WARNING(Render_OpenGL, format, str_source, str_type, id, message);