diff options
Diffstat (limited to '')
| -rw-r--r-- | src/video_core/engines/maxwell_3d.cpp | 4 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_rasterizer.cpp | 16 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_rasterizer.h | 1 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_rasterizer_cache.cpp | 364 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_rasterizer_cache.h | 43 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_shader_decompiler.cpp | 125 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_shader_gen.h | 50 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_state.cpp | 8 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_state.h | 8 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/renderer_opengl.cpp | 20 | ||||
| -rw-r--r-- | src/video_core/textures/texture.h | 12 |
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 { | |||
| 293 | tic_entry.header_version == Texture::TICHeaderVersion::Pitch, | 293 | tic_entry.header_version == Texture::TICHeaderVersion::Pitch, |
| 294 | "TIC versions other than BlockLinear or Pitch are unimplemented"); | 294 | "TIC versions other than BlockLinear or Pitch are unimplemented"); |
| 295 | 295 | ||
| 296 | ASSERT_MSG((tic_entry.texture_type == Texture::TextureType::Texture2D) || | ||
| 297 | (tic_entry.texture_type == Texture::TextureType::Texture2DNoMipmap), | ||
| 298 | "Texture types other than Texture2D are unimplemented"); | ||
| 299 | |||
| 300 | auto r_type = tic_entry.r_type.Value(); | 296 | auto r_type = tic_entry.r_type.Value(); |
| 301 | auto g_type = tic_entry.g_type.Value(); | 297 | auto g_type = tic_entry.g_type.Value(); |
| 302 | auto b_type = tic_entry.b_type.Value(); | 298 | 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, | |||
| 586 | void RasterizerOpenGL::SamplerInfo::Create() { | 586 | void RasterizerOpenGL::SamplerInfo::Create() { |
| 587 | sampler.Create(); | 587 | sampler.Create(); |
| 588 | mag_filter = min_filter = Tegra::Texture::TextureFilter::Linear; | 588 | mag_filter = min_filter = Tegra::Texture::TextureFilter::Linear; |
| 589 | wrap_u = wrap_v = Tegra::Texture::WrapMode::Wrap; | 589 | wrap_u = wrap_v = wrap_p = Tegra::Texture::WrapMode::Wrap; |
| 590 | 590 | ||
| 591 | // default is GL_LINEAR_MIPMAP_LINEAR | 591 | // default is GL_LINEAR_MIPMAP_LINEAR |
| 592 | glSamplerParameteri(sampler.handle, GL_TEXTURE_MIN_FILTER, GL_LINEAR); | 592 | glSamplerParameteri(sampler.handle, GL_TEXTURE_MIN_FILTER, GL_LINEAR); |
| @@ -613,8 +613,13 @@ void RasterizerOpenGL::SamplerInfo::SyncWithConfig(const Tegra::Texture::TSCEntr | |||
| 613 | wrap_v = config.wrap_v; | 613 | wrap_v = config.wrap_v; |
| 614 | glSamplerParameteri(s, GL_TEXTURE_WRAP_T, MaxwellToGL::WrapMode(wrap_v)); | 614 | glSamplerParameteri(s, GL_TEXTURE_WRAP_T, MaxwellToGL::WrapMode(wrap_v)); |
| 615 | } | 615 | } |
| 616 | if (wrap_p != config.wrap_p) { | ||
| 617 | wrap_p = config.wrap_p; | ||
| 618 | glSamplerParameteri(s, GL_TEXTURE_WRAP_R, MaxwellToGL::WrapMode(wrap_p)); | ||
| 619 | } | ||
| 616 | 620 | ||
| 617 | if (wrap_u == Tegra::Texture::WrapMode::Border || wrap_v == Tegra::Texture::WrapMode::Border) { | 621 | if (wrap_u == Tegra::Texture::WrapMode::Border || wrap_v == Tegra::Texture::WrapMode::Border || |
| 622 | wrap_p == Tegra::Texture::WrapMode::Border) { | ||
| 618 | const GLvec4 new_border_color = {{config.border_color_r, config.border_color_g, | 623 | const GLvec4 new_border_color = {{config.border_color_r, config.border_color_g, |
| 619 | config.border_color_b, config.border_color_a}}; | 624 | config.border_color_b, config.border_color_a}}; |
| 620 | if (border_color != new_border_color) { | 625 | if (border_color != new_border_color) { |
| @@ -698,14 +703,15 @@ u32 RasterizerOpenGL::SetupTextures(Maxwell::ShaderStage stage, Shader& shader, | |||
| 698 | const auto texture = maxwell3d.GetStageTexture(entry.GetStage(), entry.GetOffset()); | 703 | const auto texture = maxwell3d.GetStageTexture(entry.GetStage(), entry.GetOffset()); |
| 699 | 704 | ||
| 700 | if (!texture.enabled) { | 705 | if (!texture.enabled) { |
| 701 | state.texture_units[current_bindpoint].texture_2d = 0; | 706 | state.texture_units[current_bindpoint].texture = 0; |
| 702 | continue; | 707 | continue; |
| 703 | } | 708 | } |
| 704 | 709 | ||
| 705 | texture_samplers[current_bindpoint].SyncWithConfig(texture.tsc); | 710 | texture_samplers[current_bindpoint].SyncWithConfig(texture.tsc); |
| 706 | Surface surface = res_cache.GetTextureSurface(texture); | 711 | Surface surface = res_cache.GetTextureSurface(texture); |
| 707 | if (surface != nullptr) { | 712 | if (surface != nullptr) { |
| 708 | state.texture_units[current_bindpoint].texture_2d = surface->Texture().handle; | 713 | state.texture_units[current_bindpoint].texture = surface->Texture().handle; |
| 714 | state.texture_units[current_bindpoint].target = surface->Target(); | ||
| 709 | state.texture_units[current_bindpoint].swizzle.r = | 715 | state.texture_units[current_bindpoint].swizzle.r = |
| 710 | MaxwellToGL::SwizzleSource(texture.tic.x_source); | 716 | MaxwellToGL::SwizzleSource(texture.tic.x_source); |
| 711 | state.texture_units[current_bindpoint].swizzle.g = | 717 | state.texture_units[current_bindpoint].swizzle.g = |
| @@ -716,7 +722,7 @@ u32 RasterizerOpenGL::SetupTextures(Maxwell::ShaderStage stage, Shader& shader, | |||
| 716 | MaxwellToGL::SwizzleSource(texture.tic.w_source); | 722 | MaxwellToGL::SwizzleSource(texture.tic.w_source); |
| 717 | } else { | 723 | } else { |
| 718 | // Can occur when texture addr is null or its memory is unmapped/invalid | 724 | // Can occur when texture addr is null or its memory is unmapped/invalid |
| 719 | state.texture_units[current_bindpoint].texture_2d = 0; | 725 | state.texture_units[current_bindpoint].texture = 0; |
| 720 | } | 726 | } |
| 721 | } | 727 | } |
| 722 | 728 | ||
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: | |||
| 93 | Tegra::Texture::TextureFilter min_filter; | 93 | Tegra::Texture::TextureFilter min_filter; |
| 94 | Tegra::Texture::WrapMode wrap_u; | 94 | Tegra::Texture::WrapMode wrap_u; |
| 95 | Tegra::Texture::WrapMode wrap_v; | 95 | Tegra::Texture::WrapMode wrap_v; |
| 96 | Tegra::Texture::WrapMode wrap_p; | ||
| 96 | GLvec4 border_color; | 97 | GLvec4 border_color; |
| 97 | }; | 98 | }; |
| 98 | 99 | ||
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 @@ | |||
| 7 | 7 | ||
| 8 | #include "common/alignment.h" | 8 | #include "common/alignment.h" |
| 9 | #include "common/assert.h" | 9 | #include "common/assert.h" |
| 10 | #include "common/logging/log.h" | ||
| 10 | #include "common/microprofile.h" | 11 | #include "common/microprofile.h" |
| 11 | #include "common/scope_exit.h" | 12 | #include "common/scope_exit.h" |
| 12 | #include "core/core.h" | 13 | #include "core/core.h" |
| @@ -51,10 +52,12 @@ static VAddr TryGetCpuAddr(Tegra::GPUVAddr gpu_addr) { | |||
| 51 | params.type = GetFormatType(params.pixel_format); | 52 | params.type = GetFormatType(params.pixel_format); |
| 52 | params.width = Common::AlignUp(config.tic.Width(), GetCompressionFactor(params.pixel_format)); | 53 | params.width = Common::AlignUp(config.tic.Width(), GetCompressionFactor(params.pixel_format)); |
| 53 | params.height = Common::AlignUp(config.tic.Height(), GetCompressionFactor(params.pixel_format)); | 54 | params.height = Common::AlignUp(config.tic.Height(), GetCompressionFactor(params.pixel_format)); |
| 55 | params.depth = config.tic.Depth(); | ||
| 54 | params.unaligned_height = config.tic.Height(); | 56 | params.unaligned_height = config.tic.Height(); |
| 55 | params.size_in_bytes = params.SizeInBytes(); | 57 | params.size_in_bytes = params.SizeInBytes(); |
| 56 | params.cache_width = Common::AlignUp(params.width, 16); | 58 | params.cache_width = Common::AlignUp(params.width, 8); |
| 57 | params.cache_height = Common::AlignUp(params.height, 16); | 59 | params.cache_height = Common::AlignUp(params.height, 8); |
| 60 | params.target = SurfaceTargetFromTextureType(config.tic.texture_type); | ||
| 58 | return params; | 61 | return params; |
| 59 | } | 62 | } |
| 60 | 63 | ||
| @@ -69,10 +72,12 @@ static VAddr TryGetCpuAddr(Tegra::GPUVAddr gpu_addr) { | |||
| 69 | params.type = GetFormatType(params.pixel_format); | 72 | params.type = GetFormatType(params.pixel_format); |
| 70 | params.width = config.width; | 73 | params.width = config.width; |
| 71 | params.height = config.height; | 74 | params.height = config.height; |
| 75 | params.depth = 1; | ||
| 72 | params.unaligned_height = config.height; | 76 | params.unaligned_height = config.height; |
| 73 | params.size_in_bytes = params.SizeInBytes(); | 77 | params.size_in_bytes = params.SizeInBytes(); |
| 74 | params.cache_width = Common::AlignUp(params.width, 16); | 78 | params.cache_width = Common::AlignUp(params.width, 8); |
| 75 | params.cache_height = Common::AlignUp(params.height, 16); | 79 | params.cache_height = Common::AlignUp(params.height, 8); |
| 80 | params.target = SurfaceTarget::Texture2D; | ||
| 76 | return params; | 81 | return params; |
| 77 | } | 82 | } |
| 78 | 83 | ||
| @@ -86,13 +91,14 @@ static VAddr TryGetCpuAddr(Tegra::GPUVAddr gpu_addr) { | |||
| 86 | params.pixel_format = PixelFormatFromDepthFormat(format); | 91 | params.pixel_format = PixelFormatFromDepthFormat(format); |
| 87 | params.component_type = ComponentTypeFromDepthFormat(format); | 92 | params.component_type = ComponentTypeFromDepthFormat(format); |
| 88 | params.type = GetFormatType(params.pixel_format); | 93 | params.type = GetFormatType(params.pixel_format); |
| 89 | params.size_in_bytes = params.SizeInBytes(); | ||
| 90 | params.width = zeta_width; | 94 | params.width = zeta_width; |
| 91 | params.height = zeta_height; | 95 | params.height = zeta_height; |
| 96 | params.depth = 1; | ||
| 92 | params.unaligned_height = zeta_height; | 97 | params.unaligned_height = zeta_height; |
| 93 | params.size_in_bytes = params.SizeInBytes(); | 98 | params.size_in_bytes = params.SizeInBytes(); |
| 94 | params.cache_width = Common::AlignUp(params.width, 16); | 99 | params.cache_width = Common::AlignUp(params.width, 8); |
| 95 | params.cache_height = Common::AlignUp(params.height, 16); | 100 | params.cache_height = Common::AlignUp(params.height, 8); |
| 101 | params.target = SurfaceTarget::Texture2D; | ||
| 96 | return params; | 102 | return params; |
| 97 | } | 103 | } |
| 98 | 104 | ||
| @@ -166,6 +172,26 @@ static constexpr std::array<FormatTuple, SurfaceParams::MaxPixelFormat> tex_form | |||
| 166 | ComponentType::Float, false}, // Z32FS8 | 172 | ComponentType::Float, false}, // Z32FS8 |
| 167 | }}; | 173 | }}; |
| 168 | 174 | ||
| 175 | static GLenum SurfaceTargetToGL(SurfaceParams::SurfaceTarget target) { | ||
| 176 | switch (target) { | ||
| 177 | case SurfaceParams::SurfaceTarget::Texture1D: | ||
| 178 | return GL_TEXTURE_1D; | ||
| 179 | case SurfaceParams::SurfaceTarget::Texture2D: | ||
| 180 | return GL_TEXTURE_2D; | ||
| 181 | case SurfaceParams::SurfaceTarget::Texture3D: | ||
| 182 | return GL_TEXTURE_3D; | ||
| 183 | case SurfaceParams::SurfaceTarget::Texture1DArray: | ||
| 184 | return GL_TEXTURE_1D_ARRAY; | ||
| 185 | case SurfaceParams::SurfaceTarget::Texture2DArray: | ||
| 186 | return GL_TEXTURE_2D_ARRAY; | ||
| 187 | case SurfaceParams::SurfaceTarget::TextureCubemap: | ||
| 188 | return GL_TEXTURE_CUBE_MAP; | ||
| 189 | } | ||
| 190 | LOG_CRITICAL(Render_OpenGL, "Unimplemented texture target={}", static_cast<u32>(target)); | ||
| 191 | UNREACHABLE(); | ||
| 192 | return {}; | ||
| 193 | } | ||
| 194 | |||
| 169 | static const FormatTuple& GetFormatTuple(PixelFormat pixel_format, ComponentType component_type) { | 195 | static const FormatTuple& GetFormatTuple(PixelFormat pixel_format, ComponentType component_type) { |
| 170 | ASSERT(static_cast<size_t>(pixel_format) < tex_format_tuples.size()); | 196 | ASSERT(static_cast<size_t>(pixel_format) < tex_format_tuples.size()); |
| 171 | auto& format = tex_format_tuples[static_cast<unsigned int>(pixel_format)]; | 197 | auto& format = tex_format_tuples[static_cast<unsigned int>(pixel_format)]; |
| @@ -220,7 +246,8 @@ static bool IsFormatBCn(PixelFormat format) { | |||
| 220 | } | 246 | } |
| 221 | 247 | ||
| 222 | template <bool morton_to_gl, PixelFormat format> | 248 | template <bool morton_to_gl, PixelFormat format> |
| 223 | void MortonCopy(u32 stride, u32 block_height, u32 height, std::vector<u8>& gl_buffer, VAddr addr) { | 249 | void MortonCopy(u32 stride, u32 block_height, u32 height, u8* gl_buffer, size_t gl_buffer_size, |
| 250 | VAddr addr) { | ||
| 224 | constexpr u32 bytes_per_pixel = SurfaceParams::GetFormatBpp(format) / CHAR_BIT; | 251 | constexpr u32 bytes_per_pixel = SurfaceParams::GetFormatBpp(format) / CHAR_BIT; |
| 225 | constexpr u32 gl_bytes_per_pixel = CachedSurface::GetGLBytesPerPixel(format); | 252 | constexpr u32 gl_bytes_per_pixel = CachedSurface::GetGLBytesPerPixel(format); |
| 226 | 253 | ||
| @@ -230,18 +257,18 @@ void MortonCopy(u32 stride, u32 block_height, u32 height, std::vector<u8>& gl_bu | |||
| 230 | const u32 tile_size{IsFormatBCn(format) ? 4U : 1U}; | 257 | const u32 tile_size{IsFormatBCn(format) ? 4U : 1U}; |
| 231 | const std::vector<u8> data = Tegra::Texture::UnswizzleTexture( | 258 | const std::vector<u8> data = Tegra::Texture::UnswizzleTexture( |
| 232 | addr, tile_size, bytes_per_pixel, stride, height, block_height); | 259 | addr, tile_size, bytes_per_pixel, stride, height, block_height); |
| 233 | const size_t size_to_copy{std::min(gl_buffer.size(), data.size())}; | 260 | const size_t size_to_copy{std::min(gl_buffer_size, data.size())}; |
| 234 | gl_buffer.assign(data.begin(), data.begin() + size_to_copy); | 261 | memcpy(gl_buffer, data.data(), size_to_copy); |
| 235 | } else { | 262 | } else { |
| 236 | // TODO(bunnei): Assumes the default rendering GOB size of 16 (128 lines). We should | 263 | // TODO(bunnei): Assumes the default rendering GOB size of 16 (128 lines). We should |
| 237 | // check the configuration for this and perform more generic un/swizzle | 264 | // check the configuration for this and perform more generic un/swizzle |
| 238 | LOG_WARNING(Render_OpenGL, "need to use correct swizzle/GOB parameters!"); | 265 | LOG_WARNING(Render_OpenGL, "need to use correct swizzle/GOB parameters!"); |
| 239 | VideoCore::MortonCopyPixels128(stride, height, bytes_per_pixel, gl_bytes_per_pixel, | 266 | VideoCore::MortonCopyPixels128(stride, height, bytes_per_pixel, gl_bytes_per_pixel, |
| 240 | Memory::GetPointer(addr), gl_buffer.data(), morton_to_gl); | 267 | Memory::GetPointer(addr), gl_buffer, morton_to_gl); |
| 241 | } | 268 | } |
| 242 | } | 269 | } |
| 243 | 270 | ||
| 244 | static constexpr std::array<void (*)(u32, u32, u32, std::vector<u8>&, VAddr), | 271 | static constexpr std::array<void (*)(u32, u32, u32, u8*, size_t, VAddr), |
| 245 | SurfaceParams::MaxPixelFormat> | 272 | SurfaceParams::MaxPixelFormat> |
| 246 | morton_to_gl_fns = { | 273 | morton_to_gl_fns = { |
| 247 | // clang-format off | 274 | // clang-format off |
| @@ -298,7 +325,7 @@ static constexpr std::array<void (*)(u32, u32, u32, std::vector<u8>&, VAddr), | |||
| 298 | // clang-format on | 325 | // clang-format on |
| 299 | }; | 326 | }; |
| 300 | 327 | ||
| 301 | static constexpr std::array<void (*)(u32, u32, u32, std::vector<u8>&, VAddr), | 328 | static constexpr std::array<void (*)(u32, u32, u32, u8*, size_t, VAddr), |
| 302 | SurfaceParams::MaxPixelFormat> | 329 | SurfaceParams::MaxPixelFormat> |
| 303 | gl_to_morton_fns = { | 330 | gl_to_morton_fns = { |
| 304 | // clang-format off | 331 | // clang-format off |
| @@ -357,33 +384,6 @@ static constexpr std::array<void (*)(u32, u32, u32, std::vector<u8>&, VAddr), | |||
| 357 | // clang-format on | 384 | // clang-format on |
| 358 | }; | 385 | }; |
| 359 | 386 | ||
| 360 | // Allocate an uninitialized texture of appropriate size and format for the surface | ||
| 361 | static void AllocateSurfaceTexture(GLuint texture, const FormatTuple& format_tuple, u32 width, | ||
| 362 | u32 height) { | ||
| 363 | OpenGLState cur_state = OpenGLState::GetCurState(); | ||
| 364 | |||
| 365 | // Keep track of previous texture bindings | ||
| 366 | GLuint old_tex = cur_state.texture_units[0].texture_2d; | ||
| 367 | cur_state.texture_units[0].texture_2d = texture; | ||
| 368 | cur_state.Apply(); | ||
| 369 | glActiveTexture(GL_TEXTURE0); | ||
| 370 | |||
| 371 | if (!format_tuple.compressed) { | ||
| 372 | // Only pre-create the texture for non-compressed textures. | ||
| 373 | glTexImage2D(GL_TEXTURE_2D, 0, format_tuple.internal_format, width, height, 0, | ||
| 374 | format_tuple.format, format_tuple.type, nullptr); | ||
| 375 | } | ||
| 376 | |||
| 377 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0); | ||
| 378 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); | ||
| 379 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); | ||
| 380 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); | ||
| 381 | |||
| 382 | // Restore previous texture bindings | ||
| 383 | cur_state.texture_units[0].texture_2d = old_tex; | ||
| 384 | cur_state.Apply(); | ||
| 385 | } | ||
| 386 | |||
| 387 | static bool BlitTextures(GLuint src_tex, const MathUtil::Rectangle<u32>& src_rect, GLuint dst_tex, | 387 | static bool BlitTextures(GLuint src_tex, const MathUtil::Rectangle<u32>& src_rect, GLuint dst_tex, |
| 388 | const MathUtil::Rectangle<u32>& dst_rect, SurfaceType type, | 388 | const MathUtil::Rectangle<u32>& dst_rect, SurfaceType type, |
| 389 | GLuint read_fb_handle, GLuint draw_fb_handle) { | 389 | GLuint read_fb_handle, GLuint draw_fb_handle) { |
| @@ -438,12 +438,56 @@ static bool BlitTextures(GLuint src_tex, const MathUtil::Rectangle<u32>& src_rec | |||
| 438 | return true; | 438 | return true; |
| 439 | } | 439 | } |
| 440 | 440 | ||
| 441 | CachedSurface::CachedSurface(const SurfaceParams& params) : params(params) { | 441 | CachedSurface::CachedSurface(const SurfaceParams& params) |
| 442 | : params(params), gl_target(SurfaceTargetToGL(params.target)) { | ||
| 442 | texture.Create(); | 443 | texture.Create(); |
| 443 | const auto& rect{params.GetRect()}; | 444 | const auto& rect{params.GetRect()}; |
| 444 | AllocateSurfaceTexture(texture.handle, | 445 | |
| 445 | GetFormatTuple(params.pixel_format, params.component_type), | 446 | // Keep track of previous texture bindings |
| 446 | rect.GetWidth(), rect.GetHeight()); | 447 | OpenGLState cur_state = OpenGLState::GetCurState(); |
| 448 | const auto& old_tex = cur_state.texture_units[0]; | ||
| 449 | SCOPE_EXIT({ | ||
| 450 | cur_state.texture_units[0] = old_tex; | ||
| 451 | cur_state.Apply(); | ||
| 452 | }); | ||
| 453 | |||
| 454 | cur_state.texture_units[0].texture = texture.handle; | ||
| 455 | cur_state.texture_units[0].target = SurfaceTargetToGL(params.target); | ||
| 456 | cur_state.Apply(); | ||
| 457 | glActiveTexture(GL_TEXTURE0); | ||
| 458 | |||
| 459 | const auto& format_tuple = GetFormatTuple(params.pixel_format, params.component_type); | ||
| 460 | if (!format_tuple.compressed) { | ||
| 461 | // Only pre-create the texture for non-compressed textures. | ||
| 462 | switch (params.target) { | ||
| 463 | case SurfaceParams::SurfaceTarget::Texture1D: | ||
| 464 | glTexImage1D(SurfaceTargetToGL(params.target), 0, format_tuple.internal_format, | ||
| 465 | rect.GetWidth(), 0, format_tuple.format, format_tuple.type, nullptr); | ||
| 466 | break; | ||
| 467 | case SurfaceParams::SurfaceTarget::Texture2D: | ||
| 468 | glTexImage2D(SurfaceTargetToGL(params.target), 0, format_tuple.internal_format, | ||
| 469 | rect.GetWidth(), rect.GetHeight(), 0, format_tuple.format, | ||
| 470 | format_tuple.type, nullptr); | ||
| 471 | break; | ||
| 472 | case SurfaceParams::SurfaceTarget::Texture3D: | ||
| 473 | case SurfaceParams::SurfaceTarget::Texture2DArray: | ||
| 474 | glTexImage3D(SurfaceTargetToGL(params.target), 0, format_tuple.internal_format, | ||
| 475 | rect.GetWidth(), rect.GetHeight(), params.depth, 0, format_tuple.format, | ||
| 476 | format_tuple.type, nullptr); | ||
| 477 | break; | ||
| 478 | default: | ||
| 479 | LOG_CRITICAL(Render_OpenGL, "Unimplemented surface target={}", | ||
| 480 | static_cast<u32>(params.target)); | ||
| 481 | UNREACHABLE(); | ||
| 482 | glTexImage2D(GL_TEXTURE_2D, 0, format_tuple.internal_format, rect.GetWidth(), | ||
| 483 | rect.GetHeight(), 0, format_tuple.format, format_tuple.type, nullptr); | ||
| 484 | } | ||
| 485 | } | ||
| 486 | |||
| 487 | glTexParameteri(SurfaceTargetToGL(params.target), GL_TEXTURE_MAX_LEVEL, 0); | ||
| 488 | glTexParameteri(SurfaceTargetToGL(params.target), GL_TEXTURE_MIN_FILTER, GL_LINEAR); | ||
| 489 | glTexParameteri(SurfaceTargetToGL(params.target), GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); | ||
| 490 | glTexParameteri(SurfaceTargetToGL(params.target), GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); | ||
| 447 | } | 491 | } |
| 448 | 492 | ||
| 449 | static void ConvertS8Z24ToZ24S8(std::vector<u8>& data, u32 width, u32 height) { | 493 | static void ConvertS8Z24ToZ24S8(std::vector<u8>& data, u32 width, u32 height) { |
| @@ -514,23 +558,6 @@ static void ConvertFormatAsNeeded_LoadGLBuffer(std::vector<u8>& data, PixelForma | |||
| 514 | } | 558 | } |
| 515 | } | 559 | } |
| 516 | 560 | ||
| 517 | /** | ||
| 518 | * Helper function to perform software conversion (as needed) when flushing a buffer to Switch | ||
| 519 | * memory. This is for Maxwell pixel formats that cannot be represented as-is in OpenGL or with | ||
| 520 | * typical desktop GPUs. | ||
| 521 | */ | ||
| 522 | static void ConvertFormatAsNeeded_FlushGLBuffer(std::vector<u8>& /*data*/, PixelFormat pixel_format, | ||
| 523 | u32 /*width*/, u32 /*height*/) { | ||
| 524 | switch (pixel_format) { | ||
| 525 | case PixelFormat::ASTC_2D_4X4: | ||
| 526 | case PixelFormat::S8Z24: | ||
| 527 | LOG_CRITICAL(Render_OpenGL, "Unimplemented pixel_format={}", | ||
| 528 | static_cast<u32>(pixel_format)); | ||
| 529 | UNREACHABLE(); | ||
| 530 | break; | ||
| 531 | } | ||
| 532 | } | ||
| 533 | |||
| 534 | MICROPROFILE_DEFINE(OpenGL_SurfaceLoad, "OpenGL", "Surface Load", MP_RGB(128, 64, 192)); | 561 | MICROPROFILE_DEFINE(OpenGL_SurfaceLoad, "OpenGL", "Surface Load", MP_RGB(128, 64, 192)); |
| 535 | void CachedSurface::LoadGLBuffer() { | 562 | void CachedSurface::LoadGLBuffer() { |
| 536 | ASSERT(params.type != SurfaceType::Fill); | 563 | ASSERT(params.type != SurfaceType::Fill); |
| @@ -545,13 +572,24 @@ void CachedSurface::LoadGLBuffer() { | |||
| 545 | MICROPROFILE_SCOPE(OpenGL_SurfaceLoad); | 572 | MICROPROFILE_SCOPE(OpenGL_SurfaceLoad); |
| 546 | 573 | ||
| 547 | if (params.is_tiled) { | 574 | if (params.is_tiled) { |
| 548 | gl_buffer.resize(copy_size); | 575 | // TODO(bunnei): This only unswizzles and copies a 2D texture - we do not yet know how to do |
| 576 | // this for 3D textures, etc. | ||
| 577 | switch (params.target) { | ||
| 578 | case SurfaceParams::SurfaceTarget::Texture2D: | ||
| 579 | // Pass impl. to the fallback code below | ||
| 580 | break; | ||
| 581 | default: | ||
| 582 | LOG_CRITICAL(HW_GPU, "Unimplemented tiled load for target={}", | ||
| 583 | static_cast<u32>(params.target)); | ||
| 584 | UNREACHABLE(); | ||
| 585 | } | ||
| 549 | 586 | ||
| 587 | gl_buffer.resize(params.depth * copy_size); | ||
| 550 | morton_to_gl_fns[static_cast<size_t>(params.pixel_format)]( | 588 | morton_to_gl_fns[static_cast<size_t>(params.pixel_format)]( |
| 551 | params.width, params.block_height, params.height, gl_buffer, params.addr); | 589 | params.width, params.block_height, params.height, gl_buffer.data(), copy_size, |
| 590 | params.addr); | ||
| 552 | } else { | 591 | } else { |
| 553 | const u8* const texture_src_data_end = texture_src_data + copy_size; | 592 | const u8* const texture_src_data_end{texture_src_data + (params.depth * copy_size)}; |
| 554 | |||
| 555 | gl_buffer.assign(texture_src_data, texture_src_data_end); | 593 | gl_buffer.assign(texture_src_data, texture_src_data_end); |
| 556 | } | 594 | } |
| 557 | 595 | ||
| @@ -560,23 +598,7 @@ void CachedSurface::LoadGLBuffer() { | |||
| 560 | 598 | ||
| 561 | MICROPROFILE_DEFINE(OpenGL_SurfaceFlush, "OpenGL", "Surface Flush", MP_RGB(128, 192, 64)); | 599 | MICROPROFILE_DEFINE(OpenGL_SurfaceFlush, "OpenGL", "Surface Flush", MP_RGB(128, 192, 64)); |
| 562 | void CachedSurface::FlushGLBuffer() { | 600 | void CachedSurface::FlushGLBuffer() { |
| 563 | u8* const dst_buffer = Memory::GetPointer(params.addr); | 601 | ASSERT_MSG(false, "Unimplemented"); |
| 564 | |||
| 565 | ASSERT(dst_buffer); | ||
| 566 | ASSERT(gl_buffer.size() == | ||
| 567 | params.width * params.height * GetGLBytesPerPixel(params.pixel_format)); | ||
| 568 | |||
| 569 | MICROPROFILE_SCOPE(OpenGL_SurfaceFlush); | ||
| 570 | |||
| 571 | ConvertFormatAsNeeded_FlushGLBuffer(gl_buffer, params.pixel_format, params.width, | ||
| 572 | params.height); | ||
| 573 | |||
| 574 | if (!params.is_tiled) { | ||
| 575 | std::memcpy(dst_buffer, gl_buffer.data(), params.size_in_bytes); | ||
| 576 | } else { | ||
| 577 | gl_to_morton_fns[static_cast<size_t>(params.pixel_format)]( | ||
| 578 | params.width, params.block_height, params.height, gl_buffer, params.addr); | ||
| 579 | } | ||
| 580 | } | 602 | } |
| 581 | 603 | ||
| 582 | MICROPROFILE_DEFINE(OpenGL_TextureUL, "OpenGL", "Texture Upload", MP_RGB(128, 64, 192)); | 604 | 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 | |||
| 587 | MICROPROFILE_SCOPE(OpenGL_TextureUL); | 609 | MICROPROFILE_SCOPE(OpenGL_TextureUL); |
| 588 | 610 | ||
| 589 | ASSERT(gl_buffer.size() == | 611 | ASSERT(gl_buffer.size() == |
| 590 | params.width * params.height * GetGLBytesPerPixel(params.pixel_format)); | 612 | params.width * params.height * GetGLBytesPerPixel(params.pixel_format) * params.depth); |
| 591 | 613 | ||
| 592 | const auto& rect{params.GetRect()}; | 614 | const auto& rect{params.GetRect()}; |
| 593 | 615 | ||
| @@ -600,8 +622,13 @@ void CachedSurface::UploadGLTexture(GLuint read_fb_handle, GLuint draw_fb_handle | |||
| 600 | GLuint target_tex = texture.handle; | 622 | GLuint target_tex = texture.handle; |
| 601 | OpenGLState cur_state = OpenGLState::GetCurState(); | 623 | OpenGLState cur_state = OpenGLState::GetCurState(); |
| 602 | 624 | ||
| 603 | GLuint old_tex = cur_state.texture_units[0].texture_2d; | 625 | const auto& old_tex = cur_state.texture_units[0]; |
| 604 | cur_state.texture_units[0].texture_2d = target_tex; | 626 | SCOPE_EXIT({ |
| 627 | cur_state.texture_units[0] = old_tex; | ||
| 628 | cur_state.Apply(); | ||
| 629 | }); | ||
| 630 | cur_state.texture_units[0].texture = target_tex; | ||
| 631 | cur_state.texture_units[0].target = SurfaceTargetToGL(params.target); | ||
| 605 | cur_state.Apply(); | 632 | cur_state.Apply(); |
| 606 | 633 | ||
| 607 | // Ensure no bad interactions with GL_UNPACK_ALIGNMENT | 634 | // Ensure no bad interactions with GL_UNPACK_ALIGNMENT |
| @@ -610,74 +637,68 @@ void CachedSurface::UploadGLTexture(GLuint read_fb_handle, GLuint draw_fb_handle | |||
| 610 | 637 | ||
| 611 | glActiveTexture(GL_TEXTURE0); | 638 | glActiveTexture(GL_TEXTURE0); |
| 612 | if (tuple.compressed) { | 639 | if (tuple.compressed) { |
| 613 | glCompressedTexImage2D( | 640 | switch (params.target) { |
| 614 | GL_TEXTURE_2D, 0, tuple.internal_format, static_cast<GLsizei>(params.width), | 641 | case SurfaceParams::SurfaceTarget::Texture2D: |
| 615 | static_cast<GLsizei>(params.height), 0, static_cast<GLsizei>(params.size_in_bytes), | 642 | glCompressedTexImage2D( |
| 616 | &gl_buffer[buffer_offset]); | 643 | SurfaceTargetToGL(params.target), 0, tuple.internal_format, |
| 644 | static_cast<GLsizei>(params.width), static_cast<GLsizei>(params.height), 0, | ||
| 645 | static_cast<GLsizei>(params.size_in_bytes), &gl_buffer[buffer_offset]); | ||
| 646 | break; | ||
| 647 | case SurfaceParams::SurfaceTarget::Texture3D: | ||
| 648 | case SurfaceParams::SurfaceTarget::Texture2DArray: | ||
| 649 | glCompressedTexImage3D( | ||
| 650 | SurfaceTargetToGL(params.target), 0, tuple.internal_format, | ||
| 651 | static_cast<GLsizei>(params.width), static_cast<GLsizei>(params.height), | ||
| 652 | static_cast<GLsizei>(params.depth), 0, static_cast<GLsizei>(params.size_in_bytes), | ||
| 653 | &gl_buffer[buffer_offset]); | ||
| 654 | break; | ||
| 655 | default: | ||
| 656 | LOG_CRITICAL(Render_OpenGL, "Unimplemented surface target={}", | ||
| 657 | static_cast<u32>(params.target)); | ||
| 658 | UNREACHABLE(); | ||
| 659 | glCompressedTexImage2D( | ||
| 660 | GL_TEXTURE_2D, 0, tuple.internal_format, static_cast<GLsizei>(params.width), | ||
| 661 | static_cast<GLsizei>(params.height), 0, static_cast<GLsizei>(params.size_in_bytes), | ||
| 662 | &gl_buffer[buffer_offset]); | ||
| 663 | } | ||
| 617 | } else { | 664 | } else { |
| 618 | glTexSubImage2D(GL_TEXTURE_2D, 0, x0, y0, static_cast<GLsizei>(rect.GetWidth()), | ||
| 619 | static_cast<GLsizei>(rect.GetHeight()), tuple.format, tuple.type, | ||
| 620 | &gl_buffer[buffer_offset]); | ||
| 621 | } | ||
| 622 | |||
| 623 | glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); | ||
| 624 | |||
| 625 | cur_state.texture_units[0].texture_2d = old_tex; | ||
| 626 | cur_state.Apply(); | ||
| 627 | } | ||
| 628 | |||
| 629 | MICROPROFILE_DEFINE(OpenGL_TextureDL, "OpenGL", "Texture Download", MP_RGB(128, 192, 64)); | ||
| 630 | void CachedSurface::DownloadGLTexture(GLuint read_fb_handle, GLuint draw_fb_handle) { | ||
| 631 | if (params.type == SurfaceType::Fill) | ||
| 632 | return; | ||
| 633 | |||
| 634 | MICROPROFILE_SCOPE(OpenGL_TextureDL); | ||
| 635 | |||
| 636 | gl_buffer.resize(params.width * params.height * GetGLBytesPerPixel(params.pixel_format)); | ||
| 637 | |||
| 638 | OpenGLState state = OpenGLState::GetCurState(); | ||
| 639 | OpenGLState prev_state = state; | ||
| 640 | SCOPE_EXIT({ prev_state.Apply(); }); | ||
| 641 | 665 | ||
| 642 | const FormatTuple& tuple = GetFormatTuple(params.pixel_format, params.component_type); | 666 | switch (params.target) { |
| 643 | 667 | case SurfaceParams::SurfaceTarget::Texture1D: | |
| 644 | // Ensure no bad interactions with GL_PACK_ALIGNMENT | 668 | glTexSubImage1D(SurfaceTargetToGL(params.target), 0, x0, |
| 645 | ASSERT(params.width * GetGLBytesPerPixel(params.pixel_format) % 4 == 0); | 669 | static_cast<GLsizei>(rect.GetWidth()), tuple.format, tuple.type, |
| 646 | glPixelStorei(GL_PACK_ROW_LENGTH, static_cast<GLint>(params.width)); | 670 | &gl_buffer[buffer_offset]); |
| 647 | 671 | break; | |
| 648 | const auto& rect{params.GetRect()}; | 672 | case SurfaceParams::SurfaceTarget::Texture2D: |
| 649 | size_t buffer_offset = | 673 | glTexSubImage2D(SurfaceTargetToGL(params.target), 0, x0, y0, |
| 650 | (rect.bottom * params.width + rect.left) * GetGLBytesPerPixel(params.pixel_format); | 674 | static_cast<GLsizei>(rect.GetWidth()), |
| 651 | 675 | static_cast<GLsizei>(rect.GetHeight()), tuple.format, tuple.type, | |
| 652 | state.UnbindTexture(texture.handle); | 676 | &gl_buffer[buffer_offset]); |
| 653 | state.draw.read_framebuffer = read_fb_handle; | 677 | break; |
| 654 | state.Apply(); | 678 | case SurfaceParams::SurfaceTarget::Texture3D: |
| 655 | 679 | case SurfaceParams::SurfaceTarget::Texture2DArray: | |
| 656 | if (params.type == SurfaceType::ColorTexture) { | 680 | glTexSubImage3D(SurfaceTargetToGL(params.target), 0, x0, y0, 0, |
| 657 | glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, | 681 | static_cast<GLsizei>(rect.GetWidth()), |
| 658 | texture.handle, 0); | 682 | static_cast<GLsizei>(rect.GetHeight()), params.depth, tuple.format, |
| 659 | glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0, | 683 | tuple.type, &gl_buffer[buffer_offset]); |
| 660 | 0); | 684 | break; |
| 661 | } else if (params.type == SurfaceType::Depth) { | 685 | default: |
| 662 | glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0); | 686 | LOG_CRITICAL(Render_OpenGL, "Unimplemented surface target={}", |
| 663 | glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, | 687 | static_cast<u32>(params.target)); |
| 664 | texture.handle, 0); | 688 | UNREACHABLE(); |
| 665 | glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0, 0); | 689 | glTexSubImage2D(GL_TEXTURE_2D, 0, x0, y0, static_cast<GLsizei>(rect.GetWidth()), |
| 666 | } else { | 690 | static_cast<GLsizei>(rect.GetHeight()), tuple.format, tuple.type, |
| 667 | glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0); | 691 | &gl_buffer[buffer_offset]); |
| 668 | glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, | 692 | } |
| 669 | texture.handle, 0); | ||
| 670 | } | 693 | } |
| 671 | glReadPixels(static_cast<GLint>(rect.left), static_cast<GLint>(rect.bottom), | ||
| 672 | static_cast<GLsizei>(rect.GetWidth()), static_cast<GLsizei>(rect.GetHeight()), | ||
| 673 | tuple.format, tuple.type, &gl_buffer[buffer_offset]); | ||
| 674 | 694 | ||
| 675 | glPixelStorei(GL_PACK_ROW_LENGTH, 0); | 695 | glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); |
| 676 | } | 696 | } |
| 677 | 697 | ||
| 678 | RasterizerCacheOpenGL::RasterizerCacheOpenGL() { | 698 | RasterizerCacheOpenGL::RasterizerCacheOpenGL() { |
| 679 | read_framebuffer.Create(); | 699 | read_framebuffer.Create(); |
| 680 | draw_framebuffer.Create(); | 700 | draw_framebuffer.Create(); |
| 701 | copy_pbo.Create(); | ||
| 681 | } | 702 | } |
| 682 | 703 | ||
| 683 | Surface RasterizerCacheOpenGL::GetTextureSurface(const Tegra::Texture::FullTextureInfo& config) { | 704 | Surface RasterizerCacheOpenGL::GetTextureSurface(const Tegra::Texture::FullTextureInfo& config) { |
| @@ -748,7 +769,6 @@ void RasterizerCacheOpenGL::LoadSurface(const Surface& surface) { | |||
| 748 | } | 769 | } |
| 749 | 770 | ||
| 750 | void RasterizerCacheOpenGL::FlushSurface(const Surface& surface) { | 771 | void RasterizerCacheOpenGL::FlushSurface(const Surface& surface) { |
| 751 | surface->DownloadGLTexture(read_framebuffer.handle, draw_framebuffer.handle); | ||
| 752 | surface->FlushGLBuffer(); | 772 | surface->FlushGLBuffer(); |
| 753 | } | 773 | } |
| 754 | 774 | ||
| @@ -809,8 +829,8 @@ Surface RasterizerCacheOpenGL::RecreateSurface(const Surface& surface, | |||
| 809 | // If format is unchanged, we can do a faster blit without reinterpreting pixel data | 829 | // If format is unchanged, we can do a faster blit without reinterpreting pixel data |
| 810 | if (params.pixel_format == new_params.pixel_format) { | 830 | if (params.pixel_format == new_params.pixel_format) { |
| 811 | BlitTextures(surface->Texture().handle, params.GetRect(), new_surface->Texture().handle, | 831 | BlitTextures(surface->Texture().handle, params.GetRect(), new_surface->Texture().handle, |
| 812 | new_surface->GetSurfaceParams().GetRect(), params.type, | 832 | params.GetRect(), params.type, read_framebuffer.handle, |
| 813 | read_framebuffer.handle, draw_framebuffer.handle); | 833 | draw_framebuffer.handle); |
| 814 | return new_surface; | 834 | return new_surface; |
| 815 | } | 835 | } |
| 816 | 836 | ||
| @@ -821,12 +841,7 @@ Surface RasterizerCacheOpenGL::RecreateSurface(const Surface& surface, | |||
| 821 | 841 | ||
| 822 | size_t buffer_size = std::max(params.SizeInBytes(), new_params.SizeInBytes()); | 842 | size_t buffer_size = std::max(params.SizeInBytes(), new_params.SizeInBytes()); |
| 823 | 843 | ||
| 824 | // Use a Pixel Buffer Object to download the previous texture and then upload it to the new | 844 | glBindBuffer(GL_PIXEL_PACK_BUFFER, copy_pbo.handle); |
| 825 | // one using the new format. | ||
| 826 | OGLBuffer pbo; | ||
| 827 | pbo.Create(); | ||
| 828 | |||
| 829 | glBindBuffer(GL_PIXEL_PACK_BUFFER, pbo.handle); | ||
| 830 | glBufferData(GL_PIXEL_PACK_BUFFER, buffer_size, nullptr, GL_STREAM_DRAW_ARB); | 845 | glBufferData(GL_PIXEL_PACK_BUFFER, buffer_size, nullptr, GL_STREAM_DRAW_ARB); |
| 831 | if (source_format.compressed) { | 846 | if (source_format.compressed) { |
| 832 | glGetCompressedTextureImage(surface->Texture().handle, 0, | 847 | glGetCompressedTextureImage(surface->Texture().handle, 0, |
| @@ -845,8 +860,8 @@ Surface RasterizerCacheOpenGL::RecreateSurface(const Surface& surface, | |||
| 845 | // of the data in this case. Games like Super Mario Odyssey seem to hit this case | 860 | // of the data in this case. Games like Super Mario Odyssey seem to hit this case |
| 846 | // when drawing, it re-uses the memory of a previous texture as a bigger framebuffer | 861 | // when drawing, it re-uses the memory of a previous texture as a bigger framebuffer |
| 847 | // but it doesn't clear it beforehand, the texture is already full of zeros. | 862 | // but it doesn't clear it beforehand, the texture is already full of zeros. |
| 848 | LOG_CRITICAL(HW_GPU, "Trying to upload extra texture data from the CPU during " | 863 | LOG_DEBUG(HW_GPU, "Trying to upload extra texture data from the CPU during " |
| 849 | "reinterpretation but the texture is tiled."); | 864 | "reinterpretation but the texture is tiled."); |
| 850 | } | 865 | } |
| 851 | size_t remaining_size = new_params.SizeInBytes() - params.SizeInBytes(); | 866 | size_t remaining_size = new_params.SizeInBytes() - params.SizeInBytes(); |
| 852 | std::vector<u8> data(remaining_size); | 867 | std::vector<u8> data(remaining_size); |
| @@ -859,21 +874,38 @@ Surface RasterizerCacheOpenGL::RecreateSurface(const Surface& surface, | |||
| 859 | 874 | ||
| 860 | const auto& dest_rect{new_params.GetRect()}; | 875 | const auto& dest_rect{new_params.GetRect()}; |
| 861 | 876 | ||
| 862 | glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pbo.handle); | 877 | glBindBuffer(GL_PIXEL_UNPACK_BUFFER, copy_pbo.handle); |
| 863 | if (dest_format.compressed) { | 878 | if (dest_format.compressed) { |
| 864 | glCompressedTexSubImage2D( | 879 | LOG_CRITICAL(HW_GPU, "Compressed copy is unimplemented!"); |
| 865 | GL_TEXTURE_2D, 0, 0, 0, static_cast<GLsizei>(dest_rect.GetWidth()), | 880 | UNREACHABLE(); |
| 866 | static_cast<GLsizei>(dest_rect.GetHeight()), dest_format.format, | ||
| 867 | static_cast<GLsizei>(new_params.SizeInBytes()), nullptr); | ||
| 868 | } else { | 881 | } else { |
| 869 | glTextureSubImage2D(new_surface->Texture().handle, 0, 0, 0, | 882 | switch (new_params.target) { |
| 870 | static_cast<GLsizei>(dest_rect.GetWidth()), | 883 | case SurfaceParams::SurfaceTarget::Texture1D: |
| 871 | static_cast<GLsizei>(dest_rect.GetHeight()), dest_format.format, | 884 | glTextureSubImage1D(new_surface->Texture().handle, 0, 0, |
| 872 | dest_format.type, nullptr); | 885 | static_cast<GLsizei>(dest_rect.GetWidth()), dest_format.format, |
| 886 | dest_format.type, nullptr); | ||
| 887 | break; | ||
| 888 | case SurfaceParams::SurfaceTarget::Texture2D: | ||
| 889 | glTextureSubImage2D(new_surface->Texture().handle, 0, 0, 0, | ||
| 890 | static_cast<GLsizei>(dest_rect.GetWidth()), | ||
| 891 | static_cast<GLsizei>(dest_rect.GetHeight()), dest_format.format, | ||
| 892 | dest_format.type, nullptr); | ||
| 893 | break; | ||
| 894 | case SurfaceParams::SurfaceTarget::Texture3D: | ||
| 895 | case SurfaceParams::SurfaceTarget::Texture2DArray: | ||
| 896 | glTextureSubImage3D(new_surface->Texture().handle, 0, 0, 0, 0, | ||
| 897 | static_cast<GLsizei>(dest_rect.GetWidth()), | ||
| 898 | static_cast<GLsizei>(dest_rect.GetHeight()), | ||
| 899 | static_cast<GLsizei>(new_params.depth), dest_format.format, | ||
| 900 | dest_format.type, nullptr); | ||
| 901 | break; | ||
| 902 | default: | ||
| 903 | LOG_CRITICAL(Render_OpenGL, "Unimplemented surface target={}", | ||
| 904 | static_cast<u32>(params.target)); | ||
| 905 | UNREACHABLE(); | ||
| 906 | } | ||
| 873 | } | 907 | } |
| 874 | glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); | 908 | glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); |
| 875 | |||
| 876 | pbo.Release(); | ||
| 877 | } | 909 | } |
| 878 | 910 | ||
| 879 | return new_surface; | 911 | 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 { | |||
| 109 | Invalid = 4, | 109 | Invalid = 4, |
| 110 | }; | 110 | }; |
| 111 | 111 | ||
| 112 | enum class SurfaceTarget { | ||
| 113 | Texture1D, | ||
| 114 | Texture2D, | ||
| 115 | Texture3D, | ||
| 116 | Texture1DArray, | ||
| 117 | Texture2DArray, | ||
| 118 | TextureCubemap, | ||
| 119 | }; | ||
| 120 | |||
| 121 | static SurfaceTarget SurfaceTargetFromTextureType(Tegra::Texture::TextureType texture_type) { | ||
| 122 | switch (texture_type) { | ||
| 123 | case Tegra::Texture::TextureType::Texture1D: | ||
| 124 | return SurfaceTarget::Texture1D; | ||
| 125 | case Tegra::Texture::TextureType::Texture2D: | ||
| 126 | case Tegra::Texture::TextureType::Texture2DNoMipmap: | ||
| 127 | return SurfaceTarget::Texture2D; | ||
| 128 | case Tegra::Texture::TextureType::Texture1DArray: | ||
| 129 | return SurfaceTarget::Texture1DArray; | ||
| 130 | case Tegra::Texture::TextureType::Texture2DArray: | ||
| 131 | return SurfaceTarget::Texture2DArray; | ||
| 132 | default: | ||
| 133 | LOG_CRITICAL(HW_GPU, "Unimplemented texture_type={}", static_cast<u32>(texture_type)); | ||
| 134 | UNREACHABLE(); | ||
| 135 | return SurfaceTarget::Texture2D; | ||
| 136 | } | ||
| 137 | } | ||
| 138 | |||
| 112 | /** | 139 | /** |
| 113 | * Gets the compression factor for the specified PixelFormat. This applies to just the | 140 | * Gets the compression factor for the specified PixelFormat. This applies to just the |
| 114 | * "compressed width" and "compressed height", not the overall compression factor of a | 141 | * "compressed width" and "compressed height", not the overall compression factor of a |
| @@ -635,7 +662,7 @@ struct SurfaceParams { | |||
| 635 | ASSERT(width % compression_factor == 0); | 662 | ASSERT(width % compression_factor == 0); |
| 636 | ASSERT(height % compression_factor == 0); | 663 | ASSERT(height % compression_factor == 0); |
| 637 | return (width / compression_factor) * (height / compression_factor) * | 664 | return (width / compression_factor) * (height / compression_factor) * |
| 638 | GetFormatBpp(pixel_format) / CHAR_BIT; | 665 | GetFormatBpp(pixel_format) * depth / CHAR_BIT; |
| 639 | } | 666 | } |
| 640 | 667 | ||
| 641 | /// Creates SurfaceParams from a texture configuration | 668 | /// Creates SurfaceParams from a texture configuration |
| @@ -664,8 +691,10 @@ struct SurfaceParams { | |||
| 664 | SurfaceType type; | 691 | SurfaceType type; |
| 665 | u32 width; | 692 | u32 width; |
| 666 | u32 height; | 693 | u32 height; |
| 694 | u32 depth; | ||
| 667 | u32 unaligned_height; | 695 | u32 unaligned_height; |
| 668 | size_t size_in_bytes; | 696 | size_t size_in_bytes; |
| 697 | SurfaceTarget target; | ||
| 669 | 698 | ||
| 670 | // Parameters used for caching only | 699 | // Parameters used for caching only |
| 671 | u32 cache_width; | 700 | u32 cache_width; |
| @@ -709,6 +738,10 @@ public: | |||
| 709 | return texture; | 738 | return texture; |
| 710 | } | 739 | } |
| 711 | 740 | ||
| 741 | GLenum Target() const { | ||
| 742 | return gl_target; | ||
| 743 | } | ||
| 744 | |||
| 712 | static constexpr unsigned int GetGLBytesPerPixel(SurfaceParams::PixelFormat format) { | 745 | static constexpr unsigned int GetGLBytesPerPixel(SurfaceParams::PixelFormat format) { |
| 713 | if (format == SurfaceParams::PixelFormat::Invalid) | 746 | if (format == SurfaceParams::PixelFormat::Invalid) |
| 714 | return 0; | 747 | return 0; |
| @@ -724,14 +757,14 @@ public: | |||
| 724 | void LoadGLBuffer(); | 757 | void LoadGLBuffer(); |
| 725 | void FlushGLBuffer(); | 758 | void FlushGLBuffer(); |
| 726 | 759 | ||
| 727 | // Upload/Download data in gl_buffer in/to this surface's texture | 760 | // Upload data in gl_buffer to this surface's texture |
| 728 | void UploadGLTexture(GLuint read_fb_handle, GLuint draw_fb_handle); | 761 | void UploadGLTexture(GLuint read_fb_handle, GLuint draw_fb_handle); |
| 729 | void DownloadGLTexture(GLuint read_fb_handle, GLuint draw_fb_handle); | ||
| 730 | 762 | ||
| 731 | private: | 763 | private: |
| 732 | OGLTexture texture; | 764 | OGLTexture texture; |
| 733 | std::vector<u8> gl_buffer; | 765 | std::vector<u8> gl_buffer; |
| 734 | SurfaceParams params; | 766 | SurfaceParams params; |
| 767 | GLenum gl_target; | ||
| 735 | }; | 768 | }; |
| 736 | 769 | ||
| 737 | class RasterizerCacheOpenGL final : public RasterizerCache<Surface> { | 770 | class RasterizerCacheOpenGL final : public RasterizerCache<Surface> { |
| @@ -774,6 +807,10 @@ private: | |||
| 774 | 807 | ||
| 775 | OGLFramebuffer read_framebuffer; | 808 | OGLFramebuffer read_framebuffer; |
| 776 | OGLFramebuffer draw_framebuffer; | 809 | OGLFramebuffer draw_framebuffer; |
| 810 | |||
| 811 | /// Use a Pixel Buffer Object to download the previous texture and then upload it to the new one | ||
| 812 | /// using the new format. | ||
| 813 | OGLBuffer copy_pbo; | ||
| 777 | }; | 814 | }; |
| 778 | 815 | ||
| 779 | } // namespace OpenGL | 816 | } // 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: | |||
| 443 | } | 443 | } |
| 444 | declarations.AddNewLine(); | 444 | declarations.AddNewLine(); |
| 445 | 445 | ||
| 446 | // Append the sampler2D array for the used textures. | 446 | const auto& samplers = GetSamplers(); |
| 447 | const size_t num_samplers = used_samplers.size(); | 447 | for (const auto& sampler : samplers) { |
| 448 | if (num_samplers > 0) { | 448 | declarations.AddLine("uniform " + sampler.GetTypeString() + ' ' + sampler.GetName() + |
| 449 | declarations.AddLine("uniform sampler2D " + SamplerEntry::GetArrayName(stage) + '[' + | 449 | ';'); |
| 450 | std::to_string(num_samplers) + "];"); | ||
| 451 | declarations.AddNewLine(); | ||
| 452 | } | 450 | } |
| 451 | declarations.AddNewLine(); | ||
| 453 | } | 452 | } |
| 454 | 453 | ||
| 455 | /// Returns a list of constant buffer declarations | 454 | /// Returns a list of constant buffer declarations |
| @@ -461,13 +460,14 @@ public: | |||
| 461 | } | 460 | } |
| 462 | 461 | ||
| 463 | /// Returns a list of samplers used in the shader | 462 | /// Returns a list of samplers used in the shader |
| 464 | std::vector<SamplerEntry> GetSamplers() const { | 463 | const std::vector<SamplerEntry>& GetSamplers() const { |
| 465 | return used_samplers; | 464 | return used_samplers; |
| 466 | } | 465 | } |
| 467 | 466 | ||
| 468 | /// Returns the GLSL sampler used for the input shader sampler, and creates a new one if | 467 | /// Returns the GLSL sampler used for the input shader sampler, and creates a new one if |
| 469 | /// necessary. | 468 | /// necessary. |
| 470 | std::string AccessSampler(const Sampler& sampler) { | 469 | std::string AccessSampler(const Sampler& sampler, Tegra::Shader::TextureType type, |
| 470 | bool is_array) { | ||
| 471 | size_t offset = static_cast<size_t>(sampler.index.Value()); | 471 | size_t offset = static_cast<size_t>(sampler.index.Value()); |
| 472 | 472 | ||
| 473 | // If this sampler has already been used, return the existing mapping. | 473 | // If this sampler has already been used, return the existing mapping. |
| @@ -476,12 +476,13 @@ public: | |||
| 476 | [&](const SamplerEntry& entry) { return entry.GetOffset() == offset; }); | 476 | [&](const SamplerEntry& entry) { return entry.GetOffset() == offset; }); |
| 477 | 477 | ||
| 478 | if (itr != used_samplers.end()) { | 478 | if (itr != used_samplers.end()) { |
| 479 | ASSERT(itr->GetType() == type && itr->IsArray() == is_array); | ||
| 479 | return itr->GetName(); | 480 | return itr->GetName(); |
| 480 | } | 481 | } |
| 481 | 482 | ||
| 482 | // Otherwise create a new mapping for this sampler | 483 | // Otherwise create a new mapping for this sampler |
| 483 | size_t next_index = used_samplers.size(); | 484 | size_t next_index = used_samplers.size(); |
| 484 | SamplerEntry entry{stage, offset, next_index}; | 485 | SamplerEntry entry{stage, offset, next_index, type, is_array}; |
| 485 | used_samplers.emplace_back(entry); | 486 | used_samplers.emplace_back(entry); |
| 486 | return entry.GetName(); | 487 | return entry.GetName(); |
| 487 | } | 488 | } |
| @@ -722,8 +723,8 @@ private: | |||
| 722 | } | 723 | } |
| 723 | 724 | ||
| 724 | /// Generates code representing a texture sampler. | 725 | /// Generates code representing a texture sampler. |
| 725 | std::string GetSampler(const Sampler& sampler) { | 726 | std::string GetSampler(const Sampler& sampler, Tegra::Shader::TextureType type, bool is_array) { |
| 726 | return regs.AccessSampler(sampler); | 727 | return regs.AccessSampler(sampler, type, is_array); |
| 727 | } | 728 | } |
| 728 | 729 | ||
| 729 | /** | 730 | /** |
| @@ -1753,10 +1754,35 @@ private: | |||
| 1753 | break; | 1754 | break; |
| 1754 | } | 1755 | } |
| 1755 | case OpCode::Id::TEX: { | 1756 | case OpCode::Id::TEX: { |
| 1756 | const std::string op_a = regs.GetRegisterAsFloat(instr.gpr8); | 1757 | ASSERT_MSG(instr.tex.array == 0, "TEX arrays unimplemented"); |
| 1757 | const std::string op_b = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1); | 1758 | Tegra::Shader::TextureType texture_type{instr.tex.texture_type}; |
| 1758 | const std::string sampler = GetSampler(instr.sampler); | 1759 | std::string coord; |
| 1759 | const std::string coord = "vec2 coords = vec2(" + op_a + ", " + op_b + ");"; | 1760 | |
| 1761 | switch (texture_type) { | ||
| 1762 | case Tegra::Shader::TextureType::Texture1D: { | ||
| 1763 | std::string x = regs.GetRegisterAsFloat(instr.gpr8); | ||
| 1764 | coord = "float coords = " + x + ';'; | ||
| 1765 | break; | ||
| 1766 | } | ||
| 1767 | case Tegra::Shader::TextureType::Texture2D: { | ||
| 1768 | std::string x = regs.GetRegisterAsFloat(instr.gpr8); | ||
| 1769 | std::string y = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1); | ||
| 1770 | coord = "vec2 coords = vec2(" + x + ", " + y + ");"; | ||
| 1771 | break; | ||
| 1772 | } | ||
| 1773 | default: | ||
| 1774 | LOG_CRITICAL(HW_GPU, "Unhandled texture type {}", | ||
| 1775 | static_cast<u32>(texture_type)); | ||
| 1776 | UNREACHABLE(); | ||
| 1777 | |||
| 1778 | // Fallback to interpreting as a 2D texture for now | ||
| 1779 | std::string x = regs.GetRegisterAsFloat(instr.gpr8); | ||
| 1780 | std::string y = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1); | ||
| 1781 | coord = "vec2 coords = vec2(" + x + ", " + y + ");"; | ||
| 1782 | texture_type = Tegra::Shader::TextureType::Texture2D; | ||
| 1783 | } | ||
| 1784 | |||
| 1785 | const std::string sampler = GetSampler(instr.sampler, texture_type, false); | ||
| 1760 | // Add an extra scope and declare the texture coords inside to prevent | 1786 | // Add an extra scope and declare the texture coords inside to prevent |
| 1761 | // overwriting them in case they are used as outputs of the texs instruction. | 1787 | // overwriting them in case they are used as outputs of the texs instruction. |
| 1762 | shader.AddLine("{"); | 1788 | shader.AddLine("{"); |
| @@ -1778,20 +1804,65 @@ private: | |||
| 1778 | break; | 1804 | break; |
| 1779 | } | 1805 | } |
| 1780 | case OpCode::Id::TEXS: { | 1806 | case OpCode::Id::TEXS: { |
| 1781 | const std::string op_a = regs.GetRegisterAsFloat(instr.gpr8); | 1807 | std::string coord; |
| 1782 | const std::string op_b = regs.GetRegisterAsFloat(instr.gpr20); | 1808 | Tegra::Shader::TextureType texture_type{instr.texs.GetTextureType()}; |
| 1783 | const std::string sampler = GetSampler(instr.sampler); | 1809 | bool is_array{instr.texs.IsArrayTexture()}; |
| 1784 | const std::string coord = "vec2 coords = vec2(" + op_a + ", " + op_b + ");"; | 1810 | |
| 1811 | switch (texture_type) { | ||
| 1812 | case Tegra::Shader::TextureType::Texture2D: { | ||
| 1813 | if (is_array) { | ||
| 1814 | std::string index = regs.GetRegisterAsInteger(instr.gpr8); | ||
| 1815 | std::string x = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1); | ||
| 1816 | std::string y = regs.GetRegisterAsFloat(instr.gpr20); | ||
| 1817 | coord = "vec3 coords = vec3(" + x + ", " + y + ", " + index + ");"; | ||
| 1818 | } else { | ||
| 1819 | std::string x = regs.GetRegisterAsFloat(instr.gpr8); | ||
| 1820 | std::string y = regs.GetRegisterAsFloat(instr.gpr20); | ||
| 1821 | coord = "vec2 coords = vec2(" + x + ", " + y + ");"; | ||
| 1822 | } | ||
| 1823 | break; | ||
| 1824 | } | ||
| 1825 | default: | ||
| 1826 | LOG_CRITICAL(HW_GPU, "Unhandled texture type {}", | ||
| 1827 | static_cast<u32>(texture_type)); | ||
| 1828 | UNREACHABLE(); | ||
| 1785 | 1829 | ||
| 1830 | // Fallback to interpreting as a 2D texture for now | ||
| 1831 | std::string x = regs.GetRegisterAsFloat(instr.gpr8); | ||
| 1832 | std::string y = regs.GetRegisterAsFloat(instr.gpr20); | ||
| 1833 | coord = "vec2 coords = vec2(" + x + ", " + y + ");"; | ||
| 1834 | texture_type = Tegra::Shader::TextureType::Texture2D; | ||
| 1835 | is_array = false; | ||
| 1836 | } | ||
| 1837 | const std::string sampler = GetSampler(instr.sampler, texture_type, is_array); | ||
| 1786 | const std::string texture = "texture(" + sampler + ", coords)"; | 1838 | const std::string texture = "texture(" + sampler + ", coords)"; |
| 1787 | WriteTexsInstruction(instr, coord, texture); | 1839 | WriteTexsInstruction(instr, coord, texture); |
| 1788 | break; | 1840 | break; |
| 1789 | } | 1841 | } |
| 1790 | case OpCode::Id::TLDS: { | 1842 | case OpCode::Id::TLDS: { |
| 1791 | const std::string op_a = regs.GetRegisterAsInteger(instr.gpr8); | 1843 | ASSERT(instr.tlds.GetTextureType() == Tegra::Shader::TextureType::Texture2D); |
| 1792 | const std::string op_b = regs.GetRegisterAsInteger(instr.gpr20); | 1844 | ASSERT(instr.tlds.IsArrayTexture() == false); |
| 1793 | const std::string sampler = GetSampler(instr.sampler); | 1845 | std::string coord; |
| 1794 | const std::string coord = "ivec2 coords = ivec2(" + op_a + ", " + op_b + ");"; | 1846 | |
| 1847 | switch (instr.tlds.GetTextureType()) { | ||
| 1848 | case Tegra::Shader::TextureType::Texture2D: { | ||
| 1849 | if (instr.tlds.IsArrayTexture()) { | ||
| 1850 | LOG_CRITICAL(HW_GPU, "Unhandled 2d array texture"); | ||
| 1851 | UNREACHABLE(); | ||
| 1852 | } else { | ||
| 1853 | std::string x = regs.GetRegisterAsInteger(instr.gpr8); | ||
| 1854 | std::string y = regs.GetRegisterAsInteger(instr.gpr20); | ||
| 1855 | coord = "ivec2 coords = ivec2(" + x + ", " + y + ");"; | ||
| 1856 | } | ||
| 1857 | break; | ||
| 1858 | } | ||
| 1859 | default: | ||
| 1860 | LOG_CRITICAL(HW_GPU, "Unhandled texture type {}", | ||
| 1861 | static_cast<u32>(instr.tlds.GetTextureType())); | ||
| 1862 | UNREACHABLE(); | ||
| 1863 | } | ||
| 1864 | const std::string sampler = GetSampler(instr.sampler, instr.tlds.GetTextureType(), | ||
| 1865 | instr.tlds.IsArrayTexture()); | ||
| 1795 | const std::string texture = "texelFetch(" + sampler + ", coords, 0)"; | 1866 | const std::string texture = "texelFetch(" + sampler + ", coords, 0)"; |
| 1796 | WriteTexsInstruction(instr, coord, texture); | 1867 | WriteTexsInstruction(instr, coord, texture); |
| 1797 | break; | 1868 | break; |
| @@ -1799,7 +1870,7 @@ private: | |||
| 1799 | case OpCode::Id::TLD4: { | 1870 | case OpCode::Id::TLD4: { |
| 1800 | ASSERT(instr.tld4.texture_type == Tegra::Shader::TextureType::Texture2D); | 1871 | ASSERT(instr.tld4.texture_type == Tegra::Shader::TextureType::Texture2D); |
| 1801 | ASSERT(instr.tld4.array == 0); | 1872 | ASSERT(instr.tld4.array == 0); |
| 1802 | std::string coord{}; | 1873 | std::string coord; |
| 1803 | 1874 | ||
| 1804 | switch (instr.tld4.texture_type) { | 1875 | switch (instr.tld4.texture_type) { |
| 1805 | case Tegra::Shader::TextureType::Texture2D: { | 1876 | case Tegra::Shader::TextureType::Texture2D: { |
| @@ -1814,7 +1885,8 @@ private: | |||
| 1814 | UNREACHABLE(); | 1885 | UNREACHABLE(); |
| 1815 | } | 1886 | } |
| 1816 | 1887 | ||
| 1817 | const std::string sampler = GetSampler(instr.sampler); | 1888 | const std::string sampler = |
| 1889 | GetSampler(instr.sampler, instr.tld4.texture_type, false); | ||
| 1818 | // Add an extra scope and declare the texture coords inside to prevent | 1890 | // Add an extra scope and declare the texture coords inside to prevent |
| 1819 | // overwriting them in case they are used as outputs of the texs instruction. | 1891 | // overwriting them in case they are used as outputs of the texs instruction. |
| 1820 | shader.AddLine("{"); | 1892 | shader.AddLine("{"); |
| @@ -1840,7 +1912,8 @@ private: | |||
| 1840 | const std::string op_a = regs.GetRegisterAsFloat(instr.gpr8); | 1912 | const std::string op_a = regs.GetRegisterAsFloat(instr.gpr8); |
| 1841 | const std::string op_b = regs.GetRegisterAsFloat(instr.gpr20); | 1913 | const std::string op_b = regs.GetRegisterAsFloat(instr.gpr20); |
| 1842 | // TODO(Subv): Figure out how the sampler type is encoded in the TLD4S instruction. | 1914 | // TODO(Subv): Figure out how the sampler type is encoded in the TLD4S instruction. |
| 1843 | const std::string sampler = GetSampler(instr.sampler); | 1915 | const std::string sampler = |
| 1916 | GetSampler(instr.sampler, Tegra::Shader::TextureType::Texture2D, false); | ||
| 1844 | const std::string coord = "vec2 coords = vec2(" + op_a + ", " + op_b + ");"; | 1917 | const std::string coord = "vec2 coords = vec2(" + op_a + ", " + op_b + ");"; |
| 1845 | const std::string texture = "textureGather(" + sampler + ", coords, " + | 1918 | const std::string texture = "textureGather(" + sampler + ", coords, " + |
| 1846 | std::to_string(instr.tld4s.component) + ')'; | 1919 | 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 @@ | |||
| 9 | #include <vector> | 9 | #include <vector> |
| 10 | 10 | ||
| 11 | #include "common/common_types.h" | 11 | #include "common/common_types.h" |
| 12 | #include "video_core/engines/shader_bytecode.h" | ||
| 12 | 13 | ||
| 13 | namespace OpenGL::GLShader { | 14 | namespace OpenGL::GLShader { |
| 14 | 15 | ||
| @@ -73,8 +74,9 @@ class SamplerEntry { | |||
| 73 | using Maxwell = Tegra::Engines::Maxwell3D::Regs; | 74 | using Maxwell = Tegra::Engines::Maxwell3D::Regs; |
| 74 | 75 | ||
| 75 | public: | 76 | public: |
| 76 | SamplerEntry(Maxwell::ShaderStage stage, size_t offset, size_t index) | 77 | SamplerEntry(Maxwell::ShaderStage stage, size_t offset, size_t index, |
| 77 | : offset(offset), stage(stage), sampler_index(index) {} | 78 | Tegra::Shader::TextureType type, bool is_array) |
| 79 | : offset(offset), stage(stage), sampler_index(index), type(type), is_array(is_array) {} | ||
| 78 | 80 | ||
| 79 | size_t GetOffset() const { | 81 | size_t GetOffset() const { |
| 80 | return offset; | 82 | return offset; |
| @@ -89,8 +91,41 @@ public: | |||
| 89 | } | 91 | } |
| 90 | 92 | ||
| 91 | std::string GetName() const { | 93 | std::string GetName() const { |
| 92 | return std::string(TextureSamplerNames[static_cast<size_t>(stage)]) + '[' + | 94 | return std::string(TextureSamplerNames[static_cast<size_t>(stage)]) + '_' + |
| 93 | std::to_string(sampler_index) + ']'; | 95 | std::to_string(sampler_index); |
| 96 | } | ||
| 97 | |||
| 98 | std::string GetTypeString() const { | ||
| 99 | using Tegra::Shader::TextureType; | ||
| 100 | std::string glsl_type; | ||
| 101 | |||
| 102 | switch (type) { | ||
| 103 | case TextureType::Texture1D: | ||
| 104 | glsl_type = "sampler1D"; | ||
| 105 | break; | ||
| 106 | case TextureType::Texture2D: | ||
| 107 | glsl_type = "sampler2D"; | ||
| 108 | break; | ||
| 109 | case TextureType::Texture3D: | ||
| 110 | glsl_type = "sampler3D"; | ||
| 111 | break; | ||
| 112 | case TextureType::TextureCube: | ||
| 113 | glsl_type = "samplerCube"; | ||
| 114 | break; | ||
| 115 | default: | ||
| 116 | UNIMPLEMENTED(); | ||
| 117 | } | ||
| 118 | if (is_array) | ||
| 119 | glsl_type += "Array"; | ||
| 120 | return glsl_type; | ||
| 121 | } | ||
| 122 | |||
| 123 | Tegra::Shader::TextureType GetType() const { | ||
| 124 | return type; | ||
| 125 | } | ||
| 126 | |||
| 127 | bool IsArray() const { | ||
| 128 | return is_array; | ||
| 94 | } | 129 | } |
| 95 | 130 | ||
| 96 | u32 GetHash() const { | 131 | u32 GetHash() const { |
| @@ -105,11 +140,14 @@ private: | |||
| 105 | static constexpr std::array<const char*, Maxwell::MaxShaderStage> TextureSamplerNames = { | 140 | static constexpr std::array<const char*, Maxwell::MaxShaderStage> TextureSamplerNames = { |
| 106 | "tex_vs", "tex_tessc", "tex_tesse", "tex_gs", "tex_fs", | 141 | "tex_vs", "tex_tessc", "tex_tesse", "tex_gs", "tex_fs", |
| 107 | }; | 142 | }; |
| 143 | |||
| 108 | /// Offset in TSC memory from which to read the sampler object, as specified by the sampling | 144 | /// Offset in TSC memory from which to read the sampler object, as specified by the sampling |
| 109 | /// instruction. | 145 | /// instruction. |
| 110 | size_t offset; | 146 | size_t offset; |
| 111 | Maxwell::ShaderStage stage; ///< Shader stage where this sampler was used. | 147 | Maxwell::ShaderStage stage; ///< Shader stage where this sampler was used. |
| 112 | size_t sampler_index; ///< Value used to index into the generated GLSL sampler array. | 148 | size_t sampler_index; ///< Value used to index into the generated GLSL sampler array. |
| 149 | Tegra::Shader::TextureType type; ///< The type used to sample this texture (Texture2D, etc) | ||
| 150 | bool is_array; ///< Whether the texture is being sampled as an array texture or not. | ||
| 113 | }; | 151 | }; |
| 114 | 152 | ||
| 115 | struct ShaderEntries { | 153 | 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 { | |||
| 200 | const auto& texture_unit = texture_units[i]; | 200 | const auto& texture_unit = texture_units[i]; |
| 201 | const auto& cur_state_texture_unit = cur_state.texture_units[i]; | 201 | const auto& cur_state_texture_unit = cur_state.texture_units[i]; |
| 202 | 202 | ||
| 203 | if (texture_unit.texture_2d != cur_state_texture_unit.texture_2d) { | 203 | if (texture_unit.texture != cur_state_texture_unit.texture) { |
| 204 | glActiveTexture(TextureUnits::MaxwellTexture(static_cast<int>(i)).Enum()); | 204 | glActiveTexture(TextureUnits::MaxwellTexture(static_cast<int>(i)).Enum()); |
| 205 | glBindTexture(GL_TEXTURE_2D, texture_unit.texture_2d); | 205 | glBindTexture(texture_unit.target, texture_unit.texture); |
| 206 | } | 206 | } |
| 207 | if (texture_unit.sampler != cur_state_texture_unit.sampler) { | 207 | if (texture_unit.sampler != cur_state_texture_unit.sampler) { |
| 208 | glBindSampler(static_cast<GLuint>(i), texture_unit.sampler); | 208 | glBindSampler(static_cast<GLuint>(i), texture_unit.sampler); |
| @@ -214,7 +214,7 @@ void OpenGLState::Apply() const { | |||
| 214 | texture_unit.swizzle.a != cur_state_texture_unit.swizzle.a) { | 214 | texture_unit.swizzle.a != cur_state_texture_unit.swizzle.a) { |
| 215 | std::array<GLint, 4> mask = {texture_unit.swizzle.r, texture_unit.swizzle.g, | 215 | std::array<GLint, 4> mask = {texture_unit.swizzle.r, texture_unit.swizzle.g, |
| 216 | texture_unit.swizzle.b, texture_unit.swizzle.a}; | 216 | texture_unit.swizzle.b, texture_unit.swizzle.a}; |
| 217 | glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, mask.data()); | 217 | glTexParameteriv(texture_unit.target, GL_TEXTURE_SWIZZLE_RGBA, mask.data()); |
| 218 | } | 218 | } |
| 219 | } | 219 | } |
| 220 | 220 | ||
| @@ -287,7 +287,7 @@ void OpenGLState::Apply() const { | |||
| 287 | 287 | ||
| 288 | OpenGLState& OpenGLState::UnbindTexture(GLuint handle) { | 288 | OpenGLState& OpenGLState::UnbindTexture(GLuint handle) { |
| 289 | for (auto& unit : texture_units) { | 289 | for (auto& unit : texture_units) { |
| 290 | if (unit.texture_2d == handle) { | 290 | if (unit.texture == handle) { |
| 291 | unit.Unbind(); | 291 | unit.Unbind(); |
| 292 | } | 292 | } |
| 293 | } | 293 | } |
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: | |||
| 94 | 94 | ||
| 95 | // 3 texture units - one for each that is used in PICA fragment shader emulation | 95 | // 3 texture units - one for each that is used in PICA fragment shader emulation |
| 96 | struct TextureUnit { | 96 | struct TextureUnit { |
| 97 | GLuint texture_2d; // GL_TEXTURE_BINDING_2D | 97 | GLuint texture; // GL_TEXTURE_BINDING_2D |
| 98 | GLuint sampler; // GL_SAMPLER_BINDING | 98 | GLuint sampler; // GL_SAMPLER_BINDING |
| 99 | GLenum target; | ||
| 99 | struct { | 100 | struct { |
| 100 | GLint r; // GL_TEXTURE_SWIZZLE_R | 101 | GLint r; // GL_TEXTURE_SWIZZLE_R |
| 101 | GLint g; // GL_TEXTURE_SWIZZLE_G | 102 | GLint g; // GL_TEXTURE_SWIZZLE_G |
| @@ -104,7 +105,7 @@ public: | |||
| 104 | } swizzle; | 105 | } swizzle; |
| 105 | 106 | ||
| 106 | void Unbind() { | 107 | void Unbind() { |
| 107 | texture_2d = 0; | 108 | texture = 0; |
| 108 | swizzle.r = GL_RED; | 109 | swizzle.r = GL_RED; |
| 109 | swizzle.g = GL_GREEN; | 110 | swizzle.g = GL_GREEN; |
| 110 | swizzle.b = GL_BLUE; | 111 | swizzle.b = GL_BLUE; |
| @@ -114,6 +115,7 @@ public: | |||
| 114 | void Reset() { | 115 | void Reset() { |
| 115 | Unbind(); | 116 | Unbind(); |
| 116 | sampler = 0; | 117 | sampler = 0; |
| 118 | target = GL_TEXTURE_2D; | ||
| 117 | } | 119 | } |
| 118 | }; | 120 | }; |
| 119 | std::array<TextureUnit, 32> texture_units; | 121 | 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 | |||
| 177 | Memory::GetPointer(framebuffer_addr), | 177 | Memory::GetPointer(framebuffer_addr), |
| 178 | gl_framebuffer_data.data(), true); | 178 | gl_framebuffer_data.data(), true); |
| 179 | 179 | ||
| 180 | state.texture_units[0].texture_2d = screen_info.texture.resource.handle; | 180 | state.texture_units[0].texture = screen_info.texture.resource.handle; |
| 181 | state.Apply(); | 181 | state.Apply(); |
| 182 | 182 | ||
| 183 | glActiveTexture(GL_TEXTURE0); | 183 | glActiveTexture(GL_TEXTURE0); |
| @@ -194,7 +194,7 @@ void RendererOpenGL::LoadFBToScreenInfo(const Tegra::FramebufferConfig& framebuf | |||
| 194 | 194 | ||
| 195 | glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); | 195 | glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); |
| 196 | 196 | ||
| 197 | state.texture_units[0].texture_2d = 0; | 197 | state.texture_units[0].texture = 0; |
| 198 | state.Apply(); | 198 | state.Apply(); |
| 199 | } | 199 | } |
| 200 | } | 200 | } |
| @@ -205,7 +205,7 @@ void RendererOpenGL::LoadFBToScreenInfo(const Tegra::FramebufferConfig& framebuf | |||
| 205 | */ | 205 | */ |
| 206 | void RendererOpenGL::LoadColorToActiveGLTexture(u8 color_r, u8 color_g, u8 color_b, u8 color_a, | 206 | void RendererOpenGL::LoadColorToActiveGLTexture(u8 color_r, u8 color_g, u8 color_b, u8 color_a, |
| 207 | const TextureInfo& texture) { | 207 | const TextureInfo& texture) { |
| 208 | state.texture_units[0].texture_2d = texture.resource.handle; | 208 | state.texture_units[0].texture = texture.resource.handle; |
| 209 | state.Apply(); | 209 | state.Apply(); |
| 210 | 210 | ||
| 211 | glActiveTexture(GL_TEXTURE0); | 211 | glActiveTexture(GL_TEXTURE0); |
| @@ -214,7 +214,7 @@ void RendererOpenGL::LoadColorToActiveGLTexture(u8 color_r, u8 color_g, u8 color | |||
| 214 | // Update existing texture | 214 | // Update existing texture |
| 215 | glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, framebuffer_data); | 215 | glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, framebuffer_data); |
| 216 | 216 | ||
| 217 | state.texture_units[0].texture_2d = 0; | 217 | state.texture_units[0].texture = 0; |
| 218 | state.Apply(); | 218 | state.Apply(); |
| 219 | } | 219 | } |
| 220 | 220 | ||
| @@ -260,7 +260,7 @@ void RendererOpenGL::InitOpenGLObjects() { | |||
| 260 | // Allocation of storage is deferred until the first frame, when we | 260 | // Allocation of storage is deferred until the first frame, when we |
| 261 | // know the framebuffer size. | 261 | // know the framebuffer size. |
| 262 | 262 | ||
| 263 | state.texture_units[0].texture_2d = screen_info.texture.resource.handle; | 263 | state.texture_units[0].texture = screen_info.texture.resource.handle; |
| 264 | state.Apply(); | 264 | state.Apply(); |
| 265 | 265 | ||
| 266 | glActiveTexture(GL_TEXTURE0); | 266 | glActiveTexture(GL_TEXTURE0); |
| @@ -272,7 +272,7 @@ void RendererOpenGL::InitOpenGLObjects() { | |||
| 272 | 272 | ||
| 273 | screen_info.display_texture = screen_info.texture.resource.handle; | 273 | screen_info.display_texture = screen_info.texture.resource.handle; |
| 274 | 274 | ||
| 275 | state.texture_units[0].texture_2d = 0; | 275 | state.texture_units[0].texture = 0; |
| 276 | state.Apply(); | 276 | state.Apply(); |
| 277 | 277 | ||
| 278 | // Clear screen to black | 278 | // Clear screen to black |
| @@ -305,14 +305,14 @@ void RendererOpenGL::ConfigureFramebufferTexture(TextureInfo& texture, | |||
| 305 | UNREACHABLE(); | 305 | UNREACHABLE(); |
| 306 | } | 306 | } |
| 307 | 307 | ||
| 308 | state.texture_units[0].texture_2d = texture.resource.handle; | 308 | state.texture_units[0].texture = texture.resource.handle; |
| 309 | state.Apply(); | 309 | state.Apply(); |
| 310 | 310 | ||
| 311 | glActiveTexture(GL_TEXTURE0); | 311 | glActiveTexture(GL_TEXTURE0); |
| 312 | glTexImage2D(GL_TEXTURE_2D, 0, internal_format, texture.width, texture.height, 0, | 312 | glTexImage2D(GL_TEXTURE_2D, 0, internal_format, texture.width, texture.height, 0, |
| 313 | texture.gl_format, texture.gl_type, nullptr); | 313 | texture.gl_format, texture.gl_type, nullptr); |
| 314 | 314 | ||
| 315 | state.texture_units[0].texture_2d = 0; | 315 | state.texture_units[0].texture = 0; |
| 316 | state.Apply(); | 316 | state.Apply(); |
| 317 | } | 317 | } |
| 318 | 318 | ||
| @@ -354,14 +354,14 @@ void RendererOpenGL::DrawScreenTriangles(const ScreenInfo& screen_info, float x, | |||
| 354 | ScreenRectVertex(x + w, y + h, texcoords.bottom * scale_u, right * scale_v), | 354 | ScreenRectVertex(x + w, y + h, texcoords.bottom * scale_u, right * scale_v), |
| 355 | }}; | 355 | }}; |
| 356 | 356 | ||
| 357 | state.texture_units[0].texture_2d = screen_info.display_texture; | 357 | state.texture_units[0].texture = screen_info.display_texture; |
| 358 | state.texture_units[0].swizzle = {GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA}; | 358 | state.texture_units[0].swizzle = {GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA}; |
| 359 | state.Apply(); | 359 | state.Apply(); |
| 360 | 360 | ||
| 361 | glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(vertices), vertices.data()); | 361 | glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(vertices), vertices.data()); |
| 362 | glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); | 362 | glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); |
| 363 | 363 | ||
| 364 | state.texture_units[0].texture_2d = 0; | 364 | state.texture_units[0].texture = 0; |
| 365 | state.Apply(); | 365 | state.Apply(); |
| 366 | } | 366 | } |
| 367 | 367 | ||
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 { | |||
| 170 | BitField<0, 16, u32> width_minus_1; | 170 | BitField<0, 16, u32> width_minus_1; |
| 171 | BitField<23, 4, TextureType> texture_type; | 171 | BitField<23, 4, TextureType> texture_type; |
| 172 | }; | 172 | }; |
| 173 | u16 height_minus_1; | 173 | union { |
| 174 | INSERT_PADDING_BYTES(10); | 174 | BitField<0, 16, u32> height_minus_1; |
| 175 | BitField<16, 15, u32> depth_minus_1; | ||
| 176 | }; | ||
| 177 | |||
| 178 | INSERT_PADDING_BYTES(8); | ||
| 175 | 179 | ||
| 176 | GPUVAddr Address() const { | 180 | GPUVAddr Address() const { |
| 177 | return static_cast<GPUVAddr>((static_cast<GPUVAddr>(address_high) << 32) | address_low); | 181 | return static_cast<GPUVAddr>((static_cast<GPUVAddr>(address_high) << 32) | address_low); |
| @@ -192,6 +196,10 @@ struct TICEntry { | |||
| 192 | return height_minus_1 + 1; | 196 | return height_minus_1 + 1; |
| 193 | } | 197 | } |
| 194 | 198 | ||
| 199 | u32 Depth() const { | ||
| 200 | return depth_minus_1 + 1; | ||
| 201 | } | ||
| 202 | |||
| 195 | u32 BlockHeight() const { | 203 | u32 BlockHeight() const { |
| 196 | ASSERT(header_version == TICHeaderVersion::BlockLinear || | 204 | ASSERT(header_version == TICHeaderVersion::BlockLinear || |
| 197 | header_version == TICHeaderVersion::BlockLinearColorKey); | 205 | header_version == TICHeaderVersion::BlockLinearColorKey); |