mirror of
https://github.com/yuzu-mirror/yuzu.git
synced 2024-09-09 16:19:09 +01:00
Merge pull request #1256 from bunnei/tex-target-support
Initial support for non-2D textures
This commit is contained in:
commit
af074ee422
11 changed files with 422 additions and 229 deletions
|
@ -293,10 +293,6 @@ Texture::TICEntry Maxwell3D::GetTICEntry(u32 tic_index) const {
|
||||||
tic_entry.header_version == Texture::TICHeaderVersion::Pitch,
|
tic_entry.header_version == Texture::TICHeaderVersion::Pitch,
|
||||||
"TIC versions other than BlockLinear or Pitch are unimplemented");
|
"TIC versions other than BlockLinear or Pitch are unimplemented");
|
||||||
|
|
||||||
ASSERT_MSG((tic_entry.texture_type == Texture::TextureType::Texture2D) ||
|
|
||||||
(tic_entry.texture_type == Texture::TextureType::Texture2DNoMipmap),
|
|
||||||
"Texture types other than Texture2D are unimplemented");
|
|
||||||
|
|
||||||
auto r_type = tic_entry.r_type.Value();
|
auto r_type = tic_entry.r_type.Value();
|
||||||
auto g_type = tic_entry.g_type.Value();
|
auto g_type = tic_entry.g_type.Value();
|
||||||
auto b_type = tic_entry.b_type.Value();
|
auto b_type = tic_entry.b_type.Value();
|
||||||
|
|
|
@ -586,7 +586,7 @@ bool RasterizerOpenGL::AccelerateDisplay(const Tegra::FramebufferConfig& config,
|
||||||
void RasterizerOpenGL::SamplerInfo::Create() {
|
void RasterizerOpenGL::SamplerInfo::Create() {
|
||||||
sampler.Create();
|
sampler.Create();
|
||||||
mag_filter = min_filter = Tegra::Texture::TextureFilter::Linear;
|
mag_filter = min_filter = Tegra::Texture::TextureFilter::Linear;
|
||||||
wrap_u = wrap_v = Tegra::Texture::WrapMode::Wrap;
|
wrap_u = wrap_v = wrap_p = Tegra::Texture::WrapMode::Wrap;
|
||||||
|
|
||||||
// default is GL_LINEAR_MIPMAP_LINEAR
|
// default is GL_LINEAR_MIPMAP_LINEAR
|
||||||
glSamplerParameteri(sampler.handle, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
glSamplerParameteri(sampler.handle, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||||
|
@ -613,8 +613,13 @@ void RasterizerOpenGL::SamplerInfo::SyncWithConfig(const Tegra::Texture::TSCEntr
|
||||||
wrap_v = config.wrap_v;
|
wrap_v = config.wrap_v;
|
||||||
glSamplerParameteri(s, GL_TEXTURE_WRAP_T, MaxwellToGL::WrapMode(wrap_v));
|
glSamplerParameteri(s, GL_TEXTURE_WRAP_T, MaxwellToGL::WrapMode(wrap_v));
|
||||||
}
|
}
|
||||||
|
if (wrap_p != config.wrap_p) {
|
||||||
|
wrap_p = config.wrap_p;
|
||||||
|
glSamplerParameteri(s, GL_TEXTURE_WRAP_R, MaxwellToGL::WrapMode(wrap_p));
|
||||||
|
}
|
||||||
|
|
||||||
if (wrap_u == Tegra::Texture::WrapMode::Border || wrap_v == Tegra::Texture::WrapMode::Border) {
|
if (wrap_u == Tegra::Texture::WrapMode::Border || wrap_v == Tegra::Texture::WrapMode::Border ||
|
||||||
|
wrap_p == Tegra::Texture::WrapMode::Border) {
|
||||||
const GLvec4 new_border_color = {{config.border_color_r, config.border_color_g,
|
const GLvec4 new_border_color = {{config.border_color_r, config.border_color_g,
|
||||||
config.border_color_b, config.border_color_a}};
|
config.border_color_b, config.border_color_a}};
|
||||||
if (border_color != new_border_color) {
|
if (border_color != new_border_color) {
|
||||||
|
@ -698,14 +703,15 @@ u32 RasterizerOpenGL::SetupTextures(Maxwell::ShaderStage stage, Shader& shader,
|
||||||
const auto texture = maxwell3d.GetStageTexture(entry.GetStage(), entry.GetOffset());
|
const auto texture = maxwell3d.GetStageTexture(entry.GetStage(), entry.GetOffset());
|
||||||
|
|
||||||
if (!texture.enabled) {
|
if (!texture.enabled) {
|
||||||
state.texture_units[current_bindpoint].texture_2d = 0;
|
state.texture_units[current_bindpoint].texture = 0;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
texture_samplers[current_bindpoint].SyncWithConfig(texture.tsc);
|
texture_samplers[current_bindpoint].SyncWithConfig(texture.tsc);
|
||||||
Surface surface = res_cache.GetTextureSurface(texture);
|
Surface surface = res_cache.GetTextureSurface(texture);
|
||||||
if (surface != nullptr) {
|
if (surface != nullptr) {
|
||||||
state.texture_units[current_bindpoint].texture_2d = surface->Texture().handle;
|
state.texture_units[current_bindpoint].texture = surface->Texture().handle;
|
||||||
|
state.texture_units[current_bindpoint].target = surface->Target();
|
||||||
state.texture_units[current_bindpoint].swizzle.r =
|
state.texture_units[current_bindpoint].swizzle.r =
|
||||||
MaxwellToGL::SwizzleSource(texture.tic.x_source);
|
MaxwellToGL::SwizzleSource(texture.tic.x_source);
|
||||||
state.texture_units[current_bindpoint].swizzle.g =
|
state.texture_units[current_bindpoint].swizzle.g =
|
||||||
|
@ -716,7 +722,7 @@ u32 RasterizerOpenGL::SetupTextures(Maxwell::ShaderStage stage, Shader& shader,
|
||||||
MaxwellToGL::SwizzleSource(texture.tic.w_source);
|
MaxwellToGL::SwizzleSource(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_2d = 0;
|
state.texture_units[current_bindpoint].texture = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -93,6 +93,7 @@ private:
|
||||||
Tegra::Texture::TextureFilter min_filter;
|
Tegra::Texture::TextureFilter min_filter;
|
||||||
Tegra::Texture::WrapMode wrap_u;
|
Tegra::Texture::WrapMode wrap_u;
|
||||||
Tegra::Texture::WrapMode wrap_v;
|
Tegra::Texture::WrapMode wrap_v;
|
||||||
|
Tegra::Texture::WrapMode wrap_p;
|
||||||
GLvec4 border_color;
|
GLvec4 border_color;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
|
|
||||||
#include "common/alignment.h"
|
#include "common/alignment.h"
|
||||||
#include "common/assert.h"
|
#include "common/assert.h"
|
||||||
|
#include "common/logging/log.h"
|
||||||
#include "common/microprofile.h"
|
#include "common/microprofile.h"
|
||||||
#include "common/scope_exit.h"
|
#include "common/scope_exit.h"
|
||||||
#include "core/core.h"
|
#include "core/core.h"
|
||||||
|
@ -51,10 +52,12 @@ static VAddr TryGetCpuAddr(Tegra::GPUVAddr gpu_addr) {
|
||||||
params.type = GetFormatType(params.pixel_format);
|
params.type = GetFormatType(params.pixel_format);
|
||||||
params.width = Common::AlignUp(config.tic.Width(), GetCompressionFactor(params.pixel_format));
|
params.width = Common::AlignUp(config.tic.Width(), GetCompressionFactor(params.pixel_format));
|
||||||
params.height = Common::AlignUp(config.tic.Height(), GetCompressionFactor(params.pixel_format));
|
params.height = Common::AlignUp(config.tic.Height(), GetCompressionFactor(params.pixel_format));
|
||||||
|
params.depth = config.tic.Depth();
|
||||||
params.unaligned_height = config.tic.Height();
|
params.unaligned_height = config.tic.Height();
|
||||||
params.size_in_bytes = params.SizeInBytes();
|
params.size_in_bytes = params.SizeInBytes();
|
||||||
params.cache_width = Common::AlignUp(params.width, 16);
|
params.cache_width = Common::AlignUp(params.width, 8);
|
||||||
params.cache_height = Common::AlignUp(params.height, 16);
|
params.cache_height = Common::AlignUp(params.height, 8);
|
||||||
|
params.target = SurfaceTargetFromTextureType(config.tic.texture_type);
|
||||||
return params;
|
return params;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -69,10 +72,12 @@ static VAddr TryGetCpuAddr(Tegra::GPUVAddr gpu_addr) {
|
||||||
params.type = GetFormatType(params.pixel_format);
|
params.type = GetFormatType(params.pixel_format);
|
||||||
params.width = config.width;
|
params.width = config.width;
|
||||||
params.height = config.height;
|
params.height = config.height;
|
||||||
|
params.depth = 1;
|
||||||
params.unaligned_height = config.height;
|
params.unaligned_height = config.height;
|
||||||
params.size_in_bytes = params.SizeInBytes();
|
params.size_in_bytes = params.SizeInBytes();
|
||||||
params.cache_width = Common::AlignUp(params.width, 16);
|
params.cache_width = Common::AlignUp(params.width, 8);
|
||||||
params.cache_height = Common::AlignUp(params.height, 16);
|
params.cache_height = Common::AlignUp(params.height, 8);
|
||||||
|
params.target = SurfaceTarget::Texture2D;
|
||||||
return params;
|
return params;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -86,13 +91,14 @@ static VAddr TryGetCpuAddr(Tegra::GPUVAddr gpu_addr) {
|
||||||
params.pixel_format = PixelFormatFromDepthFormat(format);
|
params.pixel_format = PixelFormatFromDepthFormat(format);
|
||||||
params.component_type = ComponentTypeFromDepthFormat(format);
|
params.component_type = ComponentTypeFromDepthFormat(format);
|
||||||
params.type = GetFormatType(params.pixel_format);
|
params.type = GetFormatType(params.pixel_format);
|
||||||
params.size_in_bytes = params.SizeInBytes();
|
|
||||||
params.width = zeta_width;
|
params.width = zeta_width;
|
||||||
params.height = zeta_height;
|
params.height = zeta_height;
|
||||||
|
params.depth = 1;
|
||||||
params.unaligned_height = zeta_height;
|
params.unaligned_height = zeta_height;
|
||||||
params.size_in_bytes = params.SizeInBytes();
|
params.size_in_bytes = params.SizeInBytes();
|
||||||
params.cache_width = Common::AlignUp(params.width, 16);
|
params.cache_width = Common::AlignUp(params.width, 8);
|
||||||
params.cache_height = Common::AlignUp(params.height, 16);
|
params.cache_height = Common::AlignUp(params.height, 8);
|
||||||
|
params.target = SurfaceTarget::Texture2D;
|
||||||
return params;
|
return params;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -166,6 +172,26 @@ static constexpr std::array<FormatTuple, SurfaceParams::MaxPixelFormat> tex_form
|
||||||
ComponentType::Float, false}, // Z32FS8
|
ComponentType::Float, false}, // Z32FS8
|
||||||
}};
|
}};
|
||||||
|
|
||||||
|
static GLenum SurfaceTargetToGL(SurfaceParams::SurfaceTarget target) {
|
||||||
|
switch (target) {
|
||||||
|
case SurfaceParams::SurfaceTarget::Texture1D:
|
||||||
|
return GL_TEXTURE_1D;
|
||||||
|
case SurfaceParams::SurfaceTarget::Texture2D:
|
||||||
|
return GL_TEXTURE_2D;
|
||||||
|
case SurfaceParams::SurfaceTarget::Texture3D:
|
||||||
|
return GL_TEXTURE_3D;
|
||||||
|
case SurfaceParams::SurfaceTarget::Texture1DArray:
|
||||||
|
return GL_TEXTURE_1D_ARRAY;
|
||||||
|
case SurfaceParams::SurfaceTarget::Texture2DArray:
|
||||||
|
return GL_TEXTURE_2D_ARRAY;
|
||||||
|
case SurfaceParams::SurfaceTarget::TextureCubemap:
|
||||||
|
return GL_TEXTURE_CUBE_MAP;
|
||||||
|
}
|
||||||
|
LOG_CRITICAL(Render_OpenGL, "Unimplemented texture target={}", static_cast<u32>(target));
|
||||||
|
UNREACHABLE();
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
static const FormatTuple& GetFormatTuple(PixelFormat pixel_format, ComponentType component_type) {
|
static const FormatTuple& GetFormatTuple(PixelFormat pixel_format, ComponentType component_type) {
|
||||||
ASSERT(static_cast<size_t>(pixel_format) < tex_format_tuples.size());
|
ASSERT(static_cast<size_t>(pixel_format) < tex_format_tuples.size());
|
||||||
auto& format = tex_format_tuples[static_cast<unsigned int>(pixel_format)];
|
auto& format = tex_format_tuples[static_cast<unsigned int>(pixel_format)];
|
||||||
|
@ -220,7 +246,8 @@ static bool IsFormatBCn(PixelFormat format) {
|
||||||
}
|
}
|
||||||
|
|
||||||
template <bool morton_to_gl, PixelFormat format>
|
template <bool morton_to_gl, PixelFormat format>
|
||||||
void MortonCopy(u32 stride, u32 block_height, u32 height, std::vector<u8>& gl_buffer, VAddr addr) {
|
void MortonCopy(u32 stride, u32 block_height, u32 height, u8* gl_buffer, size_t gl_buffer_size,
|
||||||
|
VAddr addr) {
|
||||||
constexpr u32 bytes_per_pixel = SurfaceParams::GetFormatBpp(format) / CHAR_BIT;
|
constexpr u32 bytes_per_pixel = SurfaceParams::GetFormatBpp(format) / CHAR_BIT;
|
||||||
constexpr u32 gl_bytes_per_pixel = CachedSurface::GetGLBytesPerPixel(format);
|
constexpr u32 gl_bytes_per_pixel = CachedSurface::GetGLBytesPerPixel(format);
|
||||||
|
|
||||||
|
@ -230,18 +257,18 @@ void MortonCopy(u32 stride, u32 block_height, u32 height, std::vector<u8>& gl_bu
|
||||||
const u32 tile_size{IsFormatBCn(format) ? 4U : 1U};
|
const u32 tile_size{IsFormatBCn(format) ? 4U : 1U};
|
||||||
const std::vector<u8> data = Tegra::Texture::UnswizzleTexture(
|
const std::vector<u8> data = Tegra::Texture::UnswizzleTexture(
|
||||||
addr, tile_size, bytes_per_pixel, stride, height, block_height);
|
addr, tile_size, bytes_per_pixel, stride, height, block_height);
|
||||||
const size_t size_to_copy{std::min(gl_buffer.size(), data.size())};
|
const size_t size_to_copy{std::min(gl_buffer_size, data.size())};
|
||||||
gl_buffer.assign(data.begin(), data.begin() + size_to_copy);
|
memcpy(gl_buffer, data.data(), size_to_copy);
|
||||||
} else {
|
} else {
|
||||||
// TODO(bunnei): Assumes the default rendering GOB size of 16 (128 lines). We should
|
// TODO(bunnei): Assumes the default rendering GOB size of 16 (128 lines). We should
|
||||||
// check the configuration for this and perform more generic un/swizzle
|
// check the configuration for this and perform more generic un/swizzle
|
||||||
LOG_WARNING(Render_OpenGL, "need to use correct swizzle/GOB parameters!");
|
LOG_WARNING(Render_OpenGL, "need to use correct swizzle/GOB parameters!");
|
||||||
VideoCore::MortonCopyPixels128(stride, height, bytes_per_pixel, gl_bytes_per_pixel,
|
VideoCore::MortonCopyPixels128(stride, height, bytes_per_pixel, gl_bytes_per_pixel,
|
||||||
Memory::GetPointer(addr), gl_buffer.data(), morton_to_gl);
|
Memory::GetPointer(addr), gl_buffer, morton_to_gl);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static constexpr std::array<void (*)(u32, u32, u32, std::vector<u8>&, VAddr),
|
static constexpr std::array<void (*)(u32, u32, u32, u8*, size_t, VAddr),
|
||||||
SurfaceParams::MaxPixelFormat>
|
SurfaceParams::MaxPixelFormat>
|
||||||
morton_to_gl_fns = {
|
morton_to_gl_fns = {
|
||||||
// clang-format off
|
// clang-format off
|
||||||
|
@ -298,7 +325,7 @@ static constexpr std::array<void (*)(u32, u32, u32, std::vector<u8>&, VAddr),
|
||||||
// clang-format on
|
// clang-format on
|
||||||
};
|
};
|
||||||
|
|
||||||
static constexpr std::array<void (*)(u32, u32, u32, std::vector<u8>&, VAddr),
|
static constexpr std::array<void (*)(u32, u32, u32, u8*, size_t, VAddr),
|
||||||
SurfaceParams::MaxPixelFormat>
|
SurfaceParams::MaxPixelFormat>
|
||||||
gl_to_morton_fns = {
|
gl_to_morton_fns = {
|
||||||
// clang-format off
|
// clang-format off
|
||||||
|
@ -357,33 +384,6 @@ static constexpr std::array<void (*)(u32, u32, u32, std::vector<u8>&, VAddr),
|
||||||
// clang-format on
|
// clang-format on
|
||||||
};
|
};
|
||||||
|
|
||||||
// Allocate an uninitialized texture of appropriate size and format for the surface
|
|
||||||
static void AllocateSurfaceTexture(GLuint texture, const FormatTuple& format_tuple, u32 width,
|
|
||||||
u32 height) {
|
|
||||||
OpenGLState cur_state = OpenGLState::GetCurState();
|
|
||||||
|
|
||||||
// Keep track of previous texture bindings
|
|
||||||
GLuint old_tex = cur_state.texture_units[0].texture_2d;
|
|
||||||
cur_state.texture_units[0].texture_2d = texture;
|
|
||||||
cur_state.Apply();
|
|
||||||
glActiveTexture(GL_TEXTURE0);
|
|
||||||
|
|
||||||
if (!format_tuple.compressed) {
|
|
||||||
// Only pre-create the texture for non-compressed textures.
|
|
||||||
glTexImage2D(GL_TEXTURE_2D, 0, format_tuple.internal_format, width, height, 0,
|
|
||||||
format_tuple.format, format_tuple.type, nullptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
|
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
|
||||||
|
|
||||||
// Restore previous texture bindings
|
|
||||||
cur_state.texture_units[0].texture_2d = old_tex;
|
|
||||||
cur_state.Apply();
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool BlitTextures(GLuint src_tex, const MathUtil::Rectangle<u32>& src_rect, GLuint dst_tex,
|
static bool BlitTextures(GLuint src_tex, const MathUtil::Rectangle<u32>& src_rect, GLuint dst_tex,
|
||||||
const MathUtil::Rectangle<u32>& dst_rect, SurfaceType type,
|
const MathUtil::Rectangle<u32>& dst_rect, SurfaceType type,
|
||||||
GLuint read_fb_handle, GLuint draw_fb_handle) {
|
GLuint read_fb_handle, GLuint draw_fb_handle) {
|
||||||
|
@ -438,12 +438,56 @@ static bool BlitTextures(GLuint src_tex, const MathUtil::Rectangle<u32>& src_rec
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
CachedSurface::CachedSurface(const SurfaceParams& params) : params(params) {
|
CachedSurface::CachedSurface(const SurfaceParams& params)
|
||||||
|
: params(params), gl_target(SurfaceTargetToGL(params.target)) {
|
||||||
texture.Create();
|
texture.Create();
|
||||||
const auto& rect{params.GetRect()};
|
const auto& rect{params.GetRect()};
|
||||||
AllocateSurfaceTexture(texture.handle,
|
|
||||||
GetFormatTuple(params.pixel_format, params.component_type),
|
// Keep track of previous texture bindings
|
||||||
rect.GetWidth(), rect.GetHeight());
|
OpenGLState cur_state = OpenGLState::GetCurState();
|
||||||
|
const auto& old_tex = cur_state.texture_units[0];
|
||||||
|
SCOPE_EXIT({
|
||||||
|
cur_state.texture_units[0] = old_tex;
|
||||||
|
cur_state.Apply();
|
||||||
|
});
|
||||||
|
|
||||||
|
cur_state.texture_units[0].texture = texture.handle;
|
||||||
|
cur_state.texture_units[0].target = SurfaceTargetToGL(params.target);
|
||||||
|
cur_state.Apply();
|
||||||
|
glActiveTexture(GL_TEXTURE0);
|
||||||
|
|
||||||
|
const auto& format_tuple = GetFormatTuple(params.pixel_format, params.component_type);
|
||||||
|
if (!format_tuple.compressed) {
|
||||||
|
// Only pre-create the texture for non-compressed textures.
|
||||||
|
switch (params.target) {
|
||||||
|
case SurfaceParams::SurfaceTarget::Texture1D:
|
||||||
|
glTexImage1D(SurfaceTargetToGL(params.target), 0, format_tuple.internal_format,
|
||||||
|
rect.GetWidth(), 0, format_tuple.format, format_tuple.type, nullptr);
|
||||||
|
break;
|
||||||
|
case SurfaceParams::SurfaceTarget::Texture2D:
|
||||||
|
glTexImage2D(SurfaceTargetToGL(params.target), 0, format_tuple.internal_format,
|
||||||
|
rect.GetWidth(), rect.GetHeight(), 0, format_tuple.format,
|
||||||
|
format_tuple.type, nullptr);
|
||||||
|
break;
|
||||||
|
case SurfaceParams::SurfaceTarget::Texture3D:
|
||||||
|
case SurfaceParams::SurfaceTarget::Texture2DArray:
|
||||||
|
glTexImage3D(SurfaceTargetToGL(params.target), 0, format_tuple.internal_format,
|
||||||
|
rect.GetWidth(), rect.GetHeight(), params.depth, 0, format_tuple.format,
|
||||||
|
format_tuple.type, nullptr);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
LOG_CRITICAL(Render_OpenGL, "Unimplemented surface target={}",
|
||||||
|
static_cast<u32>(params.target));
|
||||||
|
UNREACHABLE();
|
||||||
|
glTexImage2D(GL_TEXTURE_2D, 0, format_tuple.internal_format, rect.GetWidth(),
|
||||||
|
rect.GetHeight(), 0, format_tuple.format, format_tuple.type, nullptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
glTexParameteri(SurfaceTargetToGL(params.target), GL_TEXTURE_MAX_LEVEL, 0);
|
||||||
|
glTexParameteri(SurfaceTargetToGL(params.target), GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||||
|
glTexParameteri(SurfaceTargetToGL(params.target), GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||||
|
glTexParameteri(SurfaceTargetToGL(params.target), GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ConvertS8Z24ToZ24S8(std::vector<u8>& data, u32 width, u32 height) {
|
static void ConvertS8Z24ToZ24S8(std::vector<u8>& data, u32 width, u32 height) {
|
||||||
|
@ -514,23 +558,6 @@ static void ConvertFormatAsNeeded_LoadGLBuffer(std::vector<u8>& data, PixelForma
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Helper function to perform software conversion (as needed) when flushing a buffer to Switch
|
|
||||||
* memory. This is for Maxwell pixel formats that cannot be represented as-is in OpenGL or with
|
|
||||||
* typical desktop GPUs.
|
|
||||||
*/
|
|
||||||
static void ConvertFormatAsNeeded_FlushGLBuffer(std::vector<u8>& /*data*/, PixelFormat pixel_format,
|
|
||||||
u32 /*width*/, u32 /*height*/) {
|
|
||||||
switch (pixel_format) {
|
|
||||||
case PixelFormat::ASTC_2D_4X4:
|
|
||||||
case PixelFormat::S8Z24:
|
|
||||||
LOG_CRITICAL(Render_OpenGL, "Unimplemented pixel_format={}",
|
|
||||||
static_cast<u32>(pixel_format));
|
|
||||||
UNREACHABLE();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
MICROPROFILE_DEFINE(OpenGL_SurfaceLoad, "OpenGL", "Surface Load", MP_RGB(128, 64, 192));
|
MICROPROFILE_DEFINE(OpenGL_SurfaceLoad, "OpenGL", "Surface Load", MP_RGB(128, 64, 192));
|
||||||
void CachedSurface::LoadGLBuffer() {
|
void CachedSurface::LoadGLBuffer() {
|
||||||
ASSERT(params.type != SurfaceType::Fill);
|
ASSERT(params.type != SurfaceType::Fill);
|
||||||
|
@ -545,13 +572,24 @@ void CachedSurface::LoadGLBuffer() {
|
||||||
MICROPROFILE_SCOPE(OpenGL_SurfaceLoad);
|
MICROPROFILE_SCOPE(OpenGL_SurfaceLoad);
|
||||||
|
|
||||||
if (params.is_tiled) {
|
if (params.is_tiled) {
|
||||||
gl_buffer.resize(copy_size);
|
// TODO(bunnei): This only unswizzles and copies a 2D texture - we do not yet know how to do
|
||||||
|
// this for 3D textures, etc.
|
||||||
|
switch (params.target) {
|
||||||
|
case SurfaceParams::SurfaceTarget::Texture2D:
|
||||||
|
// Pass impl. to the fallback code below
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
LOG_CRITICAL(HW_GPU, "Unimplemented tiled load for target={}",
|
||||||
|
static_cast<u32>(params.target));
|
||||||
|
UNREACHABLE();
|
||||||
|
}
|
||||||
|
|
||||||
|
gl_buffer.resize(params.depth * copy_size);
|
||||||
morton_to_gl_fns[static_cast<size_t>(params.pixel_format)](
|
morton_to_gl_fns[static_cast<size_t>(params.pixel_format)](
|
||||||
params.width, params.block_height, params.height, gl_buffer, params.addr);
|
params.width, params.block_height, params.height, gl_buffer.data(), copy_size,
|
||||||
|
params.addr);
|
||||||
} else {
|
} else {
|
||||||
const u8* const texture_src_data_end = texture_src_data + copy_size;
|
const u8* const texture_src_data_end{texture_src_data + (params.depth * copy_size)};
|
||||||
|
|
||||||
gl_buffer.assign(texture_src_data, texture_src_data_end);
|
gl_buffer.assign(texture_src_data, texture_src_data_end);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -560,23 +598,7 @@ void CachedSurface::LoadGLBuffer() {
|
||||||
|
|
||||||
MICROPROFILE_DEFINE(OpenGL_SurfaceFlush, "OpenGL", "Surface Flush", MP_RGB(128, 192, 64));
|
MICROPROFILE_DEFINE(OpenGL_SurfaceFlush, "OpenGL", "Surface Flush", MP_RGB(128, 192, 64));
|
||||||
void CachedSurface::FlushGLBuffer() {
|
void CachedSurface::FlushGLBuffer() {
|
||||||
u8* const dst_buffer = Memory::GetPointer(params.addr);
|
ASSERT_MSG(false, "Unimplemented");
|
||||||
|
|
||||||
ASSERT(dst_buffer);
|
|
||||||
ASSERT(gl_buffer.size() ==
|
|
||||||
params.width * params.height * GetGLBytesPerPixel(params.pixel_format));
|
|
||||||
|
|
||||||
MICROPROFILE_SCOPE(OpenGL_SurfaceFlush);
|
|
||||||
|
|
||||||
ConvertFormatAsNeeded_FlushGLBuffer(gl_buffer, params.pixel_format, params.width,
|
|
||||||
params.height);
|
|
||||||
|
|
||||||
if (!params.is_tiled) {
|
|
||||||
std::memcpy(dst_buffer, gl_buffer.data(), params.size_in_bytes);
|
|
||||||
} else {
|
|
||||||
gl_to_morton_fns[static_cast<size_t>(params.pixel_format)](
|
|
||||||
params.width, params.block_height, params.height, gl_buffer, params.addr);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
MICROPROFILE_DEFINE(OpenGL_TextureUL, "OpenGL", "Texture Upload", MP_RGB(128, 64, 192));
|
MICROPROFILE_DEFINE(OpenGL_TextureUL, "OpenGL", "Texture Upload", MP_RGB(128, 64, 192));
|
||||||
|
@ -587,7 +609,7 @@ void CachedSurface::UploadGLTexture(GLuint read_fb_handle, GLuint draw_fb_handle
|
||||||
MICROPROFILE_SCOPE(OpenGL_TextureUL);
|
MICROPROFILE_SCOPE(OpenGL_TextureUL);
|
||||||
|
|
||||||
ASSERT(gl_buffer.size() ==
|
ASSERT(gl_buffer.size() ==
|
||||||
params.width * params.height * GetGLBytesPerPixel(params.pixel_format));
|
params.width * params.height * GetGLBytesPerPixel(params.pixel_format) * params.depth);
|
||||||
|
|
||||||
const auto& rect{params.GetRect()};
|
const auto& rect{params.GetRect()};
|
||||||
|
|
||||||
|
@ -600,8 +622,13 @@ void CachedSurface::UploadGLTexture(GLuint read_fb_handle, GLuint draw_fb_handle
|
||||||
GLuint target_tex = texture.handle;
|
GLuint target_tex = texture.handle;
|
||||||
OpenGLState cur_state = OpenGLState::GetCurState();
|
OpenGLState cur_state = OpenGLState::GetCurState();
|
||||||
|
|
||||||
GLuint old_tex = cur_state.texture_units[0].texture_2d;
|
const auto& old_tex = cur_state.texture_units[0];
|
||||||
cur_state.texture_units[0].texture_2d = target_tex;
|
SCOPE_EXIT({
|
||||||
|
cur_state.texture_units[0] = old_tex;
|
||||||
|
cur_state.Apply();
|
||||||
|
});
|
||||||
|
cur_state.texture_units[0].texture = target_tex;
|
||||||
|
cur_state.texture_units[0].target = SurfaceTargetToGL(params.target);
|
||||||
cur_state.Apply();
|
cur_state.Apply();
|
||||||
|
|
||||||
// Ensure no bad interactions with GL_UNPACK_ALIGNMENT
|
// Ensure no bad interactions with GL_UNPACK_ALIGNMENT
|
||||||
|
@ -610,74 +637,68 @@ void CachedSurface::UploadGLTexture(GLuint read_fb_handle, GLuint draw_fb_handle
|
||||||
|
|
||||||
glActiveTexture(GL_TEXTURE0);
|
glActiveTexture(GL_TEXTURE0);
|
||||||
if (tuple.compressed) {
|
if (tuple.compressed) {
|
||||||
glCompressedTexImage2D(
|
switch (params.target) {
|
||||||
GL_TEXTURE_2D, 0, tuple.internal_format, static_cast<GLsizei>(params.width),
|
case SurfaceParams::SurfaceTarget::Texture2D:
|
||||||
static_cast<GLsizei>(params.height), 0, static_cast<GLsizei>(params.size_in_bytes),
|
glCompressedTexImage2D(
|
||||||
&gl_buffer[buffer_offset]);
|
SurfaceTargetToGL(params.target), 0, tuple.internal_format,
|
||||||
|
static_cast<GLsizei>(params.width), static_cast<GLsizei>(params.height), 0,
|
||||||
|
static_cast<GLsizei>(params.size_in_bytes), &gl_buffer[buffer_offset]);
|
||||||
|
break;
|
||||||
|
case SurfaceParams::SurfaceTarget::Texture3D:
|
||||||
|
case SurfaceParams::SurfaceTarget::Texture2DArray:
|
||||||
|
glCompressedTexImage3D(
|
||||||
|
SurfaceTargetToGL(params.target), 0, tuple.internal_format,
|
||||||
|
static_cast<GLsizei>(params.width), static_cast<GLsizei>(params.height),
|
||||||
|
static_cast<GLsizei>(params.depth), 0, static_cast<GLsizei>(params.size_in_bytes),
|
||||||
|
&gl_buffer[buffer_offset]);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
LOG_CRITICAL(Render_OpenGL, "Unimplemented surface target={}",
|
||||||
|
static_cast<u32>(params.target));
|
||||||
|
UNREACHABLE();
|
||||||
|
glCompressedTexImage2D(
|
||||||
|
GL_TEXTURE_2D, 0, tuple.internal_format, static_cast<GLsizei>(params.width),
|
||||||
|
static_cast<GLsizei>(params.height), 0, static_cast<GLsizei>(params.size_in_bytes),
|
||||||
|
&gl_buffer[buffer_offset]);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
glTexSubImage2D(GL_TEXTURE_2D, 0, x0, y0, static_cast<GLsizei>(rect.GetWidth()),
|
|
||||||
static_cast<GLsizei>(rect.GetHeight()), tuple.format, tuple.type,
|
switch (params.target) {
|
||||||
&gl_buffer[buffer_offset]);
|
case SurfaceParams::SurfaceTarget::Texture1D:
|
||||||
|
glTexSubImage1D(SurfaceTargetToGL(params.target), 0, x0,
|
||||||
|
static_cast<GLsizei>(rect.GetWidth()), tuple.format, tuple.type,
|
||||||
|
&gl_buffer[buffer_offset]);
|
||||||
|
break;
|
||||||
|
case SurfaceParams::SurfaceTarget::Texture2D:
|
||||||
|
glTexSubImage2D(SurfaceTargetToGL(params.target), 0, x0, y0,
|
||||||
|
static_cast<GLsizei>(rect.GetWidth()),
|
||||||
|
static_cast<GLsizei>(rect.GetHeight()), tuple.format, tuple.type,
|
||||||
|
&gl_buffer[buffer_offset]);
|
||||||
|
break;
|
||||||
|
case SurfaceParams::SurfaceTarget::Texture3D:
|
||||||
|
case SurfaceParams::SurfaceTarget::Texture2DArray:
|
||||||
|
glTexSubImage3D(SurfaceTargetToGL(params.target), 0, x0, y0, 0,
|
||||||
|
static_cast<GLsizei>(rect.GetWidth()),
|
||||||
|
static_cast<GLsizei>(rect.GetHeight()), params.depth, tuple.format,
|
||||||
|
tuple.type, &gl_buffer[buffer_offset]);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
LOG_CRITICAL(Render_OpenGL, "Unimplemented surface target={}",
|
||||||
|
static_cast<u32>(params.target));
|
||||||
|
UNREACHABLE();
|
||||||
|
glTexSubImage2D(GL_TEXTURE_2D, 0, x0, y0, static_cast<GLsizei>(rect.GetWidth()),
|
||||||
|
static_cast<GLsizei>(rect.GetHeight()), tuple.format, tuple.type,
|
||||||
|
&gl_buffer[buffer_offset]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
|
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
|
||||||
|
|
||||||
cur_state.texture_units[0].texture_2d = old_tex;
|
|
||||||
cur_state.Apply();
|
|
||||||
}
|
|
||||||
|
|
||||||
MICROPROFILE_DEFINE(OpenGL_TextureDL, "OpenGL", "Texture Download", MP_RGB(128, 192, 64));
|
|
||||||
void CachedSurface::DownloadGLTexture(GLuint read_fb_handle, GLuint draw_fb_handle) {
|
|
||||||
if (params.type == SurfaceType::Fill)
|
|
||||||
return;
|
|
||||||
|
|
||||||
MICROPROFILE_SCOPE(OpenGL_TextureDL);
|
|
||||||
|
|
||||||
gl_buffer.resize(params.width * params.height * GetGLBytesPerPixel(params.pixel_format));
|
|
||||||
|
|
||||||
OpenGLState state = OpenGLState::GetCurState();
|
|
||||||
OpenGLState prev_state = state;
|
|
||||||
SCOPE_EXIT({ prev_state.Apply(); });
|
|
||||||
|
|
||||||
const FormatTuple& tuple = GetFormatTuple(params.pixel_format, params.component_type);
|
|
||||||
|
|
||||||
// Ensure no bad interactions with GL_PACK_ALIGNMENT
|
|
||||||
ASSERT(params.width * GetGLBytesPerPixel(params.pixel_format) % 4 == 0);
|
|
||||||
glPixelStorei(GL_PACK_ROW_LENGTH, static_cast<GLint>(params.width));
|
|
||||||
|
|
||||||
const auto& rect{params.GetRect()};
|
|
||||||
size_t buffer_offset =
|
|
||||||
(rect.bottom * params.width + rect.left) * GetGLBytesPerPixel(params.pixel_format);
|
|
||||||
|
|
||||||
state.UnbindTexture(texture.handle);
|
|
||||||
state.draw.read_framebuffer = read_fb_handle;
|
|
||||||
state.Apply();
|
|
||||||
|
|
||||||
if (params.type == SurfaceType::ColorTexture) {
|
|
||||||
glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
|
|
||||||
texture.handle, 0);
|
|
||||||
glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0,
|
|
||||||
0);
|
|
||||||
} else if (params.type == SurfaceType::Depth) {
|
|
||||||
glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0);
|
|
||||||
glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D,
|
|
||||||
texture.handle, 0);
|
|
||||||
glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0, 0);
|
|
||||||
} else {
|
|
||||||
glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0);
|
|
||||||
glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D,
|
|
||||||
texture.handle, 0);
|
|
||||||
}
|
|
||||||
glReadPixels(static_cast<GLint>(rect.left), static_cast<GLint>(rect.bottom),
|
|
||||||
static_cast<GLsizei>(rect.GetWidth()), static_cast<GLsizei>(rect.GetHeight()),
|
|
||||||
tuple.format, tuple.type, &gl_buffer[buffer_offset]);
|
|
||||||
|
|
||||||
glPixelStorei(GL_PACK_ROW_LENGTH, 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
RasterizerCacheOpenGL::RasterizerCacheOpenGL() {
|
RasterizerCacheOpenGL::RasterizerCacheOpenGL() {
|
||||||
read_framebuffer.Create();
|
read_framebuffer.Create();
|
||||||
draw_framebuffer.Create();
|
draw_framebuffer.Create();
|
||||||
|
copy_pbo.Create();
|
||||||
}
|
}
|
||||||
|
|
||||||
Surface RasterizerCacheOpenGL::GetTextureSurface(const Tegra::Texture::FullTextureInfo& config) {
|
Surface RasterizerCacheOpenGL::GetTextureSurface(const Tegra::Texture::FullTextureInfo& config) {
|
||||||
|
@ -748,7 +769,6 @@ void RasterizerCacheOpenGL::LoadSurface(const Surface& surface) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void RasterizerCacheOpenGL::FlushSurface(const Surface& surface) {
|
void RasterizerCacheOpenGL::FlushSurface(const Surface& surface) {
|
||||||
surface->DownloadGLTexture(read_framebuffer.handle, draw_framebuffer.handle);
|
|
||||||
surface->FlushGLBuffer();
|
surface->FlushGLBuffer();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -809,8 +829,8 @@ Surface RasterizerCacheOpenGL::RecreateSurface(const Surface& surface,
|
||||||
// If format is unchanged, we can do a faster blit without reinterpreting pixel data
|
// If format is unchanged, we can do a faster blit without reinterpreting pixel data
|
||||||
if (params.pixel_format == new_params.pixel_format) {
|
if (params.pixel_format == new_params.pixel_format) {
|
||||||
BlitTextures(surface->Texture().handle, params.GetRect(), new_surface->Texture().handle,
|
BlitTextures(surface->Texture().handle, params.GetRect(), new_surface->Texture().handle,
|
||||||
new_surface->GetSurfaceParams().GetRect(), params.type,
|
params.GetRect(), params.type, read_framebuffer.handle,
|
||||||
read_framebuffer.handle, draw_framebuffer.handle);
|
draw_framebuffer.handle);
|
||||||
return new_surface;
|
return new_surface;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -821,12 +841,7 @@ Surface RasterizerCacheOpenGL::RecreateSurface(const Surface& surface,
|
||||||
|
|
||||||
size_t buffer_size = std::max(params.SizeInBytes(), new_params.SizeInBytes());
|
size_t buffer_size = std::max(params.SizeInBytes(), new_params.SizeInBytes());
|
||||||
|
|
||||||
// Use a Pixel Buffer Object to download the previous texture and then upload it to the new
|
glBindBuffer(GL_PIXEL_PACK_BUFFER, copy_pbo.handle);
|
||||||
// one using the new format.
|
|
||||||
OGLBuffer pbo;
|
|
||||||
pbo.Create();
|
|
||||||
|
|
||||||
glBindBuffer(GL_PIXEL_PACK_BUFFER, pbo.handle);
|
|
||||||
glBufferData(GL_PIXEL_PACK_BUFFER, buffer_size, nullptr, GL_STREAM_DRAW_ARB);
|
glBufferData(GL_PIXEL_PACK_BUFFER, buffer_size, nullptr, GL_STREAM_DRAW_ARB);
|
||||||
if (source_format.compressed) {
|
if (source_format.compressed) {
|
||||||
glGetCompressedTextureImage(surface->Texture().handle, 0,
|
glGetCompressedTextureImage(surface->Texture().handle, 0,
|
||||||
|
@ -845,8 +860,8 @@ Surface RasterizerCacheOpenGL::RecreateSurface(const Surface& surface,
|
||||||
// of the data in this case. Games like Super Mario Odyssey seem to hit this case
|
// of the data in this case. Games like Super Mario Odyssey seem to hit this case
|
||||||
// when drawing, it re-uses the memory of a previous texture as a bigger framebuffer
|
// when drawing, it re-uses the memory of a previous texture as a bigger framebuffer
|
||||||
// but it doesn't clear it beforehand, the texture is already full of zeros.
|
// but it doesn't clear it beforehand, the texture is already full of zeros.
|
||||||
LOG_CRITICAL(HW_GPU, "Trying to upload extra texture data from the CPU during "
|
LOG_DEBUG(HW_GPU, "Trying to upload extra texture data from the CPU during "
|
||||||
"reinterpretation but the texture is tiled.");
|
"reinterpretation but the texture is tiled.");
|
||||||
}
|
}
|
||||||
size_t remaining_size = new_params.SizeInBytes() - params.SizeInBytes();
|
size_t remaining_size = new_params.SizeInBytes() - params.SizeInBytes();
|
||||||
std::vector<u8> data(remaining_size);
|
std::vector<u8> data(remaining_size);
|
||||||
|
@ -859,21 +874,38 @@ Surface RasterizerCacheOpenGL::RecreateSurface(const Surface& surface,
|
||||||
|
|
||||||
const auto& dest_rect{new_params.GetRect()};
|
const auto& dest_rect{new_params.GetRect()};
|
||||||
|
|
||||||
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pbo.handle);
|
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, copy_pbo.handle);
|
||||||
if (dest_format.compressed) {
|
if (dest_format.compressed) {
|
||||||
glCompressedTexSubImage2D(
|
LOG_CRITICAL(HW_GPU, "Compressed copy is unimplemented!");
|
||||||
GL_TEXTURE_2D, 0, 0, 0, static_cast<GLsizei>(dest_rect.GetWidth()),
|
UNREACHABLE();
|
||||||
static_cast<GLsizei>(dest_rect.GetHeight()), dest_format.format,
|
|
||||||
static_cast<GLsizei>(new_params.SizeInBytes()), nullptr);
|
|
||||||
} else {
|
} else {
|
||||||
glTextureSubImage2D(new_surface->Texture().handle, 0, 0, 0,
|
switch (new_params.target) {
|
||||||
static_cast<GLsizei>(dest_rect.GetWidth()),
|
case SurfaceParams::SurfaceTarget::Texture1D:
|
||||||
static_cast<GLsizei>(dest_rect.GetHeight()), dest_format.format,
|
glTextureSubImage1D(new_surface->Texture().handle, 0, 0,
|
||||||
dest_format.type, nullptr);
|
static_cast<GLsizei>(dest_rect.GetWidth()), dest_format.format,
|
||||||
|
dest_format.type, nullptr);
|
||||||
|
break;
|
||||||
|
case SurfaceParams::SurfaceTarget::Texture2D:
|
||||||
|
glTextureSubImage2D(new_surface->Texture().handle, 0, 0, 0,
|
||||||
|
static_cast<GLsizei>(dest_rect.GetWidth()),
|
||||||
|
static_cast<GLsizei>(dest_rect.GetHeight()), dest_format.format,
|
||||||
|
dest_format.type, nullptr);
|
||||||
|
break;
|
||||||
|
case SurfaceParams::SurfaceTarget::Texture3D:
|
||||||
|
case SurfaceParams::SurfaceTarget::Texture2DArray:
|
||||||
|
glTextureSubImage3D(new_surface->Texture().handle, 0, 0, 0, 0,
|
||||||
|
static_cast<GLsizei>(dest_rect.GetWidth()),
|
||||||
|
static_cast<GLsizei>(dest_rect.GetHeight()),
|
||||||
|
static_cast<GLsizei>(new_params.depth), dest_format.format,
|
||||||
|
dest_format.type, nullptr);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
LOG_CRITICAL(Render_OpenGL, "Unimplemented surface target={}",
|
||||||
|
static_cast<u32>(params.target));
|
||||||
|
UNREACHABLE();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
|
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
|
||||||
|
|
||||||
pbo.Release();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return new_surface;
|
return new_surface;
|
||||||
|
|
|
@ -109,6 +109,33 @@ struct SurfaceParams {
|
||||||
Invalid = 4,
|
Invalid = 4,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum class SurfaceTarget {
|
||||||
|
Texture1D,
|
||||||
|
Texture2D,
|
||||||
|
Texture3D,
|
||||||
|
Texture1DArray,
|
||||||
|
Texture2DArray,
|
||||||
|
TextureCubemap,
|
||||||
|
};
|
||||||
|
|
||||||
|
static SurfaceTarget SurfaceTargetFromTextureType(Tegra::Texture::TextureType texture_type) {
|
||||||
|
switch (texture_type) {
|
||||||
|
case Tegra::Texture::TextureType::Texture1D:
|
||||||
|
return SurfaceTarget::Texture1D;
|
||||||
|
case Tegra::Texture::TextureType::Texture2D:
|
||||||
|
case Tegra::Texture::TextureType::Texture2DNoMipmap:
|
||||||
|
return SurfaceTarget::Texture2D;
|
||||||
|
case Tegra::Texture::TextureType::Texture1DArray:
|
||||||
|
return SurfaceTarget::Texture1DArray;
|
||||||
|
case Tegra::Texture::TextureType::Texture2DArray:
|
||||||
|
return SurfaceTarget::Texture2DArray;
|
||||||
|
default:
|
||||||
|
LOG_CRITICAL(HW_GPU, "Unimplemented texture_type={}", static_cast<u32>(texture_type));
|
||||||
|
UNREACHABLE();
|
||||||
|
return SurfaceTarget::Texture2D;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the compression factor for the specified PixelFormat. This applies to just the
|
* Gets the compression factor for the specified PixelFormat. This applies to just the
|
||||||
* "compressed width" and "compressed height", not the overall compression factor of a
|
* "compressed width" and "compressed height", not the overall compression factor of a
|
||||||
|
@ -635,7 +662,7 @@ struct SurfaceParams {
|
||||||
ASSERT(width % compression_factor == 0);
|
ASSERT(width % compression_factor == 0);
|
||||||
ASSERT(height % compression_factor == 0);
|
ASSERT(height % compression_factor == 0);
|
||||||
return (width / compression_factor) * (height / compression_factor) *
|
return (width / compression_factor) * (height / compression_factor) *
|
||||||
GetFormatBpp(pixel_format) / CHAR_BIT;
|
GetFormatBpp(pixel_format) * depth / CHAR_BIT;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates SurfaceParams from a texture configuration
|
/// Creates SurfaceParams from a texture configuration
|
||||||
|
@ -664,8 +691,10 @@ struct SurfaceParams {
|
||||||
SurfaceType type;
|
SurfaceType type;
|
||||||
u32 width;
|
u32 width;
|
||||||
u32 height;
|
u32 height;
|
||||||
|
u32 depth;
|
||||||
u32 unaligned_height;
|
u32 unaligned_height;
|
||||||
size_t size_in_bytes;
|
size_t size_in_bytes;
|
||||||
|
SurfaceTarget target;
|
||||||
|
|
||||||
// Parameters used for caching only
|
// Parameters used for caching only
|
||||||
u32 cache_width;
|
u32 cache_width;
|
||||||
|
@ -709,6 +738,10 @@ public:
|
||||||
return texture;
|
return texture;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GLenum Target() const {
|
||||||
|
return gl_target;
|
||||||
|
}
|
||||||
|
|
||||||
static constexpr unsigned int GetGLBytesPerPixel(SurfaceParams::PixelFormat format) {
|
static constexpr unsigned int GetGLBytesPerPixel(SurfaceParams::PixelFormat format) {
|
||||||
if (format == SurfaceParams::PixelFormat::Invalid)
|
if (format == SurfaceParams::PixelFormat::Invalid)
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -724,14 +757,14 @@ public:
|
||||||
void LoadGLBuffer();
|
void LoadGLBuffer();
|
||||||
void FlushGLBuffer();
|
void FlushGLBuffer();
|
||||||
|
|
||||||
// Upload/Download data in gl_buffer in/to this surface's texture
|
// Upload data in gl_buffer to this surface's texture
|
||||||
void UploadGLTexture(GLuint read_fb_handle, GLuint draw_fb_handle);
|
void UploadGLTexture(GLuint read_fb_handle, GLuint draw_fb_handle);
|
||||||
void DownloadGLTexture(GLuint read_fb_handle, GLuint draw_fb_handle);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
OGLTexture texture;
|
OGLTexture texture;
|
||||||
std::vector<u8> gl_buffer;
|
std::vector<u8> gl_buffer;
|
||||||
SurfaceParams params;
|
SurfaceParams params;
|
||||||
|
GLenum gl_target;
|
||||||
};
|
};
|
||||||
|
|
||||||
class RasterizerCacheOpenGL final : public RasterizerCache<Surface> {
|
class RasterizerCacheOpenGL final : public RasterizerCache<Surface> {
|
||||||
|
@ -774,6 +807,10 @@ private:
|
||||||
|
|
||||||
OGLFramebuffer read_framebuffer;
|
OGLFramebuffer read_framebuffer;
|
||||||
OGLFramebuffer draw_framebuffer;
|
OGLFramebuffer draw_framebuffer;
|
||||||
|
|
||||||
|
/// Use a Pixel Buffer Object to download the previous texture and then upload it to the new one
|
||||||
|
/// using the new format.
|
||||||
|
OGLBuffer copy_pbo;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace OpenGL
|
} // namespace OpenGL
|
||||||
|
|
|
@ -443,13 +443,12 @@ public:
|
||||||
}
|
}
|
||||||
declarations.AddNewLine();
|
declarations.AddNewLine();
|
||||||
|
|
||||||
// Append the sampler2D array for the used textures.
|
const auto& samplers = GetSamplers();
|
||||||
const size_t num_samplers = used_samplers.size();
|
for (const auto& sampler : samplers) {
|
||||||
if (num_samplers > 0) {
|
declarations.AddLine("uniform " + sampler.GetTypeString() + ' ' + sampler.GetName() +
|
||||||
declarations.AddLine("uniform sampler2D " + SamplerEntry::GetArrayName(stage) + '[' +
|
';');
|
||||||
std::to_string(num_samplers) + "];");
|
|
||||||
declarations.AddNewLine();
|
|
||||||
}
|
}
|
||||||
|
declarations.AddNewLine();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a list of constant buffer declarations
|
/// Returns a list of constant buffer declarations
|
||||||
|
@ -461,13 +460,14 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a list of samplers used in the shader
|
/// Returns a list of samplers used in the shader
|
||||||
std::vector<SamplerEntry> GetSamplers() const {
|
const std::vector<SamplerEntry>& GetSamplers() const {
|
||||||
return used_samplers;
|
return used_samplers;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the GLSL sampler used for the input shader sampler, and creates a new one if
|
/// Returns the GLSL sampler used for the input shader sampler, and creates a new one if
|
||||||
/// necessary.
|
/// necessary.
|
||||||
std::string AccessSampler(const Sampler& sampler) {
|
std::string AccessSampler(const Sampler& sampler, Tegra::Shader::TextureType type,
|
||||||
|
bool is_array) {
|
||||||
size_t offset = static_cast<size_t>(sampler.index.Value());
|
size_t offset = static_cast<size_t>(sampler.index.Value());
|
||||||
|
|
||||||
// If this sampler has already been used, return the existing mapping.
|
// If this sampler has already been used, return the existing mapping.
|
||||||
|
@ -476,12 +476,13 @@ public:
|
||||||
[&](const SamplerEntry& entry) { return entry.GetOffset() == offset; });
|
[&](const SamplerEntry& entry) { return entry.GetOffset() == offset; });
|
||||||
|
|
||||||
if (itr != used_samplers.end()) {
|
if (itr != used_samplers.end()) {
|
||||||
|
ASSERT(itr->GetType() == type && itr->IsArray() == is_array);
|
||||||
return itr->GetName();
|
return itr->GetName();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Otherwise create a new mapping for this sampler
|
// Otherwise create a new mapping for this sampler
|
||||||
size_t next_index = used_samplers.size();
|
size_t next_index = used_samplers.size();
|
||||||
SamplerEntry entry{stage, offset, next_index};
|
SamplerEntry entry{stage, offset, next_index, type, is_array};
|
||||||
used_samplers.emplace_back(entry);
|
used_samplers.emplace_back(entry);
|
||||||
return entry.GetName();
|
return entry.GetName();
|
||||||
}
|
}
|
||||||
|
@ -722,8 +723,8 @@ private:
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Generates code representing a texture sampler.
|
/// Generates code representing a texture sampler.
|
||||||
std::string GetSampler(const Sampler& sampler) {
|
std::string GetSampler(const Sampler& sampler, Tegra::Shader::TextureType type, bool is_array) {
|
||||||
return regs.AccessSampler(sampler);
|
return regs.AccessSampler(sampler, type, is_array);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1753,10 +1754,35 @@ private:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case OpCode::Id::TEX: {
|
case OpCode::Id::TEX: {
|
||||||
const std::string op_a = regs.GetRegisterAsFloat(instr.gpr8);
|
ASSERT_MSG(instr.tex.array == 0, "TEX arrays unimplemented");
|
||||||
const std::string op_b = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1);
|
Tegra::Shader::TextureType texture_type{instr.tex.texture_type};
|
||||||
const std::string sampler = GetSampler(instr.sampler);
|
std::string coord;
|
||||||
const std::string coord = "vec2 coords = vec2(" + op_a + ", " + op_b + ");";
|
|
||||||
|
switch (texture_type) {
|
||||||
|
case Tegra::Shader::TextureType::Texture1D: {
|
||||||
|
std::string x = regs.GetRegisterAsFloat(instr.gpr8);
|
||||||
|
coord = "float coords = " + x + ';';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Tegra::Shader::TextureType::Texture2D: {
|
||||||
|
std::string x = regs.GetRegisterAsFloat(instr.gpr8);
|
||||||
|
std::string y = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1);
|
||||||
|
coord = "vec2 coords = vec2(" + x + ", " + y + ");";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
LOG_CRITICAL(HW_GPU, "Unhandled texture type {}",
|
||||||
|
static_cast<u32>(texture_type));
|
||||||
|
UNREACHABLE();
|
||||||
|
|
||||||
|
// Fallback to interpreting as a 2D texture for now
|
||||||
|
std::string x = regs.GetRegisterAsFloat(instr.gpr8);
|
||||||
|
std::string y = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1);
|
||||||
|
coord = "vec2 coords = vec2(" + x + ", " + y + ");";
|
||||||
|
texture_type = Tegra::Shader::TextureType::Texture2D;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::string sampler = GetSampler(instr.sampler, texture_type, false);
|
||||||
// Add an extra scope and declare the texture coords inside to prevent
|
// Add an extra scope and declare the texture coords inside to prevent
|
||||||
// overwriting them in case they are used as outputs of the texs instruction.
|
// overwriting them in case they are used as outputs of the texs instruction.
|
||||||
shader.AddLine("{");
|
shader.AddLine("{");
|
||||||
|
@ -1778,20 +1804,65 @@ private:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case OpCode::Id::TEXS: {
|
case OpCode::Id::TEXS: {
|
||||||
const std::string op_a = regs.GetRegisterAsFloat(instr.gpr8);
|
std::string coord;
|
||||||
const std::string op_b = regs.GetRegisterAsFloat(instr.gpr20);
|
Tegra::Shader::TextureType texture_type{instr.texs.GetTextureType()};
|
||||||
const std::string sampler = GetSampler(instr.sampler);
|
bool is_array{instr.texs.IsArrayTexture()};
|
||||||
const std::string coord = "vec2 coords = vec2(" + op_a + ", " + op_b + ");";
|
|
||||||
|
|
||||||
|
switch (texture_type) {
|
||||||
|
case Tegra::Shader::TextureType::Texture2D: {
|
||||||
|
if (is_array) {
|
||||||
|
std::string index = regs.GetRegisterAsInteger(instr.gpr8);
|
||||||
|
std::string x = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1);
|
||||||
|
std::string y = regs.GetRegisterAsFloat(instr.gpr20);
|
||||||
|
coord = "vec3 coords = vec3(" + x + ", " + y + ", " + index + ");";
|
||||||
|
} else {
|
||||||
|
std::string x = regs.GetRegisterAsFloat(instr.gpr8);
|
||||||
|
std::string y = regs.GetRegisterAsFloat(instr.gpr20);
|
||||||
|
coord = "vec2 coords = vec2(" + x + ", " + y + ");";
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
LOG_CRITICAL(HW_GPU, "Unhandled texture type {}",
|
||||||
|
static_cast<u32>(texture_type));
|
||||||
|
UNREACHABLE();
|
||||||
|
|
||||||
|
// Fallback to interpreting as a 2D texture for now
|
||||||
|
std::string x = regs.GetRegisterAsFloat(instr.gpr8);
|
||||||
|
std::string y = regs.GetRegisterAsFloat(instr.gpr20);
|
||||||
|
coord = "vec2 coords = vec2(" + x + ", " + y + ");";
|
||||||
|
texture_type = Tegra::Shader::TextureType::Texture2D;
|
||||||
|
is_array = false;
|
||||||
|
}
|
||||||
|
const std::string sampler = GetSampler(instr.sampler, texture_type, is_array);
|
||||||
const std::string texture = "texture(" + sampler + ", coords)";
|
const std::string texture = "texture(" + sampler + ", coords)";
|
||||||
WriteTexsInstruction(instr, coord, texture);
|
WriteTexsInstruction(instr, coord, texture);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case OpCode::Id::TLDS: {
|
case OpCode::Id::TLDS: {
|
||||||
const std::string op_a = regs.GetRegisterAsInteger(instr.gpr8);
|
ASSERT(instr.tlds.GetTextureType() == Tegra::Shader::TextureType::Texture2D);
|
||||||
const std::string op_b = regs.GetRegisterAsInteger(instr.gpr20);
|
ASSERT(instr.tlds.IsArrayTexture() == false);
|
||||||
const std::string sampler = GetSampler(instr.sampler);
|
std::string coord;
|
||||||
const std::string coord = "ivec2 coords = ivec2(" + op_a + ", " + op_b + ");";
|
|
||||||
|
switch (instr.tlds.GetTextureType()) {
|
||||||
|
case Tegra::Shader::TextureType::Texture2D: {
|
||||||
|
if (instr.tlds.IsArrayTexture()) {
|
||||||
|
LOG_CRITICAL(HW_GPU, "Unhandled 2d array texture");
|
||||||
|
UNREACHABLE();
|
||||||
|
} else {
|
||||||
|
std::string x = regs.GetRegisterAsInteger(instr.gpr8);
|
||||||
|
std::string y = regs.GetRegisterAsInteger(instr.gpr20);
|
||||||
|
coord = "ivec2 coords = ivec2(" + x + ", " + y + ");";
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
LOG_CRITICAL(HW_GPU, "Unhandled texture type {}",
|
||||||
|
static_cast<u32>(instr.tlds.GetTextureType()));
|
||||||
|
UNREACHABLE();
|
||||||
|
}
|
||||||
|
const std::string sampler = GetSampler(instr.sampler, instr.tlds.GetTextureType(),
|
||||||
|
instr.tlds.IsArrayTexture());
|
||||||
const std::string texture = "texelFetch(" + sampler + ", coords, 0)";
|
const std::string texture = "texelFetch(" + sampler + ", coords, 0)";
|
||||||
WriteTexsInstruction(instr, coord, texture);
|
WriteTexsInstruction(instr, coord, texture);
|
||||||
break;
|
break;
|
||||||
|
@ -1799,7 +1870,7 @@ private:
|
||||||
case OpCode::Id::TLD4: {
|
case OpCode::Id::TLD4: {
|
||||||
ASSERT(instr.tld4.texture_type == Tegra::Shader::TextureType::Texture2D);
|
ASSERT(instr.tld4.texture_type == Tegra::Shader::TextureType::Texture2D);
|
||||||
ASSERT(instr.tld4.array == 0);
|
ASSERT(instr.tld4.array == 0);
|
||||||
std::string coord{};
|
std::string coord;
|
||||||
|
|
||||||
switch (instr.tld4.texture_type) {
|
switch (instr.tld4.texture_type) {
|
||||||
case Tegra::Shader::TextureType::Texture2D: {
|
case Tegra::Shader::TextureType::Texture2D: {
|
||||||
|
@ -1814,7 +1885,8 @@ private:
|
||||||
UNREACHABLE();
|
UNREACHABLE();
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::string sampler = GetSampler(instr.sampler);
|
const std::string sampler =
|
||||||
|
GetSampler(instr.sampler, instr.tld4.texture_type, false);
|
||||||
// Add an extra scope and declare the texture coords inside to prevent
|
// Add an extra scope and declare the texture coords inside to prevent
|
||||||
// overwriting them in case they are used as outputs of the texs instruction.
|
// overwriting them in case they are used as outputs of the texs instruction.
|
||||||
shader.AddLine("{");
|
shader.AddLine("{");
|
||||||
|
@ -1840,7 +1912,8 @@ private:
|
||||||
const std::string op_a = regs.GetRegisterAsFloat(instr.gpr8);
|
const std::string op_a = regs.GetRegisterAsFloat(instr.gpr8);
|
||||||
const std::string op_b = regs.GetRegisterAsFloat(instr.gpr20);
|
const std::string op_b = regs.GetRegisterAsFloat(instr.gpr20);
|
||||||
// TODO(Subv): Figure out how the sampler type is encoded in the TLD4S instruction.
|
// TODO(Subv): Figure out how the sampler type is encoded in the TLD4S instruction.
|
||||||
const std::string sampler = GetSampler(instr.sampler);
|
const std::string sampler =
|
||||||
|
GetSampler(instr.sampler, Tegra::Shader::TextureType::Texture2D, false);
|
||||||
const std::string coord = "vec2 coords = vec2(" + op_a + ", " + op_b + ");";
|
const std::string coord = "vec2 coords = vec2(" + op_a + ", " + op_b + ");";
|
||||||
const std::string texture = "textureGather(" + sampler + ", coords, " +
|
const std::string texture = "textureGather(" + sampler + ", coords, " +
|
||||||
std::to_string(instr.tld4s.component) + ')';
|
std::to_string(instr.tld4s.component) + ')';
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
|
#include "video_core/engines/shader_bytecode.h"
|
||||||
|
|
||||||
namespace OpenGL::GLShader {
|
namespace OpenGL::GLShader {
|
||||||
|
|
||||||
|
@ -73,8 +74,9 @@ class SamplerEntry {
|
||||||
using Maxwell = Tegra::Engines::Maxwell3D::Regs;
|
using Maxwell = Tegra::Engines::Maxwell3D::Regs;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
SamplerEntry(Maxwell::ShaderStage stage, size_t offset, size_t index)
|
SamplerEntry(Maxwell::ShaderStage stage, size_t offset, size_t index,
|
||||||
: offset(offset), stage(stage), sampler_index(index) {}
|
Tegra::Shader::TextureType type, bool is_array)
|
||||||
|
: offset(offset), stage(stage), sampler_index(index), type(type), is_array(is_array) {}
|
||||||
|
|
||||||
size_t GetOffset() const {
|
size_t GetOffset() const {
|
||||||
return offset;
|
return offset;
|
||||||
|
@ -89,8 +91,41 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string GetName() const {
|
std::string GetName() const {
|
||||||
return std::string(TextureSamplerNames[static_cast<size_t>(stage)]) + '[' +
|
return std::string(TextureSamplerNames[static_cast<size_t>(stage)]) + '_' +
|
||||||
std::to_string(sampler_index) + ']';
|
std::to_string(sampler_index);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string GetTypeString() const {
|
||||||
|
using Tegra::Shader::TextureType;
|
||||||
|
std::string glsl_type;
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case TextureType::Texture1D:
|
||||||
|
glsl_type = "sampler1D";
|
||||||
|
break;
|
||||||
|
case TextureType::Texture2D:
|
||||||
|
glsl_type = "sampler2D";
|
||||||
|
break;
|
||||||
|
case TextureType::Texture3D:
|
||||||
|
glsl_type = "sampler3D";
|
||||||
|
break;
|
||||||
|
case TextureType::TextureCube:
|
||||||
|
glsl_type = "samplerCube";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
UNIMPLEMENTED();
|
||||||
|
}
|
||||||
|
if (is_array)
|
||||||
|
glsl_type += "Array";
|
||||||
|
return glsl_type;
|
||||||
|
}
|
||||||
|
|
||||||
|
Tegra::Shader::TextureType GetType() const {
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsArray() const {
|
||||||
|
return is_array;
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 GetHash() const {
|
u32 GetHash() const {
|
||||||
|
@ -105,11 +140,14 @@ private:
|
||||||
static constexpr std::array<const char*, Maxwell::MaxShaderStage> TextureSamplerNames = {
|
static constexpr std::array<const char*, Maxwell::MaxShaderStage> TextureSamplerNames = {
|
||||||
"tex_vs", "tex_tessc", "tex_tesse", "tex_gs", "tex_fs",
|
"tex_vs", "tex_tessc", "tex_tesse", "tex_gs", "tex_fs",
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Offset in TSC memory from which to read the sampler object, as specified by the sampling
|
/// Offset in TSC memory from which to read the sampler object, as specified by the sampling
|
||||||
/// instruction.
|
/// instruction.
|
||||||
size_t offset;
|
size_t offset;
|
||||||
Maxwell::ShaderStage stage; ///< Shader stage where this sampler was used.
|
Maxwell::ShaderStage stage; ///< Shader stage where this sampler was used.
|
||||||
size_t sampler_index; ///< Value used to index into the generated GLSL sampler array.
|
size_t sampler_index; ///< Value used to index into the generated GLSL sampler array.
|
||||||
|
Tegra::Shader::TextureType type; ///< The type used to sample this texture (Texture2D, etc)
|
||||||
|
bool is_array; ///< Whether the texture is being sampled as an array texture or not.
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ShaderEntries {
|
struct ShaderEntries {
|
||||||
|
|
|
@ -200,9 +200,9 @@ void OpenGLState::Apply() const {
|
||||||
const auto& texture_unit = texture_units[i];
|
const auto& texture_unit = texture_units[i];
|
||||||
const auto& cur_state_texture_unit = cur_state.texture_units[i];
|
const auto& cur_state_texture_unit = cur_state.texture_units[i];
|
||||||
|
|
||||||
if (texture_unit.texture_2d != cur_state_texture_unit.texture_2d) {
|
if (texture_unit.texture != cur_state_texture_unit.texture) {
|
||||||
glActiveTexture(TextureUnits::MaxwellTexture(static_cast<int>(i)).Enum());
|
glActiveTexture(TextureUnits::MaxwellTexture(static_cast<int>(i)).Enum());
|
||||||
glBindTexture(GL_TEXTURE_2D, texture_unit.texture_2d);
|
glBindTexture(texture_unit.target, texture_unit.texture);
|
||||||
}
|
}
|
||||||
if (texture_unit.sampler != cur_state_texture_unit.sampler) {
|
if (texture_unit.sampler != cur_state_texture_unit.sampler) {
|
||||||
glBindSampler(static_cast<GLuint>(i), texture_unit.sampler);
|
glBindSampler(static_cast<GLuint>(i), texture_unit.sampler);
|
||||||
|
@ -214,7 +214,7 @@ void OpenGLState::Apply() const {
|
||||||
texture_unit.swizzle.a != cur_state_texture_unit.swizzle.a) {
|
texture_unit.swizzle.a != cur_state_texture_unit.swizzle.a) {
|
||||||
std::array<GLint, 4> mask = {texture_unit.swizzle.r, texture_unit.swizzle.g,
|
std::array<GLint, 4> mask = {texture_unit.swizzle.r, texture_unit.swizzle.g,
|
||||||
texture_unit.swizzle.b, texture_unit.swizzle.a};
|
texture_unit.swizzle.b, texture_unit.swizzle.a};
|
||||||
glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, mask.data());
|
glTexParameteriv(texture_unit.target, GL_TEXTURE_SWIZZLE_RGBA, mask.data());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -287,7 +287,7 @@ void OpenGLState::Apply() const {
|
||||||
|
|
||||||
OpenGLState& OpenGLState::UnbindTexture(GLuint handle) {
|
OpenGLState& OpenGLState::UnbindTexture(GLuint handle) {
|
||||||
for (auto& unit : texture_units) {
|
for (auto& unit : texture_units) {
|
||||||
if (unit.texture_2d == handle) {
|
if (unit.texture == handle) {
|
||||||
unit.Unbind();
|
unit.Unbind();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -94,8 +94,9 @@ public:
|
||||||
|
|
||||||
// 3 texture units - one for each that is used in PICA fragment shader emulation
|
// 3 texture units - one for each that is used in PICA fragment shader emulation
|
||||||
struct TextureUnit {
|
struct TextureUnit {
|
||||||
GLuint texture_2d; // GL_TEXTURE_BINDING_2D
|
GLuint texture; // GL_TEXTURE_BINDING_2D
|
||||||
GLuint sampler; // GL_SAMPLER_BINDING
|
GLuint sampler; // GL_SAMPLER_BINDING
|
||||||
|
GLenum target;
|
||||||
struct {
|
struct {
|
||||||
GLint r; // GL_TEXTURE_SWIZZLE_R
|
GLint r; // GL_TEXTURE_SWIZZLE_R
|
||||||
GLint g; // GL_TEXTURE_SWIZZLE_G
|
GLint g; // GL_TEXTURE_SWIZZLE_G
|
||||||
|
@ -104,7 +105,7 @@ public:
|
||||||
} swizzle;
|
} swizzle;
|
||||||
|
|
||||||
void Unbind() {
|
void Unbind() {
|
||||||
texture_2d = 0;
|
texture = 0;
|
||||||
swizzle.r = GL_RED;
|
swizzle.r = GL_RED;
|
||||||
swizzle.g = GL_GREEN;
|
swizzle.g = GL_GREEN;
|
||||||
swizzle.b = GL_BLUE;
|
swizzle.b = GL_BLUE;
|
||||||
|
@ -114,6 +115,7 @@ public:
|
||||||
void Reset() {
|
void Reset() {
|
||||||
Unbind();
|
Unbind();
|
||||||
sampler = 0;
|
sampler = 0;
|
||||||
|
target = GL_TEXTURE_2D;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
std::array<TextureUnit, 32> texture_units;
|
std::array<TextureUnit, 32> texture_units;
|
||||||
|
|
|
@ -177,7 +177,7 @@ void RendererOpenGL::LoadFBToScreenInfo(const Tegra::FramebufferConfig& framebuf
|
||||||
Memory::GetPointer(framebuffer_addr),
|
Memory::GetPointer(framebuffer_addr),
|
||||||
gl_framebuffer_data.data(), true);
|
gl_framebuffer_data.data(), true);
|
||||||
|
|
||||||
state.texture_units[0].texture_2d = screen_info.texture.resource.handle;
|
state.texture_units[0].texture = screen_info.texture.resource.handle;
|
||||||
state.Apply();
|
state.Apply();
|
||||||
|
|
||||||
glActiveTexture(GL_TEXTURE0);
|
glActiveTexture(GL_TEXTURE0);
|
||||||
|
@ -194,7 +194,7 @@ void RendererOpenGL::LoadFBToScreenInfo(const Tegra::FramebufferConfig& framebuf
|
||||||
|
|
||||||
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
|
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
|
||||||
|
|
||||||
state.texture_units[0].texture_2d = 0;
|
state.texture_units[0].texture = 0;
|
||||||
state.Apply();
|
state.Apply();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -205,7 +205,7 @@ void RendererOpenGL::LoadFBToScreenInfo(const Tegra::FramebufferConfig& framebuf
|
||||||
*/
|
*/
|
||||||
void RendererOpenGL::LoadColorToActiveGLTexture(u8 color_r, u8 color_g, u8 color_b, u8 color_a,
|
void RendererOpenGL::LoadColorToActiveGLTexture(u8 color_r, u8 color_g, u8 color_b, u8 color_a,
|
||||||
const TextureInfo& texture) {
|
const TextureInfo& texture) {
|
||||||
state.texture_units[0].texture_2d = texture.resource.handle;
|
state.texture_units[0].texture = texture.resource.handle;
|
||||||
state.Apply();
|
state.Apply();
|
||||||
|
|
||||||
glActiveTexture(GL_TEXTURE0);
|
glActiveTexture(GL_TEXTURE0);
|
||||||
|
@ -214,7 +214,7 @@ void RendererOpenGL::LoadColorToActiveGLTexture(u8 color_r, u8 color_g, u8 color
|
||||||
// Update existing texture
|
// Update existing texture
|
||||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, framebuffer_data);
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, framebuffer_data);
|
||||||
|
|
||||||
state.texture_units[0].texture_2d = 0;
|
state.texture_units[0].texture = 0;
|
||||||
state.Apply();
|
state.Apply();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -260,7 +260,7 @@ void RendererOpenGL::InitOpenGLObjects() {
|
||||||
// Allocation of storage is deferred until the first frame, when we
|
// Allocation of storage is deferred until the first frame, when we
|
||||||
// know the framebuffer size.
|
// know the framebuffer size.
|
||||||
|
|
||||||
state.texture_units[0].texture_2d = screen_info.texture.resource.handle;
|
state.texture_units[0].texture = screen_info.texture.resource.handle;
|
||||||
state.Apply();
|
state.Apply();
|
||||||
|
|
||||||
glActiveTexture(GL_TEXTURE0);
|
glActiveTexture(GL_TEXTURE0);
|
||||||
|
@ -272,7 +272,7 @@ void RendererOpenGL::InitOpenGLObjects() {
|
||||||
|
|
||||||
screen_info.display_texture = screen_info.texture.resource.handle;
|
screen_info.display_texture = screen_info.texture.resource.handle;
|
||||||
|
|
||||||
state.texture_units[0].texture_2d = 0;
|
state.texture_units[0].texture = 0;
|
||||||
state.Apply();
|
state.Apply();
|
||||||
|
|
||||||
// Clear screen to black
|
// Clear screen to black
|
||||||
|
@ -305,14 +305,14 @@ void RendererOpenGL::ConfigureFramebufferTexture(TextureInfo& texture,
|
||||||
UNREACHABLE();
|
UNREACHABLE();
|
||||||
}
|
}
|
||||||
|
|
||||||
state.texture_units[0].texture_2d = texture.resource.handle;
|
state.texture_units[0].texture = texture.resource.handle;
|
||||||
state.Apply();
|
state.Apply();
|
||||||
|
|
||||||
glActiveTexture(GL_TEXTURE0);
|
glActiveTexture(GL_TEXTURE0);
|
||||||
glTexImage2D(GL_TEXTURE_2D, 0, internal_format, texture.width, texture.height, 0,
|
glTexImage2D(GL_TEXTURE_2D, 0, internal_format, texture.width, texture.height, 0,
|
||||||
texture.gl_format, texture.gl_type, nullptr);
|
texture.gl_format, texture.gl_type, nullptr);
|
||||||
|
|
||||||
state.texture_units[0].texture_2d = 0;
|
state.texture_units[0].texture = 0;
|
||||||
state.Apply();
|
state.Apply();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -354,14 +354,14 @@ void RendererOpenGL::DrawScreenTriangles(const ScreenInfo& screen_info, float x,
|
||||||
ScreenRectVertex(x + w, y + h, texcoords.bottom * scale_u, right * scale_v),
|
ScreenRectVertex(x + w, y + h, texcoords.bottom * scale_u, right * scale_v),
|
||||||
}};
|
}};
|
||||||
|
|
||||||
state.texture_units[0].texture_2d = screen_info.display_texture;
|
state.texture_units[0].texture = screen_info.display_texture;
|
||||||
state.texture_units[0].swizzle = {GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA};
|
state.texture_units[0].swizzle = {GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA};
|
||||||
state.Apply();
|
state.Apply();
|
||||||
|
|
||||||
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(vertices), vertices.data());
|
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(vertices), vertices.data());
|
||||||
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
||||||
|
|
||||||
state.texture_units[0].texture_2d = 0;
|
state.texture_units[0].texture = 0;
|
||||||
state.Apply();
|
state.Apply();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -170,8 +170,12 @@ struct TICEntry {
|
||||||
BitField<0, 16, u32> width_minus_1;
|
BitField<0, 16, u32> width_minus_1;
|
||||||
BitField<23, 4, TextureType> texture_type;
|
BitField<23, 4, TextureType> texture_type;
|
||||||
};
|
};
|
||||||
u16 height_minus_1;
|
union {
|
||||||
INSERT_PADDING_BYTES(10);
|
BitField<0, 16, u32> height_minus_1;
|
||||||
|
BitField<16, 15, u32> depth_minus_1;
|
||||||
|
};
|
||||||
|
|
||||||
|
INSERT_PADDING_BYTES(8);
|
||||||
|
|
||||||
GPUVAddr Address() const {
|
GPUVAddr Address() const {
|
||||||
return static_cast<GPUVAddr>((static_cast<GPUVAddr>(address_high) << 32) | address_low);
|
return static_cast<GPUVAddr>((static_cast<GPUVAddr>(address_high) << 32) | address_low);
|
||||||
|
@ -192,6 +196,10 @@ struct TICEntry {
|
||||||
return height_minus_1 + 1;
|
return height_minus_1 + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
u32 Depth() const {
|
||||||
|
return depth_minus_1 + 1;
|
||||||
|
}
|
||||||
|
|
||||||
u32 BlockHeight() const {
|
u32 BlockHeight() const {
|
||||||
ASSERT(header_version == TICHeaderVersion::BlockLinear ||
|
ASSERT(header_version == TICHeaderVersion::BlockLinear ||
|
||||||
header_version == TICHeaderVersion::BlockLinearColorKey);
|
header_version == TICHeaderVersion::BlockLinearColorKey);
|
||||||
|
|
Loading…
Reference in a new issue