summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp6
-rw-r--r--src/video_core/engines/fermi_2d.cpp62
-rw-r--r--src/video_core/engines/fermi_2d.h29
-rw-r--r--src/video_core/engines/shader_bytecode.h2
-rw-r--r--src/video_core/rasterizer_interface.h4
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.cpp12
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.h4
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer_cache.cpp205
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer_cache.h10
-rw-r--r--src/video_core/renderer_opengl/gl_shader_decompiler.cpp97
-rw-r--r--src/video_core/shader/decode/arithmetic_integer.cpp4
-rw-r--r--src/video_core/shader/decode/conversion.cpp6
-rw-r--r--src/video_core/shader/decode/memory.cpp157
-rw-r--r--src/video_core/shader/shader_ir.h22
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);