2019-04-11 22:14:55 +02:00
|
|
|
// Copyright 2019 yuzu Emulator Project
|
|
|
|
// Licensed under GPLv2 or any later version
|
|
|
|
// Refer to the license.txt file included.
|
|
|
|
|
|
|
|
#include "common/assert.h"
|
2019-06-02 01:12:00 +02:00
|
|
|
#include "common/bit_util.h"
|
2019-04-11 22:14:55 +02:00
|
|
|
#include "common/common_types.h"
|
2019-05-07 16:57:16 +02:00
|
|
|
#include "common/microprofile.h"
|
2019-04-11 22:14:55 +02:00
|
|
|
#include "common/scope_exit.h"
|
2019-05-07 16:57:16 +02:00
|
|
|
#include "core/core.h"
|
2019-04-11 22:14:55 +02:00
|
|
|
#include "video_core/morton.h"
|
|
|
|
#include "video_core/renderer_opengl/gl_resource_manager.h"
|
2019-05-08 05:13:05 +02:00
|
|
|
#include "video_core/renderer_opengl/gl_state.h"
|
2019-04-11 22:14:55 +02:00
|
|
|
#include "video_core/renderer_opengl/gl_texture_cache.h"
|
2019-04-17 01:01:07 +02:00
|
|
|
#include "video_core/renderer_opengl/utils.h"
|
2019-06-24 07:13:55 +02:00
|
|
|
#include "video_core/texture_cache/surface_base.h"
|
2019-04-25 18:41:57 +02:00
|
|
|
#include "video_core/texture_cache/texture_cache.h"
|
2019-04-11 22:14:55 +02:00
|
|
|
#include "video_core/textures/convert.h"
|
|
|
|
#include "video_core/textures/texture.h"
|
|
|
|
|
|
|
|
namespace OpenGL {
|
|
|
|
|
|
|
|
using Tegra::Texture::SwizzleSource;
|
|
|
|
using VideoCore::MortonSwizzleMode;
|
|
|
|
|
2019-04-25 18:41:57 +02:00
|
|
|
using VideoCore::Surface::ComponentType;
|
|
|
|
using VideoCore::Surface::PixelFormat;
|
2019-05-13 02:33:52 +02:00
|
|
|
using VideoCore::Surface::SurfaceCompression;
|
2019-04-25 18:41:57 +02:00
|
|
|
using VideoCore::Surface::SurfaceTarget;
|
2019-05-08 05:13:05 +02:00
|
|
|
using VideoCore::Surface::SurfaceType;
|
2019-04-25 18:41:57 +02:00
|
|
|
|
2019-05-07 16:57:16 +02:00
|
|
|
MICROPROFILE_DEFINE(OpenGL_Texture_Upload, "OpenGL", "Texture Upload", MP_RGB(128, 192, 128));
|
|
|
|
MICROPROFILE_DEFINE(OpenGL_Texture_Download, "OpenGL", "Texture Download", MP_RGB(128, 192, 128));
|
2019-07-10 03:27:27 +02:00
|
|
|
MICROPROFILE_DEFINE(OpenGL_Texture_Buffer_Copy, "OpenGL", "Texture Buffer Copy",
|
|
|
|
MP_RGB(128, 192, 128));
|
2019-05-07 16:57:16 +02:00
|
|
|
|
2019-04-11 22:14:55 +02:00
|
|
|
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
|
2019-09-22 02:21:56 +02:00
|
|
|
{GL_RGB16F, GL_RGBA16, GL_HALF_FLOAT, ComponentType::Float, false}, // RGBX16F
|
2019-04-11 22:14:55 +02:00
|
|
|
{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
|
2019-10-03 01:00:16 +02:00
|
|
|
{GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // ASTC_2D_6X6
|
|
|
|
{GL_SRGB8_ALPHA8, GL_RGBA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // ASTC_2D_6X6_SRGB
|
|
|
|
{GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // ASTC_2D_10X10
|
|
|
|
{GL_SRGB8_ALPHA8, GL_RGBA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // ASTC_2D_10X10_SRGB
|
|
|
|
{GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // ASTC_2D_12X12
|
|
|
|
{GL_SRGB8_ALPHA8, GL_RGBA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // ASTC_2D_12X12_SRGB
|
|
|
|
{GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // ASTC_2D_8X6
|
|
|
|
{GL_SRGB8_ALPHA8, GL_RGBA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // ASTC_2D_8X6_SRGB
|
|
|
|
{GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // ASTC_2D_6X5
|
|
|
|
{GL_SRGB8_ALPHA8, GL_RGBA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // ASTC_2D_6X5_SRGB
|
2019-04-11 22:14:55 +02:00
|
|
|
|
|
|
|
// 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)]};
|
|
|
|
return format;
|
|
|
|
}
|
|
|
|
|
2019-05-07 16:57:16 +02:00
|
|
|
GLenum GetTextureTarget(const SurfaceTarget& target) {
|
|
|
|
switch (target) {
|
2019-07-05 01:38:19 +02:00
|
|
|
case SurfaceTarget::TextureBuffer:
|
|
|
|
return GL_TEXTURE_BUFFER;
|
2019-04-11 22:14:55 +02:00
|
|
|
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) {
|
2019-07-18 06:06:26 +02:00
|
|
|
if (params.IsBuffer()) {
|
|
|
|
return;
|
|
|
|
}
|
2019-04-11 22:14:55 +02:00
|
|
|
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);
|
2019-05-07 16:57:16 +02:00
|
|
|
glTextureParameteri(texture, GL_TEXTURE_MAX_LEVEL, params.num_levels - 1);
|
|
|
|
if (params.num_levels == 1) {
|
2019-04-11 22:14:55 +02:00
|
|
|
glTextureParameterf(texture, GL_TEXTURE_LOD_BIAS, 1000.0f);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-07-05 01:38:19 +02:00
|
|
|
OGLTexture CreateTexture(const SurfaceParams& params, GLenum target, GLenum internal_format,
|
|
|
|
OGLBuffer& texture_buffer) {
|
2019-04-11 22:14:55 +02:00
|
|
|
OGLTexture texture;
|
2019-04-14 06:44:16 +02:00
|
|
|
texture.Create(target);
|
2019-04-11 22:14:55 +02:00
|
|
|
|
2019-05-07 16:57:16 +02:00
|
|
|
switch (params.target) {
|
2019-04-11 22:14:55 +02:00
|
|
|
case SurfaceTarget::Texture1D:
|
2019-05-24 21:34:31 +02:00
|
|
|
glTextureStorage1D(texture.handle, params.emulated_levels, internal_format, params.width);
|
2019-04-11 22:14:55 +02:00
|
|
|
break;
|
2019-07-05 01:38:19 +02:00
|
|
|
case SurfaceTarget::TextureBuffer:
|
|
|
|
texture_buffer.Create();
|
|
|
|
glNamedBufferStorage(texture_buffer.handle, params.width * params.GetBytesPerPixel(),
|
|
|
|
nullptr, GL_DYNAMIC_STORAGE_BIT);
|
|
|
|
glTextureBuffer(texture.handle, internal_format, texture_buffer.handle);
|
2019-07-18 06:04:18 +02:00
|
|
|
break;
|
2019-04-11 22:14:55 +02:00
|
|
|
case SurfaceTarget::Texture2D:
|
|
|
|
case SurfaceTarget::TextureCubemap:
|
2019-05-24 21:34:31 +02:00
|
|
|
glTextureStorage2D(texture.handle, params.emulated_levels, internal_format, params.width,
|
2019-05-07 16:57:16 +02:00
|
|
|
params.height);
|
2019-04-11 22:14:55 +02:00
|
|
|
break;
|
|
|
|
case SurfaceTarget::Texture3D:
|
|
|
|
case SurfaceTarget::Texture2DArray:
|
|
|
|
case SurfaceTarget::TextureCubeArray:
|
2019-05-24 21:34:31 +02:00
|
|
|
glTextureStorage3D(texture.handle, params.emulated_levels, internal_format, params.width,
|
2019-05-07 16:57:16 +02:00
|
|
|
params.height, params.depth);
|
2019-04-11 22:14:55 +02:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
UNREACHABLE();
|
|
|
|
}
|
|
|
|
|
|
|
|
ApplyTextureDefaults(params, texture.handle);
|
|
|
|
|
|
|
|
return texture;
|
|
|
|
}
|
|
|
|
|
|
|
|
} // Anonymous namespace
|
|
|
|
|
2019-05-07 16:57:16 +02:00
|
|
|
CachedSurface::CachedSurface(const GPUVAddr gpu_addr, const SurfaceParams& params)
|
|
|
|
: VideoCommon::SurfaceBase<View>(gpu_addr, params) {
|
|
|
|
const auto& tuple{GetFormatTuple(params.pixel_format, params.component_type)};
|
2019-04-11 22:14:55 +02:00
|
|
|
internal_format = tuple.internal_format;
|
|
|
|
format = tuple.format;
|
|
|
|
type = tuple.type;
|
|
|
|
is_compressed = tuple.compressed;
|
2019-05-07 16:57:16 +02:00
|
|
|
target = GetTextureTarget(params.target);
|
2019-07-05 01:38:19 +02:00
|
|
|
texture = CreateTexture(params, target, internal_format, texture_buffer);
|
2019-05-07 16:57:16 +02:00
|
|
|
DecorateSurfaceName();
|
2019-05-11 06:17:47 +02:00
|
|
|
main_view = CreateViewInner(
|
|
|
|
ViewParams(params.target, 0, params.is_layered ? params.depth : 1, 0, params.num_levels),
|
|
|
|
true);
|
2019-05-07 16:57:16 +02:00
|
|
|
}
|
|
|
|
|
2019-06-29 22:29:39 +02:00
|
|
|
CachedSurface::~CachedSurface() = default;
|
2019-04-11 22:14:55 +02:00
|
|
|
|
2019-05-07 16:57:16 +02:00
|
|
|
void CachedSurface::DownloadTexture(std::vector<u8>& staging_buffer) {
|
|
|
|
MICROPROFILE_SCOPE(OpenGL_Texture_Download);
|
2019-04-11 22:14:55 +02:00
|
|
|
|
|
|
|
SCOPE_EXIT({ glPixelStorei(GL_PACK_ROW_LENGTH, 0); });
|
|
|
|
|
2019-05-24 21:34:31 +02:00
|
|
|
for (u32 level = 0; level < params.emulated_levels; ++level) {
|
2019-05-13 02:33:52 +02:00
|
|
|
glPixelStorei(GL_PACK_ALIGNMENT, std::min(8U, params.GetRowAlignment(level)));
|
2019-04-11 22:14:55 +02:00
|
|
|
glPixelStorei(GL_PACK_ROW_LENGTH, static_cast<GLint>(params.GetMipWidth(level)));
|
2019-05-07 16:57:16 +02:00
|
|
|
const std::size_t mip_offset = params.GetHostMipmapLevelOffset(level);
|
2019-04-11 22:14:55 +02:00
|
|
|
if (is_compressed) {
|
2019-04-24 07:45:03 +02:00
|
|
|
glGetCompressedTextureImage(texture.handle, level,
|
|
|
|
static_cast<GLsizei>(params.GetHostMipmapSize(level)),
|
2019-05-07 16:57:16 +02:00
|
|
|
staging_buffer.data() + mip_offset);
|
2019-04-11 22:14:55 +02:00
|
|
|
} else {
|
|
|
|
glGetTextureImage(texture.handle, level, format, type,
|
|
|
|
static_cast<GLsizei>(params.GetHostMipmapSize(level)),
|
2019-05-07 16:57:16 +02:00
|
|
|
staging_buffer.data() + mip_offset);
|
2019-04-11 22:14:55 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-07-05 03:10:59 +02:00
|
|
|
void CachedSurface::UploadTexture(const std::vector<u8>& staging_buffer) {
|
2019-05-07 16:57:16 +02:00
|
|
|
MICROPROFILE_SCOPE(OpenGL_Texture_Upload);
|
2019-04-24 07:45:03 +02:00
|
|
|
SCOPE_EXIT({ glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); });
|
2019-05-24 21:34:31 +02:00
|
|
|
for (u32 level = 0; level < params.emulated_levels; ++level) {
|
2019-05-07 16:57:16 +02:00
|
|
|
UploadTextureMipmap(level, staging_buffer);
|
2019-04-11 22:14:55 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-07-05 03:10:59 +02:00
|
|
|
void CachedSurface::UploadTextureMipmap(u32 level, const std::vector<u8>& staging_buffer) {
|
2019-05-13 02:33:52 +02:00
|
|
|
glPixelStorei(GL_UNPACK_ALIGNMENT, std::min(8U, params.GetRowAlignment(level)));
|
2019-04-11 22:14:55 +02:00
|
|
|
glPixelStorei(GL_UNPACK_ROW_LENGTH, static_cast<GLint>(params.GetMipWidth(level)));
|
|
|
|
|
2019-05-13 02:33:52 +02:00
|
|
|
auto compression_type = params.GetCompressionType();
|
|
|
|
|
|
|
|
const std::size_t mip_offset = compression_type == SurfaceCompression::Converted
|
|
|
|
? params.GetConvertedMipmapOffset(level)
|
|
|
|
: params.GetHostMipmapLevelOffset(level);
|
2019-07-05 03:10:59 +02:00
|
|
|
const u8* buffer{staging_buffer.data() + mip_offset};
|
2019-04-11 22:14:55 +02:00
|
|
|
if (is_compressed) {
|
|
|
|
const auto image_size{static_cast<GLsizei>(params.GetHostMipmapSize(level))};
|
2019-05-07 16:57:16 +02:00
|
|
|
switch (params.target) {
|
2019-04-11 22:14:55 +02:00
|
|
|
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)};
|
2019-05-07 16:57:16 +02:00
|
|
|
for (std::size_t face = 0; face < params.depth; ++face) {
|
2019-04-11 22:14:55 +02:00
|
|
|
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 {
|
2019-05-07 16:57:16 +02:00
|
|
|
switch (params.target) {
|
2019-04-11 22:14:55 +02:00
|
|
|
case SurfaceTarget::Texture1D:
|
|
|
|
glTextureSubImage1D(texture.handle, level, 0, params.GetMipWidth(level), format, type,
|
|
|
|
buffer);
|
|
|
|
break;
|
2019-07-05 01:38:19 +02:00
|
|
|
case SurfaceTarget::TextureBuffer:
|
|
|
|
ASSERT(level == 0);
|
|
|
|
glNamedBufferSubData(texture_buffer.handle, 0,
|
|
|
|
params.GetMipWidth(level) * params.GetBytesPerPixel(), buffer);
|
|
|
|
break;
|
2019-04-11 22:14:55 +02:00
|
|
|
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:
|
2019-05-07 16:57:16 +02:00
|
|
|
for (std::size_t face = 0; face < params.depth; ++face) {
|
2019-04-11 22:14:55 +02:00
|
|
|
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();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-04-17 01:01:07 +02:00
|
|
|
void CachedSurface::DecorateSurfaceName() {
|
2019-05-07 16:57:16 +02:00
|
|
|
LabelGLObject(GL_TEXTURE, texture.handle, GetGpuAddr(), params.TargetName());
|
|
|
|
}
|
|
|
|
|
|
|
|
void CachedSurfaceView::DecorateViewName(GPUVAddr gpu_addr, std::string prefix) {
|
2019-05-08 01:09:34 +02:00
|
|
|
LabelGLObject(GL_TEXTURE, texture_view.handle, gpu_addr, prefix);
|
2019-04-17 01:01:07 +02:00
|
|
|
}
|
|
|
|
|
2019-05-07 16:57:16 +02:00
|
|
|
View CachedSurface::CreateView(const ViewParams& view_key) {
|
2019-05-11 06:17:47 +02:00
|
|
|
return CreateViewInner(view_key, false);
|
|
|
|
}
|
|
|
|
|
|
|
|
View CachedSurface::CreateViewInner(const ViewParams& view_key, const bool is_proxy) {
|
|
|
|
auto view = std::make_shared<CachedSurfaceView>(*this, view_key, is_proxy);
|
2019-05-07 16:57:16 +02:00
|
|
|
views[view_key] = view;
|
2019-05-11 06:17:47 +02:00
|
|
|
if (!is_proxy)
|
|
|
|
view->DecorateViewName(gpu_addr, params.TargetName() + "V:" + std::to_string(view_count++));
|
2019-05-07 16:57:16 +02:00
|
|
|
return view;
|
2019-04-11 22:14:55 +02:00
|
|
|
}
|
|
|
|
|
2019-05-11 06:17:47 +02:00
|
|
|
CachedSurfaceView::CachedSurfaceView(CachedSurface& surface, const ViewParams& params,
|
|
|
|
const bool is_proxy)
|
|
|
|
: VideoCommon::ViewBase(params), surface{surface}, is_proxy{is_proxy} {
|
2019-05-07 16:57:16 +02:00
|
|
|
target = GetTextureTarget(params.target);
|
2019-05-11 06:17:47 +02:00
|
|
|
if (!is_proxy) {
|
|
|
|
texture_view = CreateTextureView();
|
|
|
|
}
|
2019-05-08 01:09:34 +02:00
|
|
|
swizzle = EncodeSwizzle(SwizzleSource::R, SwizzleSource::G, SwizzleSource::B, SwizzleSource::A);
|
2019-05-07 16:57:16 +02:00
|
|
|
}
|
2019-04-11 22:14:55 +02:00
|
|
|
|
|
|
|
CachedSurfaceView::~CachedSurfaceView() = default;
|
|
|
|
|
2019-05-18 10:57:49 +02:00
|
|
|
void CachedSurfaceView::Attach(GLenum attachment, GLenum target) const {
|
2019-05-07 16:57:16 +02:00
|
|
|
ASSERT(params.num_layers == 1 && params.num_levels == 1);
|
2019-04-14 23:16:27 +02:00
|
|
|
|
2019-05-08 01:09:34 +02:00
|
|
|
const auto& owner_params = surface.GetSurfaceParams();
|
|
|
|
|
|
|
|
switch (owner_params.target) {
|
2019-04-14 23:16:27 +02:00
|
|
|
case SurfaceTarget::Texture1D:
|
2019-05-18 10:57:49 +02:00
|
|
|
glFramebufferTexture1D(target, attachment, surface.GetTarget(), surface.GetTexture(),
|
|
|
|
params.base_level);
|
2019-04-14 23:16:27 +02:00
|
|
|
break;
|
|
|
|
case SurfaceTarget::Texture2D:
|
2019-05-18 10:57:49 +02:00
|
|
|
glFramebufferTexture2D(target, attachment, surface.GetTarget(), surface.GetTexture(),
|
|
|
|
params.base_level);
|
2019-04-14 23:16:27 +02:00
|
|
|
break;
|
|
|
|
case SurfaceTarget::Texture1DArray:
|
|
|
|
case SurfaceTarget::Texture2DArray:
|
|
|
|
case SurfaceTarget::TextureCubemap:
|
|
|
|
case SurfaceTarget::TextureCubeArray:
|
2019-05-18 10:57:49 +02:00
|
|
|
glFramebufferTextureLayer(target, attachment, surface.GetTexture(), params.base_level,
|
|
|
|
params.base_layer);
|
2019-04-14 23:16:27 +02:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
UNIMPLEMENTED();
|
2019-04-11 22:14:55 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-05-07 16:57:16 +02:00
|
|
|
void CachedSurfaceView::ApplySwizzle(SwizzleSource x_source, SwizzleSource y_source,
|
2019-04-11 22:14:55 +02:00
|
|
|
SwizzleSource z_source, SwizzleSource w_source) {
|
2019-05-08 01:09:34 +02:00
|
|
|
u32 new_swizzle = EncodeSwizzle(x_source, y_source, z_source, w_source);
|
|
|
|
if (new_swizzle == swizzle)
|
2019-04-11 22:14:55 +02:00
|
|
|
return;
|
2019-05-08 01:09:34 +02:00
|
|
|
swizzle = new_swizzle;
|
2019-04-11 22:14:55 +02:00
|
|
|
const std::array<GLint, 4> gl_swizzle = {GetSwizzleSource(x_source), GetSwizzleSource(y_source),
|
|
|
|
GetSwizzleSource(z_source),
|
|
|
|
GetSwizzleSource(w_source)};
|
2019-05-11 06:17:47 +02:00
|
|
|
const GLuint handle = GetTexture();
|
|
|
|
glTextureParameteriv(handle, GL_TEXTURE_SWIZZLE_RGBA, gl_swizzle.data());
|
2019-04-11 22:14:55 +02:00
|
|
|
}
|
|
|
|
|
2019-05-08 01:09:34 +02:00
|
|
|
OGLTextureView CachedSurfaceView::CreateTextureView() const {
|
2019-05-07 16:57:16 +02:00
|
|
|
const auto& owner_params = surface.GetSurfaceParams();
|
2019-06-25 23:40:08 +02:00
|
|
|
OGLTextureView texture_view;
|
|
|
|
texture_view.Create();
|
2019-04-11 22:14:55 +02:00
|
|
|
|
2019-06-25 23:40:08 +02:00
|
|
|
const GLuint handle{texture_view.handle};
|
2019-05-07 16:57:16 +02:00
|
|
|
const FormatTuple& tuple{
|
|
|
|
GetFormatTuple(owner_params.pixel_format, owner_params.component_type)};
|
2019-04-11 22:14:55 +02:00
|
|
|
|
2019-05-07 16:57:16 +02:00
|
|
|
glTextureView(handle, target, surface.texture.handle, tuple.internal_format, params.base_level,
|
|
|
|
params.num_levels, params.base_layer, params.num_layers);
|
2019-04-11 22:14:55 +02:00
|
|
|
|
2019-05-07 16:57:16 +02:00
|
|
|
ApplyTextureDefaults(owner_params, handle);
|
2019-04-11 22:14:55 +02:00
|
|
|
|
2019-06-25 23:40:08 +02:00
|
|
|
return texture_view;
|
2019-04-11 22:14:55 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
TextureCacheOpenGL::TextureCacheOpenGL(Core::System& system,
|
2019-06-02 01:12:00 +02:00
|
|
|
VideoCore::RasterizerInterface& rasterizer,
|
|
|
|
const Device& device)
|
2019-05-08 05:13:05 +02:00
|
|
|
: TextureCacheBase{system, rasterizer} {
|
|
|
|
src_framebuffer.Create();
|
|
|
|
dst_framebuffer.Create();
|
|
|
|
}
|
2019-04-11 22:14:55 +02:00
|
|
|
|
|
|
|
TextureCacheOpenGL::~TextureCacheOpenGL() = default;
|
|
|
|
|
2019-05-07 16:57:16 +02:00
|
|
|
Surface TextureCacheOpenGL::CreateSurface(GPUVAddr gpu_addr, const SurfaceParams& params) {
|
|
|
|
return std::make_shared<CachedSurface>(gpu_addr, params);
|
2019-04-15 21:17:27 +02:00
|
|
|
}
|
|
|
|
|
2019-06-02 04:15:55 +02:00
|
|
|
void TextureCacheOpenGL::ImageCopy(Surface& src_surface, Surface& dst_surface,
|
2019-05-07 16:57:16 +02:00
|
|
|
const VideoCommon::CopyParams& copy_params) {
|
2019-06-11 13:20:27 +02:00
|
|
|
const auto& src_params = src_surface->GetSurfaceParams();
|
|
|
|
const auto& dst_params = dst_surface->GetSurfaceParams();
|
|
|
|
if (src_params.type != dst_params.type) {
|
|
|
|
// A fallback is needed
|
|
|
|
return;
|
2019-06-02 01:12:00 +02:00
|
|
|
}
|
2019-05-07 16:57:16 +02:00
|
|
|
const auto src_handle = src_surface->GetTexture();
|
|
|
|
const auto src_target = src_surface->GetTarget();
|
|
|
|
const auto dst_handle = dst_surface->GetTexture();
|
|
|
|
const auto dst_target = dst_surface->GetTarget();
|
|
|
|
glCopyImageSubData(src_handle, src_target, copy_params.source_level, copy_params.source_x,
|
|
|
|
copy_params.source_y, copy_params.source_z, dst_handle, dst_target,
|
|
|
|
copy_params.dest_level, copy_params.dest_x, copy_params.dest_y,
|
|
|
|
copy_params.dest_z, copy_params.width, copy_params.height,
|
|
|
|
copy_params.depth);
|
2019-04-11 22:14:55 +02:00
|
|
|
}
|
|
|
|
|
2019-06-02 04:15:55 +02:00
|
|
|
void TextureCacheOpenGL::ImageBlit(View& src_view, View& dst_view,
|
2019-05-18 10:57:49 +02:00
|
|
|
const Tegra::Engines::Fermi2D::Config& copy_config) {
|
|
|
|
const auto& src_params{src_view->GetSurfaceParams()};
|
|
|
|
const auto& dst_params{dst_view->GetSurfaceParams()};
|
2019-05-08 05:13:05 +02:00
|
|
|
|
|
|
|
OpenGLState prev_state{OpenGLState::GetCurState()};
|
2019-07-13 22:52:32 +02:00
|
|
|
SCOPE_EXIT({
|
|
|
|
prev_state.AllDirty();
|
|
|
|
prev_state.Apply();
|
|
|
|
});
|
2019-05-08 05:13:05 +02:00
|
|
|
|
|
|
|
OpenGLState state;
|
|
|
|
state.draw.read_framebuffer = src_framebuffer.handle;
|
|
|
|
state.draw.draw_framebuffer = dst_framebuffer.handle;
|
2019-07-13 22:52:32 +02:00
|
|
|
state.AllDirty();
|
2019-06-14 05:03:20 +02:00
|
|
|
state.Apply();
|
2019-05-08 05:13:05 +02:00
|
|
|
|
|
|
|
u32 buffers{};
|
|
|
|
|
2019-05-18 10:57:49 +02:00
|
|
|
UNIMPLEMENTED_IF(src_params.target == SurfaceTarget::Texture3D);
|
|
|
|
UNIMPLEMENTED_IF(dst_params.target == SurfaceTarget::Texture3D);
|
2019-05-08 05:13:05 +02:00
|
|
|
|
|
|
|
if (src_params.type == SurfaceType::ColorTexture) {
|
2019-05-18 10:57:49 +02:00
|
|
|
src_view->Attach(GL_COLOR_ATTACHMENT0, GL_READ_FRAMEBUFFER);
|
2019-05-08 05:13:05 +02:00
|
|
|
glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0,
|
|
|
|
0);
|
|
|
|
|
2019-05-18 10:57:49 +02:00
|
|
|
dst_view->Attach(GL_COLOR_ATTACHMENT0, GL_DRAW_FRAMEBUFFER);
|
2019-05-08 05:13:05 +02:00
|
|
|
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0,
|
|
|
|
0);
|
|
|
|
|
|
|
|
buffers = GL_COLOR_BUFFER_BIT;
|
|
|
|
} else if (src_params.type == SurfaceType::Depth) {
|
|
|
|
glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0);
|
2019-05-18 10:57:49 +02:00
|
|
|
src_view->Attach(GL_DEPTH_ATTACHMENT, GL_READ_FRAMEBUFFER);
|
2019-05-08 05:13:05 +02:00
|
|
|
glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0, 0);
|
|
|
|
|
|
|
|
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0);
|
2019-05-18 10:57:49 +02:00
|
|
|
dst_view->Attach(GL_DEPTH_ATTACHMENT, GL_DRAW_FRAMEBUFFER);
|
2019-05-08 05:13:05 +02:00
|
|
|
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0, 0);
|
|
|
|
|
|
|
|
buffers = GL_DEPTH_BUFFER_BIT;
|
|
|
|
} else if (src_params.type == SurfaceType::DepthStencil) {
|
|
|
|
glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0);
|
2019-05-18 10:57:49 +02:00
|
|
|
src_view->Attach(GL_DEPTH_STENCIL_ATTACHMENT, GL_READ_FRAMEBUFFER);
|
2019-05-08 05:13:05 +02:00
|
|
|
|
|
|
|
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0);
|
2019-05-18 10:57:49 +02:00
|
|
|
dst_view->Attach(GL_DEPTH_STENCIL_ATTACHMENT, GL_DRAW_FRAMEBUFFER);
|
2019-05-08 05:13:05 +02:00
|
|
|
|
|
|
|
buffers = GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT;
|
|
|
|
}
|
|
|
|
|
2019-05-18 10:57:49 +02:00
|
|
|
const Common::Rectangle<u32>& src_rect = copy_config.src_rect;
|
|
|
|
const Common::Rectangle<u32>& dst_rect = copy_config.dst_rect;
|
|
|
|
const bool is_linear = copy_config.filter == Tegra::Engines::Fermi2D::Filter::Linear;
|
|
|
|
|
2019-05-08 05:13:05 +02:00
|
|
|
glBlitFramebuffer(src_rect.left, src_rect.top, src_rect.right, src_rect.bottom, dst_rect.left,
|
|
|
|
dst_rect.top, dst_rect.right, dst_rect.bottom, buffers,
|
2019-06-13 16:39:45 +02:00
|
|
|
is_linear && (buffers == GL_COLOR_BUFFER_BIT) ? GL_LINEAR : GL_NEAREST);
|
2019-05-08 05:13:05 +02:00
|
|
|
}
|
|
|
|
|
2019-06-02 04:15:55 +02:00
|
|
|
void TextureCacheOpenGL::BufferCopy(Surface& src_surface, Surface& dst_surface) {
|
2019-07-10 01:49:53 +02:00
|
|
|
MICROPROFILE_SCOPE(OpenGL_Texture_Buffer_Copy);
|
2019-06-02 01:12:00 +02:00
|
|
|
const auto& src_params = src_surface->GetSurfaceParams();
|
|
|
|
const auto& dst_params = dst_surface->GetSurfaceParams();
|
2019-06-25 23:40:08 +02:00
|
|
|
UNIMPLEMENTED_IF(src_params.num_levels > 1 || dst_params.num_levels > 1);
|
2019-06-02 01:12:00 +02:00
|
|
|
|
|
|
|
const auto source_format = GetFormatTuple(src_params.pixel_format, src_params.component_type);
|
|
|
|
const auto dest_format = GetFormatTuple(dst_params.pixel_format, dst_params.component_type);
|
|
|
|
|
|
|
|
const std::size_t source_size = src_surface->GetHostSizeInBytes();
|
|
|
|
const std::size_t dest_size = dst_surface->GetHostSizeInBytes();
|
|
|
|
|
|
|
|
const std::size_t buffer_size = std::max(source_size, dest_size);
|
|
|
|
|
|
|
|
GLuint copy_pbo_handle = FetchPBO(buffer_size);
|
|
|
|
|
|
|
|
glBindBuffer(GL_PIXEL_PACK_BUFFER, copy_pbo_handle);
|
|
|
|
|
|
|
|
if (source_format.compressed) {
|
|
|
|
glGetCompressedTextureImage(src_surface->GetTexture(), 0, static_cast<GLsizei>(source_size),
|
|
|
|
nullptr);
|
|
|
|
} else {
|
|
|
|
glGetTextureImage(src_surface->GetTexture(), 0, source_format.format, source_format.type,
|
|
|
|
static_cast<GLsizei>(source_size), nullptr);
|
|
|
|
}
|
|
|
|
glBindBuffer(GL_PIXEL_PACK_BUFFER, 0);
|
|
|
|
|
|
|
|
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, copy_pbo_handle);
|
|
|
|
|
|
|
|
const GLsizei width = static_cast<GLsizei>(dst_params.width);
|
|
|
|
const GLsizei height = static_cast<GLsizei>(dst_params.height);
|
|
|
|
const GLsizei depth = static_cast<GLsizei>(dst_params.depth);
|
|
|
|
if (dest_format.compressed) {
|
|
|
|
LOG_CRITICAL(HW_GPU, "Compressed buffer copy is unimplemented!");
|
|
|
|
UNREACHABLE();
|
|
|
|
} else {
|
|
|
|
switch (dst_params.target) {
|
|
|
|
case SurfaceTarget::Texture1D:
|
|
|
|
glTextureSubImage1D(dst_surface->GetTexture(), 0, 0, width, dest_format.format,
|
|
|
|
dest_format.type, nullptr);
|
|
|
|
break;
|
|
|
|
case SurfaceTarget::Texture2D:
|
|
|
|
glTextureSubImage2D(dst_surface->GetTexture(), 0, 0, 0, width, height,
|
|
|
|
dest_format.format, dest_format.type, nullptr);
|
|
|
|
break;
|
|
|
|
case SurfaceTarget::Texture3D:
|
|
|
|
case SurfaceTarget::Texture2DArray:
|
|
|
|
case SurfaceTarget::TextureCubeArray:
|
|
|
|
glTextureSubImage3D(dst_surface->GetTexture(), 0, 0, 0, 0, width, height, depth,
|
|
|
|
dest_format.format, dest_format.type, nullptr);
|
|
|
|
break;
|
|
|
|
case SurfaceTarget::TextureCubemap:
|
|
|
|
glTextureSubImage3D(dst_surface->GetTexture(), 0, 0, 0, 0, width, height, depth,
|
|
|
|
dest_format.format, dest_format.type, nullptr);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
LOG_CRITICAL(Render_OpenGL, "Unimplemented surface target={}",
|
|
|
|
static_cast<u32>(dst_params.target));
|
|
|
|
UNREACHABLE();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
|
|
|
|
|
|
|
|
glTextureBarrier();
|
|
|
|
}
|
|
|
|
|
|
|
|
GLuint TextureCacheOpenGL::FetchPBO(std::size_t buffer_size) {
|
2019-06-26 01:26:59 +02:00
|
|
|
ASSERT_OR_EXECUTE(buffer_size > 0, { return 0; });
|
2019-06-02 01:12:00 +02:00
|
|
|
const u32 l2 = Common::Log2Ceil64(static_cast<u64>(buffer_size));
|
|
|
|
OGLBuffer& cp = copy_pbo_cache[l2];
|
|
|
|
if (cp.handle == 0) {
|
|
|
|
const std::size_t ceil_size = 1ULL << l2;
|
|
|
|
cp.Create();
|
2019-06-14 18:51:13 +02:00
|
|
|
cp.MakeStreamCopy(ceil_size);
|
2019-06-02 01:12:00 +02:00
|
|
|
}
|
|
|
|
return cp.handle;
|
|
|
|
}
|
|
|
|
|
2019-04-11 22:14:55 +02:00
|
|
|
} // namespace OpenGL
|