diff options
-rw-r--r-- | src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp | 6 | ||||
-rw-r--r-- | src/video_core/engines/fermi_2d.cpp | 62 | ||||
-rw-r--r-- | src/video_core/engines/fermi_2d.h | 29 | ||||
-rw-r--r-- | src/video_core/engines/shader_bytecode.h | 2 | ||||
-rw-r--r-- | src/video_core/rasterizer_interface.h | 4 | ||||
-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 | ||||
-rw-r--r-- | src/video_core/shader/decode/arithmetic_integer.cpp | 4 | ||||
-rw-r--r-- | src/video_core/shader/decode/conversion.cpp | 6 | ||||
-rw-r--r-- | src/video_core/shader/decode/memory.cpp | 157 | ||||
-rw-r--r-- | src/video_core/shader/shader_ir.h | 22 |
14 files changed, 379 insertions, 241 deletions
diff --git a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp index 92acc57b1..21ccfe1f8 100644 --- a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp +++ b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp @@ -25,9 +25,9 @@ void nvdisp_disp0::flip(u32 buffer_handle, u32 offset, u32 format, u32 width, u3 u32 stride, NVFlinger::BufferQueue::BufferTransformFlags transform, const MathUtil::Rectangle<int>& crop_rect) { VAddr addr = nvmap_dev->GetObjectAddress(buffer_handle); - LOG_WARNING(Service, - "Drawing from address {:X} offset {:08X} Width {} Height {} Stride {} Format {}", - addr, offset, width, height, stride, format); + LOG_TRACE(Service, + "Drawing from address {:X} offset {:08X} Width {} Height {} Stride {} Format {}", + addr, offset, width, height, stride, format); using PixelFormat = Tegra::FramebufferConfig::PixelFormat; const Tegra::FramebufferConfig framebuffer{ diff --git a/src/video_core/engines/fermi_2d.cpp b/src/video_core/engines/fermi_2d.cpp index 9f1533263..ec1a57226 100644 --- a/src/video_core/engines/fermi_2d.cpp +++ b/src/video_core/engines/fermi_2d.cpp @@ -21,7 +21,9 @@ void Fermi2D::CallMethod(const GPU::MethodCall& method_call) { regs.reg_array[method_call.method] = method_call.argument; switch (method_call.method) { - case FERMI2D_REG_INDEX(trigger): { + // Trigger the surface copy on the last register write. This is blit_src_y, but this is 64-bit, + // so trigger on the second 32-bit write. + case FERMI2D_REG_INDEX(blit_src_y) + 1: { HandleSurfaceCopy(); break; } @@ -32,57 +34,23 @@ void Fermi2D::HandleSurfaceCopy() { LOG_WARNING(HW_GPU, "Requested a surface copy with operation {}", static_cast<u32>(regs.operation)); - const GPUVAddr source = regs.src.Address(); - const GPUVAddr dest = regs.dst.Address(); - - // TODO(Subv): Only same-format and same-size copies are allowed for now. - ASSERT(regs.src.format == regs.dst.format); - ASSERT(regs.src.width * regs.src.height == regs.dst.width * regs.dst.height); - // TODO(Subv): Only raw copies are implemented. ASSERT(regs.operation == Regs::Operation::SrcCopy); - const auto source_cpu = memory_manager.GpuToCpuAddress(source); - const auto dest_cpu = memory_manager.GpuToCpuAddress(dest); - ASSERT_MSG(source_cpu, "Invalid source GPU address"); - ASSERT_MSG(dest_cpu, "Invalid destination GPU address"); - - u32 src_bytes_per_pixel = RenderTargetBytesPerPixel(regs.src.format); - u32 dst_bytes_per_pixel = RenderTargetBytesPerPixel(regs.dst.format); - - if (!rasterizer.AccelerateSurfaceCopy(regs.src, regs.dst)) { - // All copies here update the main memory, so mark all rasterizer states as invalid. - Core::System::GetInstance().GPU().Maxwell3D().dirty_flags.OnMemoryWrite(); + const u32 src_blit_x1{static_cast<u32>(regs.blit_src_x >> 32)}; + const u32 src_blit_y1{static_cast<u32>(regs.blit_src_y >> 32)}; + const u32 src_blit_x2{ + static_cast<u32>((regs.blit_src_x + (regs.blit_dst_width * regs.blit_du_dx)) >> 32)}; + const u32 src_blit_y2{ + static_cast<u32>((regs.blit_src_y + (regs.blit_dst_height * regs.blit_dv_dy)) >> 32)}; - rasterizer.FlushRegion(*source_cpu, src_bytes_per_pixel * regs.src.width * regs.src.height); - // We have to invalidate the destination region to evict any outdated surfaces from the - // cache. We do this before actually writing the new data because the destination address - // might contain a dirty surface that will have to be written back to memory. - rasterizer.InvalidateRegion(*dest_cpu, - dst_bytes_per_pixel * regs.dst.width * regs.dst.height); + const MathUtil::Rectangle<u32> src_rect{src_blit_x1, src_blit_y1, src_blit_x2, src_blit_y2}; + const MathUtil::Rectangle<u32> dst_rect{regs.blit_dst_x, regs.blit_dst_y, + regs.blit_dst_x + regs.blit_dst_width, + regs.blit_dst_y + regs.blit_dst_height}; - if (regs.src.linear == regs.dst.linear) { - // If the input layout and the output layout are the same, just perform a raw copy. - ASSERT(regs.src.BlockHeight() == regs.dst.BlockHeight()); - Memory::CopyBlock(*dest_cpu, *source_cpu, - src_bytes_per_pixel * regs.dst.width * regs.dst.height); - return; - } - u8* src_buffer = Memory::GetPointer(*source_cpu); - u8* dst_buffer = Memory::GetPointer(*dest_cpu); - if (!regs.src.linear && regs.dst.linear) { - // If the input is tiled and the output is linear, deswizzle the input and copy it over. - Texture::CopySwizzledData(regs.src.width, regs.src.height, regs.src.depth, - src_bytes_per_pixel, dst_bytes_per_pixel, src_buffer, - dst_buffer, true, regs.src.BlockHeight(), - regs.src.BlockDepth(), 0); - } else { - // If the input is linear and the output is tiled, swizzle the input and copy it over. - Texture::CopySwizzledData(regs.src.width, regs.src.height, regs.src.depth, - src_bytes_per_pixel, dst_bytes_per_pixel, dst_buffer, - src_buffer, false, regs.dst.BlockHeight(), - regs.dst.BlockDepth(), 0); - } + if (!rasterizer.AccelerateSurfaceCopy(regs.src, regs.dst, src_rect, dst_rect)) { + UNIMPLEMENTED(); } } diff --git a/src/video_core/engines/fermi_2d.h b/src/video_core/engines/fermi_2d.h index 50009bf75..c69f74cc5 100644 --- a/src/video_core/engines/fermi_2d.h +++ b/src/video_core/engines/fermi_2d.h @@ -94,12 +94,22 @@ public: Operation operation; - INSERT_PADDING_WORDS(0x9); + INSERT_PADDING_WORDS(0x177); - // TODO(Subv): This is only a guess. - u32 trigger; + u32 blit_control; - INSERT_PADDING_WORDS(0x1A3); + INSERT_PADDING_WORDS(0x8); + + u32 blit_dst_x; + u32 blit_dst_y; + u32 blit_dst_width; + u32 blit_dst_height; + u64 blit_du_dx; + u64 blit_dv_dy; + u64 blit_src_x; + u64 blit_src_y; + + INSERT_PADDING_WORDS(0x21); }; std::array<u32, NUM_REGS> reg_array; }; @@ -122,7 +132,16 @@ private: ASSERT_REG_POSITION(dst, 0x80); ASSERT_REG_POSITION(src, 0x8C); ASSERT_REG_POSITION(operation, 0xAB); -ASSERT_REG_POSITION(trigger, 0xB5); +ASSERT_REG_POSITION(blit_control, 0x223); +ASSERT_REG_POSITION(blit_dst_x, 0x22c); +ASSERT_REG_POSITION(blit_dst_y, 0x22d); +ASSERT_REG_POSITION(blit_dst_width, 0x22e); +ASSERT_REG_POSITION(blit_dst_height, 0x22f); +ASSERT_REG_POSITION(blit_du_dx, 0x230); +ASSERT_REG_POSITION(blit_dv_dy, 0x232); +ASSERT_REG_POSITION(blit_src_x, 0x234); +ASSERT_REG_POSITION(blit_src_y, 0x236); + #undef ASSERT_REG_POSITION } // namespace Tegra::Engines diff --git a/src/video_core/engines/shader_bytecode.h b/src/video_core/engines/shader_bytecode.h index 269df9437..1f425f90b 100644 --- a/src/video_core/engines/shader_bytecode.h +++ b/src/video_core/engines/shader_bytecode.h @@ -186,7 +186,7 @@ enum class SubOp : u64 { }; enum class F2iRoundingOp : u64 { - None = 0, + RoundEven = 0, Floor = 1, Ceil = 2, Trunc = 3, diff --git a/src/video_core/rasterizer_interface.h b/src/video_core/rasterizer_interface.h index 77da135a0..b2a223705 100644 --- a/src/video_core/rasterizer_interface.h +++ b/src/video_core/rasterizer_interface.h @@ -46,7 +46,9 @@ public: /// Attempt to use a faster method to perform a surface copy virtual bool 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) { return false; } 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, diff --git a/src/video_core/shader/decode/arithmetic_integer.cpp b/src/video_core/shader/decode/arithmetic_integer.cpp index 38bb692d6..9fd4b273e 100644 --- a/src/video_core/shader/decode/arithmetic_integer.cpp +++ b/src/video_core/shader/decode/arithmetic_integer.cpp @@ -41,7 +41,7 @@ u32 ShaderIR::DecodeArithmeticInteger(NodeBlock& bb, u32 pc) { const Node value = Operation(OperationCode::IAdd, PRECISE, op_a, op_b); - SetInternalFlagsFromInteger(bb, value, instr.op_32.generates_cc); + SetInternalFlagsFromInteger(bb, value, instr.generates_cc); SetRegister(bb, instr.gpr0, value); break; } @@ -284,4 +284,4 @@ void ShaderIR::WriteLop3Instruction(NodeBlock& bb, Register dest, Node op_a, Nod SetRegister(bb, dest, value); } -} // namespace VideoCommon::Shader
\ No newline at end of file +} // namespace VideoCommon::Shader diff --git a/src/video_core/shader/decode/conversion.cpp b/src/video_core/shader/decode/conversion.cpp index a992f73f8..55a6fbbf2 100644 --- a/src/video_core/shader/decode/conversion.cpp +++ b/src/video_core/shader/decode/conversion.cpp @@ -118,8 +118,8 @@ u32 ShaderIR::DecodeConversion(NodeBlock& bb, u32 pc) { value = [&]() { switch (instr.conversion.f2i.rounding) { - case Tegra::Shader::F2iRoundingOp::None: - return value; + case Tegra::Shader::F2iRoundingOp::RoundEven: + return Operation(OperationCode::FRoundEven, PRECISE, value); case Tegra::Shader::F2iRoundingOp::Floor: return Operation(OperationCode::FFloor, PRECISE, value); case Tegra::Shader::F2iRoundingOp::Ceil: @@ -146,4 +146,4 @@ u32 ShaderIR::DecodeConversion(NodeBlock& bb, u32 pc) { return pc; } -} // namespace VideoCommon::Shader
\ No newline at end of file +} // namespace VideoCommon::Shader diff --git a/src/video_core/shader/decode/memory.cpp b/src/video_core/shader/decode/memory.cpp index e006f8138..523421794 100644 --- a/src/video_core/shader/decode/memory.cpp +++ b/src/video_core/shader/decode/memory.cpp @@ -306,7 +306,6 @@ u32 ShaderIR::DecodeMemory(NodeBlock& bb, u32 pc) { case OpCode::Id::TLD4S: { UNIMPLEMENTED_IF_MSG(instr.tld4s.UsesMiscMode(TextureMiscMode::AOFFI), "AOFFI is not implemented"); - if (instr.tld4s.UsesMiscMode(TextureMiscMode::NODEP)) { LOG_WARNING(HW_GPU, "TLD4S.NODEP implementation is incomplete"); } @@ -315,9 +314,8 @@ u32 ShaderIR::DecodeMemory(NodeBlock& bb, u32 pc) { const Node op_a = GetRegister(instr.gpr8); const Node op_b = GetRegister(instr.gpr20); - std::vector<Node> coords; - // TODO(Subv): Figure out how the sampler type is encoded in the TLD4S instruction. + std::vector<Node> coords; if (depth_compare) { // Note: TLD4S coordinate encoding works just like TEXS's const Node op_y = GetRegister(instr.gpr8.Value() + 1); @@ -328,18 +326,17 @@ u32 ShaderIR::DecodeMemory(NodeBlock& bb, u32 pc) { coords.push_back(op_a); coords.push_back(op_b); } - const auto num_coords = static_cast<u32>(coords.size()); - coords.push_back(Immediate(static_cast<u32>(instr.tld4s.component))); + std::vector<Node> extras; + extras.push_back(Immediate(static_cast<u32>(instr.tld4s.component))); const auto& sampler = GetSampler(instr.sampler, TextureType::Texture2D, false, depth_compare); Node4 values; for (u32 element = 0; element < values.size(); ++element) { - auto params = coords; - MetaTexture meta{sampler, element, num_coords}; - values[element] = - Operation(OperationCode::F4TextureGather, std::move(meta), std::move(params)); + auto coords_copy = coords; + MetaTexture meta{sampler, {}, {}, extras, element}; + values[element] = Operation(OperationCode::TextureGather, meta, std::move(coords_copy)); } WriteTexsInstructionFloat(bb, instr, values); @@ -360,12 +357,13 @@ u32 ShaderIR::DecodeMemory(NodeBlock& bb, u32 pc) { switch (instr.txq.query_type) { case Tegra::Shader::TextureQueryType::Dimension: { for (u32 element = 0; element < 4; ++element) { - if (instr.txq.IsComponentEnabled(element)) { - MetaTexture meta{sampler, element}; - const Node value = Operation(OperationCode::F4TextureQueryDimensions, - std::move(meta), GetRegister(instr.gpr8)); - SetTemporal(bb, indexer++, value); + if (!instr.txq.IsComponentEnabled(element)) { + continue; } + MetaTexture meta{sampler, {}, {}, {}, element}; + const Node value = + Operation(OperationCode::TextureQueryDimensions, meta, GetRegister(instr.gpr8)); + SetTemporal(bb, indexer++, value); } for (u32 i = 0; i < indexer; ++i) { SetRegister(bb, instr.gpr0.Value() + i, GetTemporal(i)); @@ -412,9 +410,8 @@ u32 ShaderIR::DecodeMemory(NodeBlock& bb, u32 pc) { for (u32 element = 0; element < 2; ++element) { auto params = coords; - MetaTexture meta_texture{sampler, element, static_cast<u32>(coords.size())}; - const Node value = - Operation(OperationCode::F4TextureQueryLod, meta_texture, std::move(params)); + MetaTexture meta{sampler, {}, {}, {}, element}; + const Node value = Operation(OperationCode::TextureQueryLod, meta, std::move(params)); SetTemporal(bb, element, value); } for (u32 element = 0; element < 2; ++element) { @@ -535,15 +532,16 @@ void ShaderIR::WriteTexsInstructionHalfFloat(NodeBlock& bb, Instruction instr, } Node4 ShaderIR::GetTextureCode(Instruction instr, TextureType texture_type, - TextureProcessMode process_mode, bool depth_compare, bool is_array, - std::size_t array_offset, std::size_t bias_offset, - std::vector<Node>&& coords) { - UNIMPLEMENTED_IF_MSG( - (texture_type == TextureType::Texture3D && (is_array || depth_compare)) || - (texture_type == TextureType::TextureCube && is_array && depth_compare), - "This method is not supported."); + TextureProcessMode process_mode, std::vector<Node> coords, + Node array, Node depth_compare, u32 bias_offset) { + const bool is_array = array; + const bool is_shadow = depth_compare; - const auto& sampler = GetSampler(instr.sampler, texture_type, is_array, depth_compare); + UNIMPLEMENTED_IF_MSG((texture_type == TextureType::Texture3D && (is_array || is_shadow)) || + (texture_type == TextureType::TextureCube && is_array && is_shadow), + "This method is not supported."); + + const auto& sampler = GetSampler(instr.sampler, texture_type, is_array, is_shadow); const bool lod_needed = process_mode == TextureProcessMode::LZ || process_mode == TextureProcessMode::LL || @@ -552,35 +550,30 @@ Node4 ShaderIR::GetTextureCode(Instruction instr, TextureType texture_type, // LOD selection (either via bias or explicit textureLod) not supported in GL for // sampler2DArrayShadow and samplerCubeArrayShadow. const bool gl_lod_supported = - !((texture_type == Tegra::Shader::TextureType::Texture2D && is_array && depth_compare) || - (texture_type == Tegra::Shader::TextureType::TextureCube && is_array && depth_compare)); + !((texture_type == Tegra::Shader::TextureType::Texture2D && is_array && is_shadow) || + (texture_type == Tegra::Shader::TextureType::TextureCube && is_array && is_shadow)); const OperationCode read_method = - lod_needed && gl_lod_supported ? OperationCode::F4TextureLod : OperationCode::F4Texture; + lod_needed && gl_lod_supported ? OperationCode::TextureLod : OperationCode::Texture; UNIMPLEMENTED_IF(process_mode != TextureProcessMode::None && !gl_lod_supported); - std::optional<u32> array_offset_value; - if (is_array) - array_offset_value = static_cast<u32>(array_offset); - - const auto coords_count = static_cast<u32>(coords.size()); - + std::vector<Node> extras; if (process_mode != TextureProcessMode::None && gl_lod_supported) { if (process_mode == TextureProcessMode::LZ) { - coords.push_back(Immediate(0.0f)); + extras.push_back(Immediate(0.0f)); } else { // If present, lod or bias are always stored in the register indexed by the gpr20 // field with an offset depending on the usage of the other registers - coords.push_back(GetRegister(instr.gpr20.Value() + bias_offset)); + extras.push_back(GetRegister(instr.gpr20.Value() + bias_offset)); } } Node4 values; for (u32 element = 0; element < values.size(); ++element) { - auto params = coords; - MetaTexture meta{sampler, element, coords_count, array_offset_value}; - values[element] = Operation(read_method, std::move(meta), std::move(params)); + auto copy_coords = coords; + MetaTexture meta{sampler, array, depth_compare, extras, element}; + values[element] = Operation(read_method, meta, std::move(copy_coords)); } return values; @@ -602,28 +595,22 @@ Node4 ShaderIR::GetTexCode(Instruction instr, TextureType texture_type, for (std::size_t i = 0; i < coord_count; ++i) { coords.push_back(GetRegister(coord_register + i)); } - // 1D.DC in opengl the 2nd component is ignored. + // 1D.DC in OpenGL the 2nd component is ignored. if (depth_compare && !is_array && texture_type == TextureType::Texture1D) { coords.push_back(Immediate(0.0f)); } - std::size_t array_offset{}; - if (is_array) { - array_offset = coords.size(); - coords.push_back(GetRegister(array_register)); - } + + const Node array = is_array ? GetRegister(array_register) : nullptr; + + Node dc{}; if (depth_compare) { - // Depth is always stored in the register signaled by gpr20 - // or in the next register if lod or bias are used + // Depth is always stored in the register signaled by gpr20 or in the next register if lod + // or bias are used const u64 depth_register = instr.gpr20.Value() + (lod_bias_enabled ? 1 : 0); - coords.push_back(GetRegister(depth_register)); - } - // Fill ignored coordinates - while (coords.size() < total_coord_count) { - coords.push_back(Immediate(0)); + dc = GetRegister(depth_register); } - return GetTextureCode(instr, texture_type, process_mode, depth_compare, is_array, array_offset, - 0, std::move(coords)); + return GetTextureCode(instr, texture_type, process_mode, coords, array, dc, 0); } Node4 ShaderIR::GetTexsCode(Instruction instr, TextureType texture_type, @@ -641,6 +628,7 @@ Node4 ShaderIR::GetTexsCode(Instruction instr, TextureType texture_type, (is_array || !(lod_bias_enabled || depth_compare) || (coord_count > 2)) ? static_cast<u64>(instr.gpr20.Value()) : coord_register + 1; + const u32 bias_offset = coord_count > 2 ? 1 : 0; std::vector<Node> coords; for (std::size_t i = 0; i < coord_count; ++i) { @@ -648,24 +636,17 @@ Node4 ShaderIR::GetTexsCode(Instruction instr, TextureType texture_type, coords.push_back(GetRegister(last ? last_coord_register : coord_register + i)); } - std::size_t array_offset{}; - if (is_array) { - array_offset = coords.size(); - coords.push_back(GetRegister(array_register)); - } + const Node array = is_array ? GetRegister(array_register) : nullptr; + + Node dc{}; if (depth_compare) { - // Depth is always stored in the register signaled by gpr20 - // or in the next register if lod or bias are used + // Depth is always stored in the register signaled by gpr20 or in the next register if lod + // or bias are used const u64 depth_register = instr.gpr20.Value() + (lod_bias_enabled ? 1 : 0); - coords.push_back(GetRegister(depth_register)); - } - // Fill ignored coordinates - while (coords.size() < total_coord_count) { - coords.push_back(Immediate(0)); + dc = GetRegister(depth_register); } - return GetTextureCode(instr, texture_type, process_mode, depth_compare, is_array, array_offset, - (coord_count > 2 ? 1 : 0), std::move(coords)); + return GetTextureCode(instr, texture_type, process_mode, coords, array, dc, bias_offset); } Node4 ShaderIR::GetTld4Code(Instruction instr, TextureType texture_type, bool depth_compare, @@ -680,24 +661,16 @@ Node4 ShaderIR::GetTld4Code(Instruction instr, TextureType texture_type, bool de const u64 coord_register = array_register + (is_array ? 1 : 0); std::vector<Node> coords; - - for (size_t i = 0; i < coord_count; ++i) { + for (size_t i = 0; i < coord_count; ++i) coords.push_back(GetRegister(coord_register + i)); - } - std::optional<u32> array_offset; - if (is_array) { - array_offset = static_cast<u32>(coords.size()); - coords.push_back(GetRegister(array_register)); - } const auto& sampler = GetSampler(instr.sampler, texture_type, is_array, depth_compare); Node4 values; for (u32 element = 0; element < values.size(); ++element) { - auto params = coords; - MetaTexture meta{sampler, element, static_cast<u32>(coords.size()), array_offset}; - values[element] = - Operation(OperationCode::F4TextureGather, std::move(meta), std::move(params)); + auto coords_copy = coords; + MetaTexture meta{sampler, GetRegister(array_register), {}, {}, element}; + values[element] = Operation(OperationCode::TextureGather, meta, std::move(coords_copy)); } return values; @@ -705,7 +678,6 @@ Node4 ShaderIR::GetTld4Code(Instruction instr, TextureType texture_type, bool de Node4 ShaderIR::GetTldsCode(Instruction instr, TextureType texture_type, bool is_array) { const std::size_t type_coord_count = GetCoordCount(texture_type); - const std::size_t total_coord_count = type_coord_count + (is_array ? 1 : 0); const bool lod_enabled = instr.tlds.GetTextureProcessMode() == TextureProcessMode::LL; // If enabled arrays index is always stored in the gpr8 field @@ -719,33 +691,22 @@ Node4 ShaderIR::GetTldsCode(Instruction instr, TextureType texture_type, bool is : coord_register + 1; std::vector<Node> coords; - for (std::size_t i = 0; i < type_coord_count; ++i) { const bool last = (i == (type_coord_count - 1)) && (type_coord_count > 1); coords.push_back(GetRegister(last ? last_coord_register : coord_register + i)); } - std::optional<u32> array_offset; - if (is_array) { - array_offset = static_cast<u32>(coords.size()); - coords.push_back(GetRegister(array_register)); - } - const auto coords_count = static_cast<u32>(coords.size()); - if (lod_enabled) { - // When lod is used always is in grp20 - coords.push_back(GetRegister(instr.gpr20)); - } else { - coords.push_back(Immediate(0)); - } + const Node array = is_array ? GetRegister(array_register) : nullptr; + // When lod is used always is in gpr20 + const Node lod = lod_enabled ? GetRegister(instr.gpr20) : Immediate(0); const auto& sampler = GetSampler(instr.sampler, texture_type, is_array, false); Node4 values; for (u32 element = 0; element < values.size(); ++element) { - auto params = coords; - MetaTexture meta{sampler, element, coords_count, array_offset}; - values[element] = - Operation(OperationCode::F4TexelFetch, std::move(meta), std::move(params)); + auto coords_copy = coords; + MetaTexture meta{sampler, array, {}, {lod}, element}; + values[element] = Operation(OperationCode::TexelFetch, meta, std::move(coords_copy)); } return values; } diff --git a/src/video_core/shader/shader_ir.h b/src/video_core/shader/shader_ir.h index 1d4fbef53..52c7f2c4e 100644 --- a/src/video_core/shader/shader_ir.h +++ b/src/video_core/shader/shader_ir.h @@ -156,12 +156,12 @@ enum class OperationCode { Logical2HNotEqual, /// (MetaHalfArithmetic, f16vec2 a, f16vec2) -> bool2 Logical2HGreaterEqual, /// (MetaHalfArithmetic, f16vec2 a, f16vec2) -> bool2 - F4Texture, /// (MetaTexture, float[N] coords, float[M] params) -> float4 - F4TextureLod, /// (MetaTexture, float[N] coords, float[M] params) -> float4 - F4TextureGather, /// (MetaTexture, float[N] coords, float[M] params) -> float4 - F4TextureQueryDimensions, /// (MetaTexture, float a) -> float4 - F4TextureQueryLod, /// (MetaTexture, float[N] coords) -> float4 - F4TexelFetch, /// (MetaTexture, int[N], int) -> float4 + Texture, /// (MetaTexture, float[N] coords) -> float4 + TextureLod, /// (MetaTexture, float[N] coords) -> float4 + TextureGather, /// (MetaTexture, float[N] coords) -> float4 + TextureQueryDimensions, /// (MetaTexture, float a) -> float4 + TextureQueryLod, /// (MetaTexture, float[N] coords) -> float4 + TexelFetch, /// (MetaTexture, int[N], int) -> float4 Branch, /// (uint branch_target) -> void PushFlowStack, /// (uint branch_target) -> void @@ -288,9 +288,10 @@ struct MetaHalfArithmetic { struct MetaTexture { const Sampler& sampler; + Node array{}; + Node depth_compare{}; + std::vector<Node> extras; u32 element{}; - u32 coords_count{}; - std::optional<u32> array_index; }; constexpr MetaArithmetic PRECISE = {true}; @@ -754,9 +755,8 @@ private: bool lod_bias_enabled, std::size_t max_coords, std::size_t max_inputs); Node4 GetTextureCode(Tegra::Shader::Instruction instr, Tegra::Shader::TextureType texture_type, - Tegra::Shader::TextureProcessMode process_mode, bool depth_compare, - bool is_array, std::size_t array_offset, std::size_t bias_offset, - std::vector<Node>&& coords); + Tegra::Shader::TextureProcessMode process_mode, std::vector<Node> coords, + Node array, Node depth_compare, u32 bias_offset); Node GetVideoOperand(Node op, bool is_chunk, bool is_signed, Tegra::Shader::VideoType type, u64 byte_height); |