summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/video_core/engines/maxwell_3d.cpp4
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.cpp16
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.h1
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer_cache.cpp364
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer_cache.h43
-rw-r--r--src/video_core/renderer_opengl/gl_shader_decompiler.cpp125
-rw-r--r--src/video_core/renderer_opengl/gl_shader_gen.h50
-rw-r--r--src/video_core/renderer_opengl/gl_state.cpp8
-rw-r--r--src/video_core/renderer_opengl/gl_state.h8
-rw-r--r--src/video_core/renderer_opengl/renderer_opengl.cpp20
-rw-r--r--src/video_core/textures/texture.h12
11 files changed, 422 insertions, 229 deletions
diff --git a/src/video_core/engines/maxwell_3d.cpp b/src/video_core/engines/maxwell_3d.cpp
index e63ad4d46..1308080b5 100644
--- a/src/video_core/engines/maxwell_3d.cpp
+++ b/src/video_core/engines/maxwell_3d.cpp
@@ -293,10 +293,6 @@ Texture::TICEntry Maxwell3D::GetTICEntry(u32 tic_index) const {
tic_entry.header_version == Texture::TICHeaderVersion::Pitch,
"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 g_type = tic_entry.g_type.Value();
auto b_type = tic_entry.b_type.Value();
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp
index 0c3bbc475..e6d6917fa 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp
@@ -586,7 +586,7 @@ bool RasterizerOpenGL::AccelerateDisplay(const Tegra::FramebufferConfig& config,
void RasterizerOpenGL::SamplerInfo::Create() {
sampler.Create();
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
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;
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,
config.border_color_b, config.border_color_a}};
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());
if (!texture.enabled) {
- state.texture_units[current_bindpoint].texture_2d = 0;
+ state.texture_units[current_bindpoint].texture = 0;
continue;
}
texture_samplers[current_bindpoint].SyncWithConfig(texture.tsc);
Surface surface = res_cache.GetTextureSurface(texture);
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 =
MaxwellToGL::SwizzleSource(texture.tic.x_source);
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);
} else {
// 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;
}
}
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h
index 9c30dc0e8..c6bb1516b 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.h
+++ b/src/video_core/renderer_opengl/gl_rasterizer.h
@@ -93,6 +93,7 @@ private:
Tegra::Texture::TextureFilter min_filter;
Tegra::Texture::WrapMode wrap_u;
Tegra::Texture::WrapMode wrap_v;
+ Tegra::Texture::WrapMode wrap_p;
GLvec4 border_color;
};
diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
index f6b2c5a86..360fb0cd5 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
@@ -7,6 +7,7 @@
#include "common/alignment.h"
#include "common/assert.h"
+#include "common/logging/log.h"
#include "common/microprofile.h"
#include "common/scope_exit.h"
#include "core/core.h"
@@ -51,10 +52,12 @@ static VAddr TryGetCpuAddr(Tegra::GPUVAddr gpu_addr) {
params.type = GetFormatType(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.depth = config.tic.Depth();
params.unaligned_height = config.tic.Height();
params.size_in_bytes = params.SizeInBytes();
- params.cache_width = Common::AlignUp(params.width, 16);
- params.cache_height = Common::AlignUp(params.height, 16);
+ params.cache_width = Common::AlignUp(params.width, 8);
+ params.cache_height = Common::AlignUp(params.height, 8);
+ params.target = SurfaceTargetFromTextureType(config.tic.texture_type);
return params;
}
@@ -69,10 +72,12 @@ static VAddr TryGetCpuAddr(Tegra::GPUVAddr gpu_addr) {
params.type = GetFormatType(params.pixel_format);
params.width = config.width;
params.height = config.height;
+ params.depth = 1;
params.unaligned_height = config.height;
params.size_in_bytes = params.SizeInBytes();
- params.cache_width = Common::AlignUp(params.width, 16);
- params.cache_height = Common::AlignUp(params.height, 16);
+ params.cache_width = Common::AlignUp(params.width, 8);
+ params.cache_height = Common::AlignUp(params.height, 8);
+ params.target = SurfaceTarget::Texture2D;
return params;
}
@@ -86,13 +91,14 @@ static VAddr TryGetCpuAddr(Tegra::GPUVAddr gpu_addr) {
params.pixel_format = PixelFormatFromDepthFormat(format);
params.component_type = ComponentTypeFromDepthFormat(format);
params.type = GetFormatType(params.pixel_format);
- params.size_in_bytes = params.SizeInBytes();
params.width = zeta_width;
params.height = zeta_height;
+ params.depth = 1;
params.unaligned_height = zeta_height;
params.size_in_bytes = params.SizeInBytes();
- params.cache_width = Common::AlignUp(params.width, 16);
- params.cache_height = Common::AlignUp(params.height, 16);
+ params.cache_width = Common::AlignUp(params.width, 8);
+ params.cache_height = Common::AlignUp(params.height, 8);
+ params.target = SurfaceTarget::Texture2D;
return params;
}
@@ -166,6 +172,26 @@ static constexpr std::array<FormatTuple, SurfaceParams::MaxPixelFormat> tex_form
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) {
ASSERT(static_cast<size_t>(pixel_format) < tex_format_tuples.size());
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>
-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 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 std::vector<u8> data = Tegra::Texture::UnswizzleTexture(
addr, tile_size, bytes_per_pixel, stride, height, block_height);
- const size_t size_to_copy{std::min(gl_buffer.size(), data.size())};
- gl_buffer.assign(data.begin(), data.begin() + size_to_copy);
+ const size_t size_to_copy{std::min(gl_buffer_size, data.size())};
+ memcpy(gl_buffer, data.data(), size_to_copy);
} else {
// 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
LOG_WARNING(Render_OpenGL, "need to use correct swizzle/GOB parameters!");
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>
morton_to_gl_fns = {
// clang-format off
@@ -298,7 +325,7 @@ static constexpr std::array<void (*)(u32, u32, u32, std::vector<u8>&, VAddr),
// 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>
gl_to_morton_fns = {
// clang-format off
@@ -357,33 +384,6 @@ static constexpr std::array<void (*)(u32, u32, u32, std::vector<u8>&, VAddr),
// 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,
const MathUtil::Rectangle<u32>& dst_rect, SurfaceType type,
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;
}
-CachedSurface::CachedSurface(const SurfaceParams& params) : params(params) {
+CachedSurface::CachedSurface(const SurfaceParams& params)
+ : params(params), gl_target(SurfaceTargetToGL(params.target)) {
texture.Create();
const auto& rect{params.GetRect()};
- AllocateSurfaceTexture(texture.handle,
- GetFormatTuple(params.pixel_format, params.component_type),
- rect.GetWidth(), rect.GetHeight());
+
+ // Keep track of previous texture bindings
+ 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) {
@@ -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));
void CachedSurface::LoadGLBuffer() {
ASSERT(params.type != SurfaceType::Fill);
@@ -545,13 +572,24 @@ void CachedSurface::LoadGLBuffer() {
MICROPROFILE_SCOPE(OpenGL_SurfaceLoad);
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)](
- 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 {
- 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);
}
@@ -560,23 +598,7 @@ void CachedSurface::LoadGLBuffer() {
MICROPROFILE_DEFINE(OpenGL_SurfaceFlush, "OpenGL", "Surface Flush", MP_RGB(128, 192, 64));
void CachedSurface::FlushGLBuffer() {
- u8* const dst_buffer = Memory::GetPointer(params.addr);
-
- 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);
- }
+ ASSERT_MSG(false, "Unimplemented");
}
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);
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()};
@@ -600,8 +622,13 @@ void CachedSurface::UploadGLTexture(GLuint read_fb_handle, GLuint draw_fb_handle
GLuint target_tex = texture.handle;
OpenGLState cur_state = OpenGLState::GetCurState();
- GLuint old_tex = cur_state.texture_units[0].texture_2d;
- cur_state.texture_units[0].texture_2d = target_tex;
+ 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 = target_tex;
+ cur_state.texture_units[0].target = SurfaceTargetToGL(params.target);
cur_state.Apply();
// 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);
if (tuple.compressed) {
- 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]);
+ switch (params.target) {
+ case SurfaceParams::SurfaceTarget::Texture2D:
+ glCompressedTexImage2D(
+ 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 {
- 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);
-
- 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);
+ switch (params.target) {
+ 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]);
+ }
}
- 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);
+ glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
}
RasterizerCacheOpenGL::RasterizerCacheOpenGL() {
read_framebuffer.Create();
draw_framebuffer.Create();
+ copy_pbo.Create();
}
Surface RasterizerCacheOpenGL::GetTextureSurface(const Tegra::Texture::FullTextureInfo& config) {
@@ -748,7 +769,6 @@ void RasterizerCacheOpenGL::LoadSurface(const Surface& surface) {
}
void RasterizerCacheOpenGL::FlushSurface(const Surface& surface) {
- surface->DownloadGLTexture(read_framebuffer.handle, draw_framebuffer.handle);
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 (params.pixel_format == new_params.pixel_format) {
BlitTextures(surface->Texture().handle, params.GetRect(), new_surface->Texture().handle,
- new_surface->GetSurfaceParams().GetRect(), params.type,
- read_framebuffer.handle, draw_framebuffer.handle);
+ params.GetRect(), params.type, read_framebuffer.handle,
+ draw_framebuffer.handle);
return new_surface;
}
@@ -821,12 +841,7 @@ Surface RasterizerCacheOpenGL::RecreateSurface(const Surface& surface,
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
- // one using the new format.
- OGLBuffer pbo;
- pbo.Create();
-
- glBindBuffer(GL_PIXEL_PACK_BUFFER, pbo.handle);
+ glBindBuffer(GL_PIXEL_PACK_BUFFER, copy_pbo.handle);
glBufferData(GL_PIXEL_PACK_BUFFER, buffer_size, nullptr, GL_STREAM_DRAW_ARB);
if (source_format.compressed) {
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
// 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.
- LOG_CRITICAL(HW_GPU, "Trying to upload extra texture data from the CPU during "
- "reinterpretation but the texture is tiled.");
+ LOG_DEBUG(HW_GPU, "Trying to upload extra texture data from the CPU during "
+ "reinterpretation but the texture is tiled.");
}
size_t remaining_size = new_params.SizeInBytes() - params.SizeInBytes();
std::vector<u8> data(remaining_size);
@@ -859,21 +874,38 @@ Surface RasterizerCacheOpenGL::RecreateSurface(const Surface& surface,
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) {
- glCompressedTexSubImage2D(
- GL_TEXTURE_2D, 0, 0, 0, static_cast<GLsizei>(dest_rect.GetWidth()),
- static_cast<GLsizei>(dest_rect.GetHeight()), dest_format.format,
- static_cast<GLsizei>(new_params.SizeInBytes()), nullptr);
+ LOG_CRITICAL(HW_GPU, "Compressed copy is unimplemented!");
+ UNREACHABLE();
} else {
- 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);
+ switch (new_params.target) {
+ case SurfaceParams::SurfaceTarget::Texture1D:
+ glTextureSubImage1D(new_surface->Texture().handle, 0, 0,
+ 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);
-
- pbo.Release();
}
return new_surface;
diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.h b/src/video_core/renderer_opengl/gl_rasterizer_cache.h
index aad75f200..8312b2c7a 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer_cache.h
+++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.h
@@ -109,6 +109,33 @@ struct SurfaceParams {
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
* "compressed width" and "compressed height", not the overall compression factor of a
@@ -635,7 +662,7 @@ struct SurfaceParams {
ASSERT(width % compression_factor == 0);
ASSERT(height % compression_factor == 0);
return (width / compression_factor) * (height / compression_factor) *
- GetFormatBpp(pixel_format) / CHAR_BIT;
+ GetFormatBpp(pixel_format) * depth / CHAR_BIT;
}
/// Creates SurfaceParams from a texture configuration
@@ -664,8 +691,10 @@ struct SurfaceParams {
SurfaceType type;
u32 width;
u32 height;
+ u32 depth;
u32 unaligned_height;
size_t size_in_bytes;
+ SurfaceTarget target;
// Parameters used for caching only
u32 cache_width;
@@ -709,6 +738,10 @@ public:
return texture;
}
+ GLenum Target() const {
+ return gl_target;
+ }
+
static constexpr unsigned int GetGLBytesPerPixel(SurfaceParams::PixelFormat format) {
if (format == SurfaceParams::PixelFormat::Invalid)
return 0;
@@ -724,14 +757,14 @@ public:
void LoadGLBuffer();
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 DownloadGLTexture(GLuint read_fb_handle, GLuint draw_fb_handle);
private:
OGLTexture texture;
std::vector<u8> gl_buffer;
SurfaceParams params;
+ GLenum gl_target;
};
class RasterizerCacheOpenGL final : public RasterizerCache<Surface> {
@@ -774,6 +807,10 @@ private:
OGLFramebuffer read_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
diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
index 841647ebe..172ba8335 100644
--- a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
@@ -443,13 +443,12 @@ public:
}
declarations.AddNewLine();
- // Append the sampler2D array for the used textures.
- const size_t num_samplers = used_samplers.size();
- if (num_samplers > 0) {
- declarations.AddLine("uniform sampler2D " + SamplerEntry::GetArrayName(stage) + '[' +
- std::to_string(num_samplers) + "];");
- declarations.AddNewLine();
+ const auto& samplers = GetSamplers();
+ for (const auto& sampler : samplers) {
+ declarations.AddLine("uniform " + sampler.GetTypeString() + ' ' + sampler.GetName() +
+ ';');
}
+ declarations.AddNewLine();
}
/// Returns a list of constant buffer declarations
@@ -461,13 +460,14 @@ public:
}
/// Returns a list of samplers used in the shader
- std::vector<SamplerEntry> GetSamplers() const {
+ const std::vector<SamplerEntry>& GetSamplers() const {
return used_samplers;
}
/// Returns the GLSL sampler used for the input shader sampler, and creates a new one if
/// 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());
// If this sampler has already been used, return the existing mapping.
@@ -476,12 +476,13 @@ public:
[&](const SamplerEntry& entry) { return entry.GetOffset() == offset; });
if (itr != used_samplers.end()) {
+ ASSERT(itr->GetType() == type && itr->IsArray() == is_array);
return itr->GetName();
}
// Otherwise create a new mapping for this sampler
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);
return entry.GetName();
}
@@ -722,8 +723,8 @@ private:
}
/// Generates code representing a texture sampler.
- std::string GetSampler(const Sampler& sampler) {
- return regs.AccessSampler(sampler);
+ std::string GetSampler(const Sampler& sampler, Tegra::Shader::TextureType type, bool is_array) {
+ return regs.AccessSampler(sampler, type, is_array);
}
/**
@@ -1753,10 +1754,35 @@ private:
break;
}
case OpCode::Id::TEX: {
- const std::string op_a = regs.GetRegisterAsFloat(instr.gpr8);
- const std::string op_b = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1);
- const std::string sampler = GetSampler(instr.sampler);
- const std::string coord = "vec2 coords = vec2(" + op_a + ", " + op_b + ");";
+ ASSERT_MSG(instr.tex.array == 0, "TEX arrays unimplemented");
+ Tegra::Shader::TextureType texture_type{instr.tex.texture_type};
+ std::string coord;
+
+ 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
// overwriting them in case they are used as outputs of the texs instruction.
shader.AddLine("{");
@@ -1778,20 +1804,65 @@ private:
break;
}
case OpCode::Id::TEXS: {
- const std::string op_a = regs.GetRegisterAsFloat(instr.gpr8);
- const std::string op_b = regs.GetRegisterAsFloat(instr.gpr20);
- const std::string sampler = GetSampler(instr.sampler);
- const std::string coord = "vec2 coords = vec2(" + op_a + ", " + op_b + ");";
+ std::string coord;
+ Tegra::Shader::TextureType texture_type{instr.texs.GetTextureType()};
+ bool is_array{instr.texs.IsArrayTexture()};
+
+ 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)";
WriteTexsInstruction(instr, coord, texture);
break;
}
case OpCode::Id::TLDS: {
- const std::string op_a = regs.GetRegisterAsInteger(instr.gpr8);
- const std::string op_b = regs.GetRegisterAsInteger(instr.gpr20);
- const std::string sampler = GetSampler(instr.sampler);
- const std::string coord = "ivec2 coords = ivec2(" + op_a + ", " + op_b + ");";
+ ASSERT(instr.tlds.GetTextureType() == Tegra::Shader::TextureType::Texture2D);
+ ASSERT(instr.tlds.IsArrayTexture() == false);
+ std::string coord;
+
+ 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)";
WriteTexsInstruction(instr, coord, texture);
break;
@@ -1799,7 +1870,7 @@ private:
case OpCode::Id::TLD4: {
ASSERT(instr.tld4.texture_type == Tegra::Shader::TextureType::Texture2D);
ASSERT(instr.tld4.array == 0);
- std::string coord{};
+ std::string coord;
switch (instr.tld4.texture_type) {
case Tegra::Shader::TextureType::Texture2D: {
@@ -1814,7 +1885,8 @@ private:
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
// overwriting them in case they are used as outputs of the texs instruction.
shader.AddLine("{");
@@ -1840,7 +1912,8 @@ private:
const std::string op_a = regs.GetRegisterAsFloat(instr.gpr8);
const std::string op_b = regs.GetRegisterAsFloat(instr.gpr20);
// 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 texture = "textureGather(" + sampler + ", coords, " +
std::to_string(instr.tld4s.component) + ')';
diff --git a/src/video_core/renderer_opengl/gl_shader_gen.h b/src/video_core/renderer_opengl/gl_shader_gen.h
index cbb2090ea..a43e2997b 100644
--- a/src/video_core/renderer_opengl/gl_shader_gen.h
+++ b/src/video_core/renderer_opengl/gl_shader_gen.h
@@ -9,6 +9,7 @@
#include <vector>
#include "common/common_types.h"
+#include "video_core/engines/shader_bytecode.h"
namespace OpenGL::GLShader {
@@ -73,8 +74,9 @@ class SamplerEntry {
using Maxwell = Tegra::Engines::Maxwell3D::Regs;
public:
- SamplerEntry(Maxwell::ShaderStage stage, size_t offset, size_t index)
- : offset(offset), stage(stage), sampler_index(index) {}
+ SamplerEntry(Maxwell::ShaderStage stage, size_t offset, size_t 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 {
return offset;
@@ -89,8 +91,41 @@ public:
}
std::string GetName() const {
- return std::string(TextureSamplerNames[static_cast<size_t>(stage)]) + '[' +
- std::to_string(sampler_index) + ']';
+ return std::string(TextureSamplerNames[static_cast<size_t>(stage)]) + '_' +
+ 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 {
@@ -105,11 +140,14 @@ private:
static constexpr std::array<const char*, Maxwell::MaxShaderStage> TextureSamplerNames = {
"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
/// instruction.
size_t offset;
- Maxwell::ShaderStage stage; ///< Shader stage where this sampler was used.
- size_t sampler_index; ///< Value used to index into the generated GLSL sampler array.
+ Maxwell::ShaderStage stage; ///< Shader stage where this sampler was used.
+ 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 {
diff --git a/src/video_core/renderer_opengl/gl_state.cpp b/src/video_core/renderer_opengl/gl_state.cpp
index 60a4defd1..6f70deb96 100644
--- a/src/video_core/renderer_opengl/gl_state.cpp
+++ b/src/video_core/renderer_opengl/gl_state.cpp
@@ -200,9 +200,9 @@ void OpenGLState::Apply() const {
const auto& texture_unit = 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());
- glBindTexture(GL_TEXTURE_2D, texture_unit.texture_2d);
+ glBindTexture(texture_unit.target, texture_unit.texture);
}
if (texture_unit.sampler != cur_state_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) {
std::array<GLint, 4> mask = {texture_unit.swizzle.r, texture_unit.swizzle.g,
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) {
for (auto& unit : texture_units) {
- if (unit.texture_2d == handle) {
+ if (unit.texture == handle) {
unit.Unbind();
}
}
diff --git a/src/video_core/renderer_opengl/gl_state.h b/src/video_core/renderer_opengl/gl_state.h
index 46e96a97d..e3e24b9e7 100644
--- a/src/video_core/renderer_opengl/gl_state.h
+++ b/src/video_core/renderer_opengl/gl_state.h
@@ -94,8 +94,9 @@ public:
// 3 texture units - one for each that is used in PICA fragment shader emulation
struct TextureUnit {
- GLuint texture_2d; // GL_TEXTURE_BINDING_2D
- GLuint sampler; // GL_SAMPLER_BINDING
+ GLuint texture; // GL_TEXTURE_BINDING_2D
+ GLuint sampler; // GL_SAMPLER_BINDING
+ GLenum target;
struct {
GLint r; // GL_TEXTURE_SWIZZLE_R
GLint g; // GL_TEXTURE_SWIZZLE_G
@@ -104,7 +105,7 @@ public:
} swizzle;
void Unbind() {
- texture_2d = 0;
+ texture = 0;
swizzle.r = GL_RED;
swizzle.g = GL_GREEN;
swizzle.b = GL_BLUE;
@@ -114,6 +115,7 @@ public:
void Reset() {
Unbind();
sampler = 0;
+ target = GL_TEXTURE_2D;
}
};
std::array<TextureUnit, 32> texture_units;
diff --git a/src/video_core/renderer_opengl/renderer_opengl.cpp b/src/video_core/renderer_opengl/renderer_opengl.cpp
index 411a73d50..ccff3e342 100644
--- a/src/video_core/renderer_opengl/renderer_opengl.cpp
+++ b/src/video_core/renderer_opengl/renderer_opengl.cpp
@@ -177,7 +177,7 @@ void RendererOpenGL::LoadFBToScreenInfo(const Tegra::FramebufferConfig& framebuf
Memory::GetPointer(framebuffer_addr),
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();
glActiveTexture(GL_TEXTURE0);
@@ -194,7 +194,7 @@ void RendererOpenGL::LoadFBToScreenInfo(const Tegra::FramebufferConfig& framebuf
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
- state.texture_units[0].texture_2d = 0;
+ state.texture_units[0].texture = 0;
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,
const TextureInfo& texture) {
- state.texture_units[0].texture_2d = texture.resource.handle;
+ state.texture_units[0].texture = texture.resource.handle;
state.Apply();
glActiveTexture(GL_TEXTURE0);
@@ -214,7 +214,7 @@ void RendererOpenGL::LoadColorToActiveGLTexture(u8 color_r, u8 color_g, u8 color
// Update existing texture
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();
}
@@ -260,7 +260,7 @@ void RendererOpenGL::InitOpenGLObjects() {
// Allocation of storage is deferred until the first frame, when we
// 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();
glActiveTexture(GL_TEXTURE0);
@@ -272,7 +272,7 @@ void RendererOpenGL::InitOpenGLObjects() {
screen_info.display_texture = screen_info.texture.resource.handle;
- state.texture_units[0].texture_2d = 0;
+ state.texture_units[0].texture = 0;
state.Apply();
// Clear screen to black
@@ -305,14 +305,14 @@ void RendererOpenGL::ConfigureFramebufferTexture(TextureInfo& texture,
UNREACHABLE();
}
- state.texture_units[0].texture_2d = texture.resource.handle;
+ state.texture_units[0].texture = texture.resource.handle;
state.Apply();
glActiveTexture(GL_TEXTURE0);
glTexImage2D(GL_TEXTURE_2D, 0, internal_format, texture.width, texture.height, 0,
texture.gl_format, texture.gl_type, nullptr);
- state.texture_units[0].texture_2d = 0;
+ state.texture_units[0].texture = 0;
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),
}};
- 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.Apply();
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(vertices), vertices.data());
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
- state.texture_units[0].texture_2d = 0;
+ state.texture_units[0].texture = 0;
state.Apply();
}
diff --git a/src/video_core/textures/texture.h b/src/video_core/textures/texture.h
index c6bd2f4b9..c2fb824b2 100644
--- a/src/video_core/textures/texture.h
+++ b/src/video_core/textures/texture.h
@@ -170,8 +170,12 @@ struct TICEntry {
BitField<0, 16, u32> width_minus_1;
BitField<23, 4, TextureType> texture_type;
};
- u16 height_minus_1;
- INSERT_PADDING_BYTES(10);
+ union {
+ BitField<0, 16, u32> height_minus_1;
+ BitField<16, 15, u32> depth_minus_1;
+ };
+
+ INSERT_PADDING_BYTES(8);
GPUVAddr Address() const {
return static_cast<GPUVAddr>((static_cast<GPUVAddr>(address_high) << 32) | address_low);
@@ -192,6 +196,10 @@ struct TICEntry {
return height_minus_1 + 1;
}
+ u32 Depth() const {
+ return depth_minus_1 + 1;
+ }
+
u32 BlockHeight() const {
ASSERT(header_version == TICHeaderVersion::BlockLinear ||
header_version == TICHeaderVersion::BlockLinearColorKey);