diff options
Diffstat (limited to 'src/video_core/renderer_opengl')
-rw-r--r-- | src/video_core/renderer_opengl/gl_rasterizer.cpp | 12 | ||||
-rw-r--r-- | src/video_core/renderer_opengl/gl_rasterizer.h | 4 | ||||
-rw-r--r-- | src/video_core/renderer_opengl/gl_rasterizer_cache.cpp | 205 | ||||
-rw-r--r-- | src/video_core/renderer_opengl/gl_rasterizer_cache.h | 10 | ||||
-rw-r--r-- | src/video_core/renderer_opengl/gl_shader_decompiler.cpp | 97 |
5 files changed, 258 insertions, 70 deletions
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp index 974ca6a20..12d876120 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp @@ -778,15 +778,11 @@ void RasterizerOpenGL::FlushAndInvalidateRegion(VAddr addr, u64 size) { } bool RasterizerOpenGL::AccelerateSurfaceCopy(const Tegra::Engines::Fermi2D::Regs::Surface& src, - const Tegra::Engines::Fermi2D::Regs::Surface& dst) { + const Tegra::Engines::Fermi2D::Regs::Surface& dst, + const MathUtil::Rectangle<u32>& src_rect, + const MathUtil::Rectangle<u32>& dst_rect) { MICROPROFILE_SCOPE(OpenGL_Blits); - - if (Settings::values.use_accurate_gpu_emulation) { - // Skip the accelerated copy and perform a slow but more accurate copy - return false; - } - - res_cache.FermiCopySurface(src, dst); + res_cache.FermiCopySurface(src, dst, src_rect, dst_rect); return true; } diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h index f3b607f4d..258d62259 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.h +++ b/src/video_core/renderer_opengl/gl_rasterizer.h @@ -61,7 +61,9 @@ public: void InvalidateRegion(VAddr addr, u64 size) override; void FlushAndInvalidateRegion(VAddr addr, u64 size) override; bool AccelerateSurfaceCopy(const Tegra::Engines::Fermi2D::Regs::Surface& src, - const Tegra::Engines::Fermi2D::Regs::Surface& dst) override; + const Tegra::Engines::Fermi2D::Regs::Surface& dst, + const MathUtil::Rectangle<u32>& src_rect, + const MathUtil::Rectangle<u32>& dst_rect) override; bool AccelerateDisplay(const Tegra::FramebufferConfig& config, VAddr framebuffer_addr, u32 pixel_stride) override; bool AccelerateDrawBatch(bool is_indexed) override; diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp index a79eee03e..59f671048 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp @@ -125,6 +125,9 @@ std::size_t SurfaceParams::InnerMemorySize(bool force_gl, bool layer_only, params.width = Common::AlignUp(config.tic.Width(), GetCompressionFactor(params.pixel_format)); params.height = Common::AlignUp(config.tic.Height(), GetCompressionFactor(params.pixel_format)); + if (!params.is_tiled) { + params.pitch = config.tic.Pitch(); + } params.unaligned_height = config.tic.Height(); params.target = SurfaceTargetFromTextureType(config.tic.texture_type); params.identity = SurfaceClass::Uploaded; @@ -191,7 +194,13 @@ std::size_t SurfaceParams::InnerMemorySize(bool force_gl, bool layer_only, config.format == Tegra::RenderTargetFormat::RGBA8_SRGB; params.component_type = ComponentTypeFromRenderTarget(config.format); params.type = GetFormatType(params.pixel_format); - params.width = config.width; + if (params.is_tiled) { + params.width = config.width; + } else { + params.pitch = config.width; + const u32 bpp = params.GetFormatBpp() / 8; + params.width = params.pitch / bpp; + } params.height = config.height; params.unaligned_height = config.height; params.target = SurfaceTarget::Texture2D; @@ -428,7 +437,8 @@ void SwizzleFunc(const MortonSwizzleMode& mode, const SurfaceParams& params, } } -static void FastCopySurface(const Surface& src_surface, const Surface& dst_surface) { +void RasterizerCacheOpenGL::FastCopySurface(const Surface& src_surface, + const Surface& dst_surface) { const auto& src_params{src_surface->GetSurfaceParams()}; const auto& dst_params{dst_surface->GetSurfaceParams()}; @@ -438,12 +448,15 @@ static void FastCopySurface(const Surface& src_surface, const Surface& dst_surfa glCopyImageSubData(src_surface->Texture().handle, SurfaceTargetToGL(src_params.target), 0, 0, 0, 0, dst_surface->Texture().handle, SurfaceTargetToGL(dst_params.target), 0, 0, 0, 0, width, height, 1); + + dst_surface->MarkAsModified(true, *this); } MICROPROFILE_DEFINE(OpenGL_CopySurface, "OpenGL", "CopySurface", MP_RGB(128, 192, 64)); -static void CopySurface(const Surface& src_surface, const Surface& dst_surface, - const GLuint copy_pbo_handle, const GLenum src_attachment = 0, - const GLenum dst_attachment = 0, const std::size_t cubemap_face = 0) { +void RasterizerCacheOpenGL::CopySurface(const Surface& src_surface, const Surface& dst_surface, + const GLuint copy_pbo_handle, const GLenum src_attachment, + const GLenum dst_attachment, + const std::size_t cubemap_face) { MICROPROFILE_SCOPE(OpenGL_CopySurface); ASSERT_MSG(dst_attachment == 0, "Unimplemented"); @@ -523,6 +536,8 @@ static void CopySurface(const Surface& src_surface, const Surface& dst_surface, } glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); } + + dst_surface->MarkAsModified(true, *this); } CachedSurface::CachedSurface(const SurfaceParams& params) @@ -688,9 +703,20 @@ void CachedSurface::LoadGLBuffer() { for (u32 i = 0; i < params.max_mip_level; i++) SwizzleFunc(MortonSwizzleMode::MortonToLinear, params, gl_buffer[i], i); } else { - const auto texture_src_data{Memory::GetPointer(params.addr)}; - const auto texture_src_data_end{texture_src_data + params.size_in_bytes_gl}; - gl_buffer[0].assign(texture_src_data, texture_src_data_end); + const u32 bpp = params.GetFormatBpp() / 8; + const u32 copy_size = params.width * bpp; + if (params.pitch == copy_size) { + std::memcpy(gl_buffer[0].data(), Memory::GetPointer(params.addr), + params.size_in_bytes_gl); + } else { + const u8* start = Memory::GetPointer(params.addr); + u8* write_to = gl_buffer[0].data(); + for (u32 h = params.height; h > 0; h--) { + std::memcpy(write_to, start, copy_size); + start += params.pitch; + write_to += copy_size; + } + } } for (u32 i = 0; i < params.max_mip_level; i++) { ConvertFormatAsNeeded_LoadGLBuffer(gl_buffer[i], params.pixel_format, params.MipWidth(i), @@ -727,7 +753,19 @@ void CachedSurface::FlushGLBuffer() { SwizzleFunc(MortonSwizzleMode::LinearToMorton, params, gl_buffer[0], 0); } else { - std::memcpy(Memory::GetPointer(GetAddr()), gl_buffer[0].data(), GetSizeInBytes()); + const u32 bpp = params.GetFormatBpp() / 8; + const u32 copy_size = params.width * bpp; + if (params.pitch == copy_size) { + std::memcpy(Memory::GetPointer(params.addr), gl_buffer[0].data(), GetSizeInBytes()); + } else { + u8* start = Memory::GetPointer(params.addr); + const u8* read_to = gl_buffer[0].data(); + for (u32 h = params.height; h > 0; h--) { + std::memcpy(start, read_to, copy_size); + start += params.pitch; + read_to += copy_size; + } + } } } @@ -853,8 +891,8 @@ void CachedSurface::EnsureTextureView() { constexpr GLuint min_level = 0; glGenTextures(1, &texture_view.handle); - glTextureView(texture_view.handle, target, texture.handle, gl_internal_format, 0, - params.max_mip_level, 0, 1); + glTextureView(texture_view.handle, target, texture.handle, gl_internal_format, min_level, + params.max_mip_level, min_layer, num_layers); ApplyTextureDefaults(texture_view.handle, params.max_mip_level); glTextureParameteriv(texture_view.handle, GL_TEXTURE_SWIZZLE_RGBA, reinterpret_cast<const GLint*>(swizzle.data())); @@ -1019,26 +1057,161 @@ void RasterizerCacheOpenGL::FastLayeredCopySurface(const Surface& src_surface, } address += layer_size; } + + dst_surface->MarkAsModified(true, *this); +} + +static bool BlitSurface(const Surface& src_surface, const Surface& dst_surface, + const MathUtil::Rectangle<u32>& src_rect, + const MathUtil::Rectangle<u32>& dst_rect, GLuint read_fb_handle, + GLuint draw_fb_handle, GLenum src_attachment = 0, GLenum dst_attachment = 0, + std::size_t cubemap_face = 0) { + + const auto& src_params{src_surface->GetSurfaceParams()}; + const auto& dst_params{dst_surface->GetSurfaceParams()}; + + OpenGLState prev_state{OpenGLState::GetCurState()}; + SCOPE_EXIT({ prev_state.Apply(); }); + + OpenGLState state; + state.draw.read_framebuffer = read_fb_handle; + state.draw.draw_framebuffer = draw_fb_handle; + state.Apply(); + + u32 buffers{}; + + if (src_params.type == SurfaceType::ColorTexture) { + switch (src_params.target) { + case SurfaceTarget::Texture2D: + glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + src_attachment, + GL_TEXTURE_2D, src_surface->Texture().handle, 0); + glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, + 0, 0); + break; + case SurfaceTarget::TextureCubemap: + glFramebufferTexture2D( + GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + src_attachment, + static_cast<GLenum>(GL_TEXTURE_CUBE_MAP_POSITIVE_X + cubemap_face), + src_surface->Texture().handle, 0); + glFramebufferTexture2D( + GL_READ_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, + static_cast<GLenum>(GL_TEXTURE_CUBE_MAP_POSITIVE_X + cubemap_face), 0, 0); + break; + case SurfaceTarget::Texture2DArray: + glFramebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + src_attachment, + src_surface->Texture().handle, 0, 0); + glFramebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, 0, 0, 0); + break; + case SurfaceTarget::Texture3D: + glFramebufferTexture3D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + src_attachment, + SurfaceTargetToGL(src_params.target), + src_surface->Texture().handle, 0, 0); + glFramebufferTexture3D(GL_READ_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, + SurfaceTargetToGL(src_params.target), 0, 0, 0); + break; + default: + glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + src_attachment, + GL_TEXTURE_2D, src_surface->Texture().handle, 0); + glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, + 0, 0); + break; + } + + switch (dst_params.target) { + case SurfaceTarget::Texture2D: + glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + dst_attachment, + GL_TEXTURE_2D, dst_surface->Texture().handle, 0); + glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, + 0, 0); + break; + case SurfaceTarget::TextureCubemap: + glFramebufferTexture2D( + GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + dst_attachment, + static_cast<GLenum>(GL_TEXTURE_CUBE_MAP_POSITIVE_X + cubemap_face), + dst_surface->Texture().handle, 0); + glFramebufferTexture2D( + GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, + static_cast<GLenum>(GL_TEXTURE_CUBE_MAP_POSITIVE_X + cubemap_face), 0, 0); + break; + case SurfaceTarget::Texture2DArray: + glFramebufferTextureLayer(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + dst_attachment, + dst_surface->Texture().handle, 0, 0); + glFramebufferTextureLayer(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, 0, 0, 0); + break; + + case SurfaceTarget::Texture3D: + glFramebufferTexture3D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + dst_attachment, + SurfaceTargetToGL(dst_params.target), + dst_surface->Texture().handle, 0, 0); + glFramebufferTexture3D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, + SurfaceTargetToGL(dst_params.target), 0, 0, 0); + break; + default: + glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + dst_attachment, + GL_TEXTURE_2D, dst_surface->Texture().handle, 0); + glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, + 0, 0); + break; + } + + buffers = GL_COLOR_BUFFER_BIT; + } else if (src_params.type == SurfaceType::Depth) { + glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + src_attachment, + GL_TEXTURE_2D, 0, 0); + glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, + src_surface->Texture().handle, 0); + glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0, 0); + + glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + dst_attachment, + GL_TEXTURE_2D, 0, 0); + glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, + dst_surface->Texture().handle, 0); + glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0, 0); + + buffers = GL_DEPTH_BUFFER_BIT; + } else if (src_params.type == SurfaceType::DepthStencil) { + glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + src_attachment, + GL_TEXTURE_2D, 0, 0); + glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, + src_surface->Texture().handle, 0); + + glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + dst_attachment, + GL_TEXTURE_2D, 0, 0); + glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, + dst_surface->Texture().handle, 0); + + buffers = GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT; + } + + glBlitFramebuffer(src_rect.left, src_rect.top, src_rect.right, src_rect.bottom, dst_rect.left, + dst_rect.top, dst_rect.right, dst_rect.bottom, buffers, + buffers == GL_COLOR_BUFFER_BIT ? GL_LINEAR : GL_NEAREST); + + return true; } void RasterizerCacheOpenGL::FermiCopySurface( const Tegra::Engines::Fermi2D::Regs::Surface& src_config, - const Tegra::Engines::Fermi2D::Regs::Surface& dst_config) { + const Tegra::Engines::Fermi2D::Regs::Surface& dst_config, + const MathUtil::Rectangle<u32>& src_rect, const MathUtil::Rectangle<u32>& dst_rect) { const auto& src_params = SurfaceParams::CreateForFermiCopySurface(src_config); const auto& dst_params = SurfaceParams::CreateForFermiCopySurface(dst_config); - ASSERT(src_params.width == dst_params.width); - ASSERT(src_params.height == dst_params.height); ASSERT(src_params.pixel_format == dst_params.pixel_format); ASSERT(src_params.block_height == dst_params.block_height); ASSERT(src_params.is_tiled == dst_params.is_tiled); ASSERT(src_params.depth == dst_params.depth); - ASSERT(src_params.depth == 1); // Currently, FastCopySurface only works with 2D surfaces ASSERT(src_params.target == dst_params.target); ASSERT(src_params.rt.index == dst_params.rt.index); - FastCopySurface(GetSurface(src_params, true), GetSurface(dst_params, false)); + auto src_surface = GetSurface(src_params, true); + auto dst_surface = GetSurface(dst_params, true); + + BlitSurface(src_surface, dst_surface, src_rect, dst_rect, read_framebuffer.handle, + draw_framebuffer.handle); + + dst_surface->MarkAsModified(true, *this); } void RasterizerCacheOpenGL::AccurateCopySurface(const Surface& src_surface, diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.h b/src/video_core/renderer_opengl/gl_rasterizer_cache.h index 490b8252e..b81882d04 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer_cache.h +++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.h @@ -8,6 +8,7 @@ #include <map> #include <memory> #include <string> +#include <unordered_set> #include <vector> #include "common/alignment.h" @@ -272,6 +273,7 @@ struct SurfaceParams { u32 height; u32 depth; u32 unaligned_height; + u32 pitch; SurfaceTarget target; SurfaceClass identity; u32 max_mip_level; @@ -421,7 +423,9 @@ public: /// Copies the contents of one surface to another void FermiCopySurface(const Tegra::Engines::Fermi2D::Regs::Surface& src_config, - const Tegra::Engines::Fermi2D::Regs::Surface& dst_config); + const Tegra::Engines::Fermi2D::Regs::Surface& dst_config, + const MathUtil::Rectangle<u32>& src_rect, + const MathUtil::Rectangle<u32>& dst_rect); private: void LoadSurface(const Surface& surface); @@ -442,6 +446,10 @@ private: /// Performs a slow but accurate surface copy, flushing to RAM and reinterpreting the data void AccurateCopySurface(const Surface& src_surface, const Surface& dst_surface); void FastLayeredCopySurface(const Surface& src_surface, const Surface& dst_surface); + void FastCopySurface(const Surface& src_surface, const Surface& dst_surface); + void CopySurface(const Surface& src_surface, const Surface& dst_surface, + const GLuint copy_pbo_handle, const GLenum src_attachment = 0, + const GLenum dst_attachment = 0, const std::size_t cubemap_face = 0); /// The surface reserve is a "backup" cache, this is where we put unique surfaces that have /// previously been used. This is to prevent surfaces from being constantly created and diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp index 70e124dc4..b39bb4843 100644 --- a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp +++ b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp @@ -719,45 +719,51 @@ private: constexpr std::array<const char*, 4> coord_constructors = {"float", "vec2", "vec3", "vec4"}; const auto meta = std::get_if<MetaTexture>(&operation.GetMeta()); - const auto count = static_cast<u32>(operation.GetOperandsCount()); ASSERT(meta); + const auto count = static_cast<u32>(operation.GetOperandsCount()); + const bool has_array = meta->sampler.IsArray(); + const bool has_shadow = meta->sampler.IsShadow(); + std::string expr = func; expr += '('; expr += GetSampler(meta->sampler); expr += ", "; - expr += coord_constructors[meta->coords_count - 1]; + expr += coord_constructors.at(count + (has_array ? 1 : 0) + (has_shadow ? 1 : 0) - 1); expr += '('; for (u32 i = 0; i < count; ++i) { - const bool is_extra = i >= meta->coords_count; - const bool is_array = i == meta->array_index; - - std::string operand = [&]() { - if (is_extra && is_extra_int) { - if (const auto immediate = std::get_if<ImmediateNode>(operation[i])) { - return std::to_string(static_cast<s32>(immediate->GetValue())); - } else { - return "ftoi(" + Visit(operation[i]) + ')'; - } - } else { - return Visit(operation[i]); - } - }(); - if (is_array) { - ASSERT(!is_extra); - operand = "float(ftoi(" + operand + "))"; - } - - expr += operand; + expr += Visit(operation[i]); - if (i + 1 == meta->coords_count) { - expr += ')'; - } - if (i + 1 < count) { + const u32 next = i + 1; + if (next < count || has_array || has_shadow) + expr += ", "; + } + if (has_array) { + expr += "float(ftoi(" + Visit(meta->array) + "))"; + } + if (has_shadow) { + if (has_array) expr += ", "; + expr += Visit(meta->depth_compare); + } + expr += ')'; + + for (const Node extra : meta->extras) { + expr += ", "; + if (is_extra_int) { + if (const auto immediate = std::get_if<ImmediateNode>(extra)) { + // Inline the string as an immediate integer in GLSL (some extra arguments are + // required to be constant) + expr += std::to_string(static_cast<s32>(immediate->GetValue())); + } else { + expr += "ftoi(" + Visit(extra) + ')'; + } + } else { + expr += Visit(extra); } } + expr += ')'; return expr; } @@ -1134,7 +1140,7 @@ private: Type::HalfFloat); } - std::string F4Texture(Operation operation) { + std::string Texture(Operation operation) { const auto meta = std::get_if<MetaTexture>(&operation.GetMeta()); ASSERT(meta); @@ -1145,7 +1151,7 @@ private: return expr + GetSwizzle(meta->element); } - std::string F4TextureLod(Operation operation) { + std::string TextureLod(Operation operation) { const auto meta = std::get_if<MetaTexture>(&operation.GetMeta()); ASSERT(meta); @@ -1156,7 +1162,7 @@ private: return expr + GetSwizzle(meta->element); } - std::string F4TextureGather(Operation operation) { + std::string TextureGather(Operation operation) { const auto meta = std::get_if<MetaTexture>(&operation.GetMeta()); ASSERT(meta); @@ -1164,7 +1170,7 @@ private: GetSwizzle(meta->element); } - std::string F4TextureQueryDimensions(Operation operation) { + std::string TextureQueryDimensions(Operation operation) { const auto meta = std::get_if<MetaTexture>(&operation.GetMeta()); ASSERT(meta); @@ -1184,7 +1190,7 @@ private: return "0"; } - std::string F4TextureQueryLod(Operation operation) { + std::string TextureQueryLod(Operation operation) { const auto meta = std::get_if<MetaTexture>(&operation.GetMeta()); ASSERT(meta); @@ -1195,29 +1201,32 @@ private: return "0"; } - std::string F4TexelFetch(Operation operation) { + std::string TexelFetch(Operation operation) { constexpr std::array<const char*, 4> constructors = {"int", "ivec2", "ivec3", "ivec4"}; const auto meta = std::get_if<MetaTexture>(&operation.GetMeta()); - const auto count = static_cast<u32>(operation.GetOperandsCount()); ASSERT(meta); + UNIMPLEMENTED_IF(meta->sampler.IsArray()); + UNIMPLEMENTED_IF(!meta->extras.empty()); + + const auto count = static_cast<u32>(operation.GetOperandsCount()); std::string expr = "texelFetch("; expr += GetSampler(meta->sampler); expr += ", "; - expr += constructors[meta->coords_count - 1]; + expr += constructors.at(count - 1); expr += '('; for (u32 i = 0; i < count; ++i) { expr += VisitOperand(operation, i, Type::Int); - if (i + 1 == meta->coords_count) { + const u32 next = i + 1; + if (next == count) expr += ')'; - } - if (i + 1 < count) { + if (next < count) expr += ", "; - } } expr += ')'; + return expr + GetSwizzle(meta->element); } @@ -1454,12 +1463,12 @@ private: &GLSLDecompiler::Logical2HNotEqual, &GLSLDecompiler::Logical2HGreaterEqual, - &GLSLDecompiler::F4Texture, - &GLSLDecompiler::F4TextureLod, - &GLSLDecompiler::F4TextureGather, - &GLSLDecompiler::F4TextureQueryDimensions, - &GLSLDecompiler::F4TextureQueryLod, - &GLSLDecompiler::F4TexelFetch, + &GLSLDecompiler::Texture, + &GLSLDecompiler::TextureLod, + &GLSLDecompiler::TextureGather, + &GLSLDecompiler::TextureQueryDimensions, + &GLSLDecompiler::TextureQueryLod, + &GLSLDecompiler::TexelFetch, &GLSLDecompiler::Branch, &GLSLDecompiler::PushFlowStack, |