summaryrefslogtreecommitdiffstats
path: root/src/video_core/renderer_opengl
diff options
context:
space:
mode:
Diffstat (limited to 'src/video_core/renderer_opengl')
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.cpp147
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.h13
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer_cache.cpp147
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer_cache.h86
-rw-r--r--src/video_core/renderer_opengl/gl_shader_decompiler.cpp55
-rw-r--r--src/video_core/renderer_opengl/renderer_opengl.cpp19
6 files changed, 328 insertions, 139 deletions
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp
index 2d4a0d6db..9b3542e10 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp
@@ -116,7 +116,7 @@ RasterizerOpenGL::RasterizerOpenGL() {
glEnable(GL_BLEND);
- LOG_CRITICAL(Render_OpenGL, "Sync fixed function OpenGL state here!");
+ NGLOG_CRITICAL(Render_OpenGL, "Sync fixed function OpenGL state here!");
}
RasterizerOpenGL::~RasterizerOpenGL() {
@@ -127,7 +127,8 @@ RasterizerOpenGL::~RasterizerOpenGL() {
}
}
-void RasterizerOpenGL::SetupVertexArray(u8* array_ptr, GLintptr buffer_offset) {
+std::pair<u8*, GLintptr> RasterizerOpenGL::SetupVertexArrays(u8* array_ptr,
+ GLintptr buffer_offset) {
MICROPROFILE_SCOPE(OpenGL_VAO);
const auto& regs = Core::System().GetInstance().GPU().Maxwell3D().regs;
const auto& memory_manager = Core::System().GetInstance().GPU().memory_manager;
@@ -136,43 +137,58 @@ void RasterizerOpenGL::SetupVertexArray(u8* array_ptr, GLintptr buffer_offset) {
state.draw.vertex_buffer = stream_buffer->GetHandle();
state.Apply();
- // TODO(bunnei): Add support for 1+ vertex arrays
- const auto& vertex_array{regs.vertex_array[0]};
- const auto& vertex_array_limit{regs.vertex_array_limit[0]};
- ASSERT_MSG(vertex_array.enable, "vertex array 0 is disabled?");
- ASSERT_MSG(!vertex_array.divisor, "vertex array 0 divisor is unimplemented!");
- for (unsigned index = 1; index < Maxwell::NumVertexArrays; ++index) {
- ASSERT_MSG(!regs.vertex_array[index].enable, "vertex array %d is unimplemented!", index);
+ // Upload all guest vertex arrays sequentially to our buffer
+ for (u32 index = 0; index < Maxwell::NumVertexArrays; ++index) {
+ const auto& vertex_array = regs.vertex_array[index];
+ if (!vertex_array.IsEnabled())
+ continue;
+
+ const Tegra::GPUVAddr start = vertex_array.StartAddress();
+ const Tegra::GPUVAddr end = regs.vertex_array_limit[index].LimitAddress();
+
+ ASSERT(end > start);
+ u64 size = end - start + 1;
+
+ // Copy vertex array data
+ res_cache.FlushRegion(start, size, nullptr);
+ Memory::ReadBlock(*memory_manager->GpuToCpuAddress(start), array_ptr, size);
+
+ // Bind the vertex array to the buffer at the current offset.
+ glBindVertexBuffer(index, stream_buffer->GetHandle(), buffer_offset, vertex_array.stride);
+
+ ASSERT_MSG(vertex_array.divisor == 0, "Vertex buffer divisor unimplemented");
+
+ array_ptr += size;
+ buffer_offset += size;
}
// Use the vertex array as-is, assumes that the data is formatted correctly for OpenGL.
// Enables the first 16 vertex attributes always, as we don't know which ones are actually used
- // until shader time. Note, Tegra technically supports 32, but we're cappinig this to 16 for now
+ // until shader time. Note, Tegra technically supports 32, but we're capping this to 16 for now
// to avoid OpenGL errors.
+ // TODO(Subv): Analyze the shader to identify which attributes are actually used and don't
+ // assume every shader uses them all.
for (unsigned index = 0; index < 16; ++index) {
auto& attrib = regs.vertex_attrib_format[index];
NGLOG_DEBUG(HW_GPU, "vertex attrib {}, count={}, size={}, type={}, offset={}, normalize={}",
index, attrib.ComponentCount(), attrib.SizeString(), attrib.TypeString(),
attrib.offset.Value(), attrib.IsNormalized());
- glVertexAttribPointer(index, attrib.ComponentCount(), MaxwellToGL::VertexType(attrib),
- attrib.IsNormalized() ? GL_TRUE : GL_FALSE, vertex_array.stride,
- reinterpret_cast<GLvoid*>(buffer_offset + attrib.offset));
+ auto& buffer = regs.vertex_array[attrib.buffer];
+ ASSERT(buffer.IsEnabled());
+
glEnableVertexAttribArray(index);
+ glVertexAttribFormat(index, attrib.ComponentCount(), MaxwellToGL::VertexType(attrib),
+ attrib.IsNormalized() ? GL_TRUE : GL_FALSE, attrib.offset);
+ glVertexAttribBinding(index, attrib.buffer);
+
hw_vao_enabled_attributes[index] = true;
}
- // Copy vertex array data
- const u64 data_size{vertex_array_limit.LimitAddress() - vertex_array.StartAddress() + 1};
- const VAddr data_addr{memory_manager->PhysicalToVirtualAddress(vertex_array.StartAddress())};
- res_cache.FlushRegion(data_addr, data_size, nullptr);
- Memory::ReadBlock(data_addr, array_ptr, data_size);
-
- array_ptr += data_size;
- buffer_offset += data_size;
+ return {array_ptr, buffer_offset};
}
-void RasterizerOpenGL::SetupShaders(u8* buffer_ptr, GLintptr buffer_offset, size_t ptr_pos) {
+void RasterizerOpenGL::SetupShaders(u8* buffer_ptr, GLintptr buffer_offset) {
// Helper function for uploading uniform data
const auto copy_buffer = [&](GLuint handle, GLintptr offset, GLsizeiptr size) {
if (has_ARB_direct_state_access) {
@@ -190,8 +206,6 @@ void RasterizerOpenGL::SetupShaders(u8* buffer_ptr, GLintptr buffer_offset, size
u32 current_constbuffer_bindpoint = 0;
for (unsigned index = 1; index < Maxwell::MaxShaderProgram; ++index) {
- ptr_pos += sizeof(GLShader::MaxwellUniformData);
-
auto& shader_config = gpu.regs.shader_config[index];
const Maxwell::ShaderProgram program{static_cast<Maxwell::ShaderProgram>(index)};
@@ -205,18 +219,21 @@ void RasterizerOpenGL::SetupShaders(u8* buffer_ptr, GLintptr buffer_offset, size
}
// Upload uniform data as one UBO per stage
- const GLintptr ubo_offset = buffer_offset + static_cast<GLintptr>(ptr_pos);
+ const GLintptr ubo_offset = buffer_offset;
copy_buffer(uniform_buffers[stage].handle, ubo_offset,
sizeof(GLShader::MaxwellUniformData));
GLShader::MaxwellUniformData* ub_ptr =
- reinterpret_cast<GLShader::MaxwellUniformData*>(&buffer_ptr[ptr_pos]);
+ reinterpret_cast<GLShader::MaxwellUniformData*>(buffer_ptr);
ub_ptr->SetFromRegs(gpu.state.shader_stages[stage]);
+ buffer_ptr += sizeof(GLShader::MaxwellUniformData);
+ buffer_offset += sizeof(GLShader::MaxwellUniformData);
+
// Fetch program code from memory
GLShader::ProgramCode program_code;
const u64 gpu_address{gpu.regs.code_address.CodeAddress() + shader_config.offset};
- const VAddr cpu_address{gpu.memory_manager.PhysicalToVirtualAddress(gpu_address)};
- Memory::ReadBlock(cpu_address, program_code.data(), program_code.size() * sizeof(u64));
+ const boost::optional<VAddr> cpu_address{gpu.memory_manager.GpuToCpuAddress(gpu_address)};
+ Memory::ReadBlock(*cpu_address, program_code.data(), program_code.size() * sizeof(u64));
GLShader::ShaderSetup setup{std::move(program_code)};
GLShader::ShaderEntries shader_resources;
@@ -235,8 +252,8 @@ void RasterizerOpenGL::SetupShaders(u8* buffer_ptr, GLintptr buffer_offset, size
break;
}
default:
- LOG_CRITICAL(HW_GPU, "Unimplemented shader index=%d, enable=%d, offset=0x%08X", index,
- shader_config.enable.Value(), shader_config.offset);
+ NGLOG_CRITICAL(HW_GPU, "Unimplemented shader index={}, enable={}, offset={:#010X}",
+ index, shader_config.enable.Value(), shader_config.offset);
UNREACHABLE();
}
@@ -252,6 +269,24 @@ void RasterizerOpenGL::SetupShaders(u8* buffer_ptr, GLintptr buffer_offset, size
shader_program_manager->UseTrivialGeometryShader();
}
+size_t RasterizerOpenGL::CalculateVertexArraysSize() const {
+ const auto& regs = Core::System().GetInstance().GPU().Maxwell3D().regs;
+
+ size_t size = 0;
+ for (u32 index = 0; index < Maxwell::NumVertexArrays; ++index) {
+ if (!regs.vertex_array[index].IsEnabled())
+ continue;
+
+ const Tegra::GPUVAddr start = regs.vertex_array[index].StartAddress();
+ const Tegra::GPUVAddr end = regs.vertex_array_limit[index].LimitAddress();
+
+ ASSERT(end > start);
+ size += end - start + 1;
+ }
+
+ return size;
+}
+
bool RasterizerOpenGL::AccelerateDrawBatch(bool is_indexed) {
accelerate_draw = is_indexed ? AccelDraw::Indexed : AccelDraw::Arrays;
DrawArrays();
@@ -329,44 +364,49 @@ void RasterizerOpenGL::DrawArrays() {
const u64 index_buffer_size{regs.index_array.count * regs.index_array.FormatSizeInBytes()};
const unsigned vertex_num{is_indexed ? regs.index_array.count : regs.vertex_buffer.count};
- // TODO(bunnei): Add support for 1+ vertex arrays
- vs_input_size = vertex_num * regs.vertex_array[0].stride;
-
state.draw.vertex_buffer = stream_buffer->GetHandle();
state.Apply();
- size_t buffer_size = static_cast<size_t>(vs_input_size);
+ size_t buffer_size = CalculateVertexArraysSize();
+
if (is_indexed) {
- buffer_size = Common::AlignUp(buffer_size, 4) + index_buffer_size;
+ buffer_size = Common::AlignUp<size_t>(buffer_size, 4) + index_buffer_size;
}
// Uniform space for the 5 shader stages
- buffer_size += sizeof(GLShader::MaxwellUniformData) * Maxwell::MaxShaderStage;
+ buffer_size = Common::AlignUp<size_t>(buffer_size, 4) +
+ sizeof(GLShader::MaxwellUniformData) * Maxwell::MaxShaderStage;
- size_t ptr_pos = 0;
u8* buffer_ptr;
GLintptr buffer_offset;
std::tie(buffer_ptr, buffer_offset) =
stream_buffer->Map(static_cast<GLsizeiptr>(buffer_size), 4);
- SetupVertexArray(buffer_ptr, buffer_offset);
- ptr_pos += vs_input_size;
+ u8* offseted_buffer;
+ std::tie(offseted_buffer, buffer_offset) = SetupVertexArrays(buffer_ptr, buffer_offset);
+
+ offseted_buffer =
+ reinterpret_cast<u8*>(Common::AlignUp(reinterpret_cast<size_t>(offseted_buffer), 4));
+ buffer_offset = Common::AlignUp<size_t>(buffer_offset, 4);
// If indexed mode, copy the index buffer
GLintptr index_buffer_offset = 0;
if (is_indexed) {
- ptr_pos = Common::AlignUp(ptr_pos, 4);
-
const auto& memory_manager = Core::System().GetInstance().GPU().memory_manager;
- const VAddr index_data_addr{
- memory_manager->PhysicalToVirtualAddress(regs.index_array.StartAddress())};
- Memory::ReadBlock(index_data_addr, &buffer_ptr[ptr_pos], index_buffer_size);
+ const boost::optional<VAddr> index_data_addr{
+ memory_manager->GpuToCpuAddress(regs.index_array.StartAddress())};
+ Memory::ReadBlock(*index_data_addr, offseted_buffer, index_buffer_size);
- index_buffer_offset = buffer_offset + static_cast<GLintptr>(ptr_pos);
- ptr_pos += index_buffer_size;
+ index_buffer_offset = buffer_offset;
+ offseted_buffer += index_buffer_size;
+ buffer_offset += index_buffer_size;
}
- SetupShaders(buffer_ptr, buffer_offset, ptr_pos);
+ offseted_buffer =
+ reinterpret_cast<u8*>(Common::AlignUp(reinterpret_cast<size_t>(offseted_buffer), 4));
+ buffer_offset = Common::AlignUp<size_t>(buffer_offset, 4);
+
+ SetupShaders(offseted_buffer, buffer_offset);
stream_buffer->Unmap();
@@ -478,17 +518,17 @@ void RasterizerOpenGL::FlushAll() {
res_cache.FlushAll();
}
-void RasterizerOpenGL::FlushRegion(VAddr addr, u64 size) {
+void RasterizerOpenGL::FlushRegion(Tegra::GPUVAddr addr, u64 size) {
MICROPROFILE_SCOPE(OpenGL_CacheManagement);
res_cache.FlushRegion(addr, size);
}
-void RasterizerOpenGL::InvalidateRegion(VAddr addr, u64 size) {
+void RasterizerOpenGL::InvalidateRegion(Tegra::GPUVAddr addr, u64 size) {
MICROPROFILE_SCOPE(OpenGL_CacheManagement);
res_cache.InvalidateRegion(addr, size, nullptr);
}
-void RasterizerOpenGL::FlushAndInvalidateRegion(VAddr addr, u64 size) {
+void RasterizerOpenGL::FlushAndInvalidateRegion(Tegra::GPUVAddr addr, u64 size) {
MICROPROFILE_SCOPE(OpenGL_CacheManagement);
res_cache.FlushRegion(addr, size);
res_cache.InvalidateRegion(addr, size, nullptr);
@@ -519,7 +559,8 @@ bool RasterizerOpenGL::AccelerateDisplay(const Tegra::FramebufferConfig& framebu
MICROPROFILE_SCOPE(OpenGL_CacheManagement);
SurfaceParams src_params;
- src_params.addr = framebuffer_addr;
+ src_params.cpu_addr = framebuffer_addr;
+ src_params.addr = res_cache.TryFindFramebufferGpuAddress(framebuffer_addr).get_value_or(0);
src_params.width = std::min(framebuffer.width, pixel_stride);
src_params.height = framebuffer.height;
src_params.stride = pixel_stride;
@@ -618,9 +659,9 @@ u32 RasterizerOpenGL::SetupConstBuffers(Maxwell::ShaderStage stage, GLuint progr
buffer_draw_state.enabled = true;
buffer_draw_state.bindpoint = current_bindpoint + bindpoint;
- VAddr addr = gpu.memory_manager->PhysicalToVirtualAddress(buffer.address);
+ boost::optional<VAddr> addr = gpu.memory_manager->GpuToCpuAddress(buffer.address);
std::vector<u8> data(used_buffer.GetSize() * sizeof(float));
- Memory::ReadBlock(addr, data.data(), data.size());
+ Memory::ReadBlock(*addr, data.data(), data.size());
glBindBuffer(GL_SHADER_STORAGE_BUFFER, buffer_draw_state.ssbo);
glBufferData(GL_SHADER_STORAGE_BUFFER, data.size(), data.data(), GL_DYNAMIC_DRAW);
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h
index 03e02b52a..9709e595e 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.h
+++ b/src/video_core/renderer_opengl/gl_rasterizer.h
@@ -11,6 +11,7 @@
#include <glad/glad.h>
#include "common/common_types.h"
#include "video_core/engines/maxwell_3d.h"
+#include "video_core/memory_manager.h"
#include "video_core/rasterizer_interface.h"
#include "video_core/renderer_opengl/gl_rasterizer_cache.h"
#include "video_core/renderer_opengl/gl_resource_manager.h"
@@ -29,9 +30,9 @@ public:
void DrawArrays() override;
void NotifyMaxwellRegisterChanged(u32 method) override;
void FlushAll() override;
- void FlushRegion(VAddr addr, u64 size) override;
- void InvalidateRegion(VAddr addr, u64 size) override;
- void FlushAndInvalidateRegion(VAddr addr, u64 size) override;
+ void FlushRegion(Tegra::GPUVAddr addr, u64 size) override;
+ void InvalidateRegion(Tegra::GPUVAddr addr, u64 size) override;
+ void FlushAndInvalidateRegion(Tegra::GPUVAddr addr, u64 size) override;
bool AccelerateDisplayTransfer(const void* config) override;
bool AccelerateTextureCopy(const void* config) override;
bool AccelerateFill(const void* config) override;
@@ -148,13 +149,13 @@ private:
static constexpr size_t STREAM_BUFFER_SIZE = 4 * 1024 * 1024;
std::unique_ptr<OGLStreamBuffer> stream_buffer;
- GLsizeiptr vs_input_size;
+ size_t CalculateVertexArraysSize() const;
- void SetupVertexArray(u8* array_ptr, GLintptr buffer_offset);
+ std::pair<u8*, GLintptr> SetupVertexArrays(u8* array_ptr, GLintptr buffer_offset);
std::array<OGLBuffer, Tegra::Engines::Maxwell3D::Regs::MaxShaderStage> uniform_buffers;
- void SetupShaders(u8* buffer_ptr, GLintptr buffer_offset, size_t ptr_pos);
+ void SetupShaders(u8* buffer_ptr, GLintptr buffer_offset);
enum class AccelDraw { Disabled, Arrays, Indexed };
AccelDraw accelerate_draw;
diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
index 7410471cc..501d15e98 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
@@ -41,18 +41,15 @@ struct FormatTuple {
GLenum format;
GLenum type;
bool compressed;
- // How many pixels in the original texture are equivalent to one pixel in the compressed
- // texture.
- u32 compression_factor;
};
static constexpr std::array<FormatTuple, SurfaceParams::MaxPixelFormat> tex_format_tuples = {{
- {GL_RGBA8, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, false, 1}, // ABGR8
- {GL_RGB, GL_RGB, GL_UNSIGNED_SHORT_5_6_5_REV, false, 1}, // B5G6R5
- {GL_RGB10_A2, GL_RGBA, GL_UNSIGNED_INT_2_10_10_10_REV, false, 1}, // A2B10G10R10
- {GL_COMPRESSED_RGB_S3TC_DXT1_EXT, GL_RGB, GL_UNSIGNED_INT_8_8_8_8, true, 16}, // DXT1
- {GL_COMPRESSED_RGBA_S3TC_DXT3_EXT, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, true, 16}, // DXT23
- {GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, true, 16}, // DXT45
+ {GL_RGBA8, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, false}, // ABGR8
+ {GL_RGB, GL_RGB, GL_UNSIGNED_SHORT_5_6_5_REV, false}, // B5G6R5
+ {GL_RGB10_A2, GL_RGBA, GL_UNSIGNED_INT_2_10_10_10_REV, false}, // A2B10G10R10
+ {GL_COMPRESSED_RGB_S3TC_DXT1_EXT, GL_RGB, GL_UNSIGNED_INT_8_8_8_8, true}, // DXT1
+ {GL_COMPRESSED_RGBA_S3TC_DXT3_EXT, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, true}, // DXT23
+ {GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, true}, // DXT45
}};
static const FormatTuple& GetFormatTuple(PixelFormat pixel_format, ComponentType component_type) {
@@ -83,26 +80,30 @@ static u16 GetResolutionScaleFactor() {
}
template <bool morton_to_gl, PixelFormat format>
-void MortonCopy(u32 stride, u32 block_height, u32 height, u8* gl_buffer, VAddr base, VAddr start,
- VAddr end) {
- constexpr u32 bytes_per_pixel = SurfaceParams::GetFormatBpp(format) / 8;
+void MortonCopy(u32 stride, u32 block_height, u32 height, u8* gl_buffer, Tegra::GPUVAddr base,
+ Tegra::GPUVAddr start, Tegra::GPUVAddr end) {
+ constexpr u32 bytes_per_pixel = SurfaceParams::GetFormatBpp(format) / CHAR_BIT;
constexpr u32 gl_bytes_per_pixel = CachedSurface::GetGLBytesPerPixel(format);
+ const auto& gpu = Core::System::GetInstance().GPU();
if (morton_to_gl) {
auto data = Tegra::Texture::UnswizzleTexture(
- base, SurfaceParams::TextureFormatFromPixelFormat(format), stride, height,
- block_height);
+ *gpu.memory_manager->GpuToCpuAddress(base),
+ SurfaceParams::TextureFormatFromPixelFormat(format), stride, height, block_height);
std::memcpy(gl_buffer, data.data(), data.size());
} else {
// TODO(bunnei): Assumes the default rendering GOB size of 16 (128 lines). We should check
// the configuration for this and perform more generic un/swizzle
- LOG_WARNING(Render_OpenGL, "need to use correct swizzle/GOB parameters!");
- VideoCore::MortonCopyPixels128(stride, height, bytes_per_pixel, gl_bytes_per_pixel,
- Memory::GetPointer(base), gl_buffer, morton_to_gl);
+ NGLOG_WARNING(Render_OpenGL, "need to use correct swizzle/GOB parameters!");
+ VideoCore::MortonCopyPixels128(
+ stride, height, bytes_per_pixel, gl_bytes_per_pixel,
+ Memory::GetPointer(*gpu.memory_manager->GpuToCpuAddress(base)), gl_buffer,
+ morton_to_gl);
}
}
-static constexpr std::array<void (*)(u32, u32, u32, u8*, VAddr, VAddr, VAddr),
+static constexpr std::array<void (*)(u32, u32, u32, u8*, Tegra::GPUVAddr, Tegra::GPUVAddr,
+ Tegra::GPUVAddr),
SurfaceParams::MaxPixelFormat>
morton_to_gl_fns = {
MortonCopy<true, PixelFormat::ABGR8>, MortonCopy<true, PixelFormat::B5G6R5>,
@@ -110,7 +111,8 @@ static constexpr std::array<void (*)(u32, u32, u32, u8*, VAddr, VAddr, VAddr),
MortonCopy<true, PixelFormat::DXT23>, MortonCopy<true, PixelFormat::DXT45>,
};
-static constexpr std::array<void (*)(u32, u32, u32, u8*, VAddr, VAddr, VAddr),
+static constexpr std::array<void (*)(u32, u32, u32, u8*, Tegra::GPUVAddr, Tegra::GPUVAddr,
+ Tegra::GPUVAddr),
SurfaceParams::MaxPixelFormat>
gl_to_morton_fns = {
MortonCopy<false, PixelFormat::ABGR8>,
@@ -219,9 +221,9 @@ SurfaceParams SurfaceParams::FromInterval(SurfaceInterval interval) const {
SurfaceParams params = *this;
const u32 tiled_size = is_tiled ? 8 : 1;
const u64 stride_tiled_bytes = BytesInPixels(stride * tiled_size);
- VAddr aligned_start =
+ Tegra::GPUVAddr aligned_start =
addr + Common::AlignDown(boost::icl::first(interval) - addr, stride_tiled_bytes);
- VAddr aligned_end =
+ Tegra::GPUVAddr aligned_end =
addr + Common::AlignUp(boost::icl::last_next(interval) - addr, stride_tiled_bytes);
if (aligned_end - aligned_start > stride_tiled_bytes) {
@@ -342,6 +344,13 @@ bool SurfaceParams::CanTexCopy(const SurfaceParams& texcopy_params) const {
return FromInterval(texcopy_params.GetInterval()).GetInterval() == texcopy_params.GetInterval();
}
+VAddr SurfaceParams::GetCpuAddr() const {
+ // When this function is used, only cpu_addr or (GPU) addr should be set, not both
+ ASSERT(!(cpu_addr && addr));
+ const auto& gpu = Core::System::GetInstance().GPU();
+ return cpu_addr.get_value_or(*gpu.memory_manager->GpuToCpuAddress(addr));
+}
+
bool CachedSurface::CanFill(const SurfaceParams& dest_surface,
SurfaceInterval fill_interval) const {
if (type == SurfaceType::Fill && IsRegionValid(fill_interval) &&
@@ -349,9 +358,9 @@ bool CachedSurface::CanFill(const SurfaceParams& dest_surface,
boost::icl::last_next(fill_interval) <= end && // dest_surface is within our fill range
dest_surface.FromInterval(fill_interval).GetInterval() ==
fill_interval) { // make sure interval is a rectangle in dest surface
- if (fill_size * 8 != dest_surface.GetFormatBpp()) {
+ if (fill_size * CHAR_BIT != dest_surface.GetFormatBpp()) {
// Check if bits repeat for our fill_size
- const u32 dest_bytes_per_pixel = std::max(dest_surface.GetFormatBpp() / 8, 1u);
+ const u32 dest_bytes_per_pixel = std::max(dest_surface.GetFormatBpp() / CHAR_BIT, 1u);
std::vector<u8> fill_test(fill_size * dest_bytes_per_pixel);
for (u32 i = 0; i < dest_bytes_per_pixel; ++i)
@@ -456,15 +465,15 @@ void RasterizerCacheOpenGL::CopySurface(const Surface& src_surface, const Surfac
}
MICROPROFILE_DEFINE(OpenGL_SurfaceLoad, "OpenGL", "Surface Load", MP_RGB(128, 64, 192));
-void CachedSurface::LoadGLBuffer(VAddr load_start, VAddr load_end) {
+void CachedSurface::LoadGLBuffer(Tegra::GPUVAddr load_start, Tegra::GPUVAddr load_end) {
ASSERT(type != SurfaceType::Fill);
- u8* const texture_src_data = Memory::GetPointer(addr);
+ u8* const texture_src_data = Memory::GetPointer(GetCpuAddr());
if (texture_src_data == nullptr)
return;
if (gl_buffer == nullptr) {
- gl_buffer_size = width * height * GetGLBytesPerPixel(pixel_format);
+ gl_buffer_size = GetActualWidth() * GetActualHeight() * GetGLBytesPerPixel(pixel_format);
gl_buffer.reset(new u8[gl_buffer_size]);
}
@@ -479,14 +488,15 @@ void CachedSurface::LoadGLBuffer(VAddr load_start, VAddr load_end) {
std::memcpy(&gl_buffer[start_offset], texture_src_data + start_offset,
bytes_per_pixel * width * height);
} else {
- morton_to_gl_fns[static_cast<size_t>(pixel_format)](
- stride, block_height, height, &gl_buffer[0], addr, load_start, load_end);
+ morton_to_gl_fns[static_cast<size_t>(pixel_format)](GetActualWidth(), block_height,
+ GetActualHeight(), &gl_buffer[0], addr,
+ load_start, load_end);
}
}
MICROPROFILE_DEFINE(OpenGL_SurfaceFlush, "OpenGL", "Surface Flush", MP_RGB(128, 192, 64));
-void CachedSurface::FlushGLBuffer(VAddr flush_start, VAddr flush_end) {
- u8* const dst_buffer = Memory::GetPointer(addr);
+void CachedSurface::FlushGLBuffer(Tegra::GPUVAddr flush_start, Tegra::GPUVAddr flush_end) {
+ u8* const dst_buffer = Memory::GetPointer(GetCpuAddr());
if (dst_buffer == nullptr)
return;
@@ -536,7 +546,8 @@ void CachedSurface::UploadGLTexture(const MathUtil::Rectangle<u32>& rect, GLuint
MICROPROFILE_SCOPE(OpenGL_TextureUL);
- ASSERT(gl_buffer_size == width * height * GetGLBytesPerPixel(pixel_format));
+ ASSERT(gl_buffer_size ==
+ GetActualWidth() * GetActualHeight() * GetGLBytesPerPixel(pixel_format));
// Load data from memory to the surface
GLint x0 = static_cast<GLint>(rect.left);
@@ -571,11 +582,9 @@ void CachedSurface::UploadGLTexture(const MathUtil::Rectangle<u32>& rect, GLuint
glActiveTexture(GL_TEXTURE0);
if (tuple.compressed) {
glCompressedTexImage2D(GL_TEXTURE_2D, 0, tuple.internal_format,
- static_cast<GLsizei>(rect.GetWidth()),
- static_cast<GLsizei>(rect.GetHeight()), 0,
- rect.GetWidth() * rect.GetHeight() *
- GetGLBytesPerPixel(pixel_format) / tuple.compression_factor,
- &gl_buffer[buffer_offset]);
+ static_cast<GLsizei>(rect.GetWidth() * GetCompresssionFactor()),
+ static_cast<GLsizei>(rect.GetHeight() * GetCompresssionFactor()), 0,
+ size, &gl_buffer[buffer_offset]);
} else {
glTexSubImage2D(GL_TEXTURE_2D, 0, x0, y0, static_cast<GLsizei>(rect.GetWidth()),
static_cast<GLsizei>(rect.GetHeight()), tuple.format, tuple.type,
@@ -945,6 +954,33 @@ Surface RasterizerCacheOpenGL::GetSurface(const SurfaceParams& params, ScaleMatc
return surface;
}
+boost::optional<Tegra::GPUVAddr> RasterizerCacheOpenGL::TryFindFramebufferGpuAddress(
+ VAddr cpu_addr) const {
+ // Tries to find the GPU address of a framebuffer based on the CPU address. This is because
+ // final output framebuffers are specified by CPU address, but internally our GPU cache uses GPU
+ // addresses. We iterate through all cached framebuffers, and compare their starting CPU address
+ // to the one provided. This is obviously not great, and won't work if the framebuffer overlaps
+ // surfaces.
+
+ std::vector<Tegra::GPUVAddr> gpu_addresses;
+ for (const auto& pair : surface_cache) {
+ for (const auto& surface : pair.second) {
+ const VAddr surface_cpu_addr = surface->GetCpuAddr();
+ if (cpu_addr >= surface_cpu_addr && cpu_addr < (surface_cpu_addr + surface->size)) {
+ ASSERT_MSG(cpu_addr == surface_cpu_addr, "overlapping surfaces are unsupported");
+ gpu_addresses.push_back(surface->addr);
+ }
+ }
+ }
+
+ if (gpu_addresses.empty()) {
+ return {};
+ }
+
+ ASSERT_MSG(gpu_addresses.size() == 1, ">1 surface is unsupported");
+ return gpu_addresses[0];
+}
+
SurfaceRect_Tuple RasterizerCacheOpenGL::GetSurfaceSubRect(const SurfaceParams& params,
ScaleMatch match_res_scale,
bool load_if_create) {
@@ -1028,11 +1064,11 @@ Surface RasterizerCacheOpenGL::GetTextureSurface(const Tegra::Texture::FullTextu
auto& gpu = Core::System::GetInstance().GPU();
SurfaceParams params;
- params.addr = gpu.memory_manager->PhysicalToVirtualAddress(config.tic.Address());
- params.width = config.tic.Width();
- params.height = config.tic.Height();
+ params.addr = config.tic.Address();
params.is_tiled = config.tic.IsTiled();
params.pixel_format = SurfaceParams::PixelFormatFromTextureFormat(config.tic.format);
+ params.width = config.tic.Width() / params.GetCompresssionFactor();
+ params.height = config.tic.Height() / params.GetCompresssionFactor();
// TODO(Subv): Different types per component are not supported.
ASSERT(config.tic.r_type.Value() == config.tic.g_type.Value() &&
@@ -1045,7 +1081,7 @@ Surface RasterizerCacheOpenGL::GetTextureSurface(const Tegra::Texture::FullTextu
params.block_height = config.tic.BlockHeight();
} else {
// Use the texture-provided stride value if the texture isn't tiled.
- params.stride = params.PixelsInBytes(config.tic.Pitch());
+ params.stride = static_cast<u32>(params.PixelsInBytes(config.tic.Pitch()));
}
params.UpdateParams();
@@ -1073,11 +1109,10 @@ Surface RasterizerCacheOpenGL::GetTextureSurface(const Tegra::Texture::FullTextu
SurfaceSurfaceRect_Tuple RasterizerCacheOpenGL::GetFramebufferSurfaces(
bool using_color_fb, bool using_depth_fb, const MathUtil::Rectangle<s32>& viewport) {
const auto& regs = Core::System().GetInstance().GPU().Maxwell3D().regs;
- const auto& memory_manager = Core::System().GetInstance().GPU().memory_manager;
const auto& config = regs.rt[0];
// TODO(bunnei): This is hard corded to use just the first render buffer
- LOG_WARNING(Render_OpenGL, "hard-coded for render target 0!");
+ NGLOG_WARNING(Render_OpenGL, "hard-coded for render target 0!");
// update resolution_scale_factor and reset cache if changed
// TODO (bunnei): This code was ported as-is from Citra, and is technically not thread-safe. We
@@ -1106,7 +1141,7 @@ SurfaceSurfaceRect_Tuple RasterizerCacheOpenGL::GetFramebufferSurfaces(
color_params.block_height = Tegra::Texture::TICEntry::DefaultBlockHeight;
SurfaceParams depth_params = color_params;
- color_params.addr = memory_manager->PhysicalToVirtualAddress(config.Address());
+ color_params.addr = config.Address();
color_params.pixel_format = SurfaceParams::PixelFormatFromRenderTargetFormat(config.format);
color_params.component_type = SurfaceParams::ComponentTypeFromRenderTarget(config.format);
color_params.UpdateParams();
@@ -1122,8 +1157,8 @@ SurfaceSurfaceRect_Tuple RasterizerCacheOpenGL::GetFramebufferSurfaces(
// Make sure that framebuffers don't overlap if both color and depth are being used
if (using_color_fb && using_depth_fb &&
boost::icl::length(color_vp_interval & depth_vp_interval)) {
- LOG_CRITICAL(Render_OpenGL, "Color and depth framebuffer memory regions overlap; "
- "overlapping framebuffers not supported!");
+ NGLOG_CRITICAL(Render_OpenGL, "Color and depth framebuffer memory regions overlap; "
+ "overlapping framebuffers not supported!");
using_depth_fb = false;
}
@@ -1222,7 +1257,8 @@ void RasterizerCacheOpenGL::DuplicateSurface(const Surface& src_surface,
}
}
-void RasterizerCacheOpenGL::ValidateSurface(const Surface& surface, VAddr addr, u64 size) {
+void RasterizerCacheOpenGL::ValidateSurface(const Surface& surface, Tegra::GPUVAddr addr,
+ u64 size) {
if (size == 0)
return;
@@ -1261,7 +1297,7 @@ void RasterizerCacheOpenGL::ValidateSurface(const Surface& surface, VAddr addr,
}
}
-void RasterizerCacheOpenGL::FlushRegion(VAddr addr, u64 size, Surface flush_surface) {
+void RasterizerCacheOpenGL::FlushRegion(Tegra::GPUVAddr addr, u64 size, Surface flush_surface) {
if (size == 0)
return;
@@ -1297,7 +1333,8 @@ void RasterizerCacheOpenGL::FlushAll() {
FlushRegion(0, Kernel::VMManager::MAX_ADDRESS);
}
-void RasterizerCacheOpenGL::InvalidateRegion(VAddr addr, u64 size, const Surface& region_owner) {
+void RasterizerCacheOpenGL::InvalidateRegion(Tegra::GPUVAddr addr, u64 size,
+ const Surface& region_owner) {
if (size == 0)
return;
@@ -1390,10 +1427,10 @@ void RasterizerCacheOpenGL::UnregisterSurface(const Surface& surface) {
surface_cache.subtract({surface->GetInterval(), SurfaceSet{surface}});
}
-void RasterizerCacheOpenGL::UpdatePagesCachedCount(VAddr addr, u64 size, int delta) {
- const u64 num_pages =
- ((addr + size - 1) >> Memory::PAGE_BITS) - (addr >> Memory::PAGE_BITS) + 1;
- const u64 page_start = addr >> Memory::PAGE_BITS;
+void RasterizerCacheOpenGL::UpdatePagesCachedCount(Tegra::GPUVAddr addr, u64 size, int delta) {
+ const u64 num_pages = ((addr + size - 1) >> Tegra::MemoryManager::PAGE_BITS) -
+ (addr >> Tegra::MemoryManager::PAGE_BITS) + 1;
+ const u64 page_start = addr >> Tegra::MemoryManager::PAGE_BITS;
const u64 page_end = page_start + num_pages;
// Interval maps will erase segments if count reaches 0, so if delta is negative we have to
@@ -1406,8 +1443,10 @@ void RasterizerCacheOpenGL::UpdatePagesCachedCount(VAddr addr, u64 size, int del
const auto interval = pair.first & pages_interval;
const int count = pair.second;
- const VAddr interval_start_addr = boost::icl::first(interval) << Memory::PAGE_BITS;
- const VAddr interval_end_addr = boost::icl::last_next(interval) << Memory::PAGE_BITS;
+ const Tegra::GPUVAddr interval_start_addr = boost::icl::first(interval)
+ << Tegra::MemoryManager::PAGE_BITS;
+ const Tegra::GPUVAddr interval_end_addr = boost::icl::last_next(interval)
+ << Tegra::MemoryManager::PAGE_BITS;
const u64 interval_size = interval_end_addr - interval_start_addr;
if (delta > 0 && count == delta)
diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.h b/src/video_core/renderer_opengl/gl_rasterizer_cache.h
index e4cb3390f..55f1bdee8 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer_cache.h
+++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.h
@@ -17,12 +17,14 @@
#ifdef __GNUC__
#pragma GCC diagnostic pop
#endif
+#include <boost/optional.hpp>
#include <glad/glad.h>
#include "common/assert.h"
#include "common/common_funcs.h"
#include "common/common_types.h"
#include "common/math_util.h"
#include "video_core/gpu.h"
+#include "video_core/memory_manager.h"
#include "video_core/renderer_opengl/gl_resource_manager.h"
#include "video_core/textures/texture.h"
@@ -30,9 +32,9 @@ struct CachedSurface;
using Surface = std::shared_ptr<CachedSurface>;
using SurfaceSet = std::set<Surface>;
-using SurfaceRegions = boost::icl::interval_set<VAddr>;
-using SurfaceMap = boost::icl::interval_map<VAddr, Surface>;
-using SurfaceCache = boost::icl::interval_map<VAddr, SurfaceSet>;
+using SurfaceRegions = boost::icl::interval_set<Tegra::GPUVAddr>;
+using SurfaceMap = boost::icl::interval_map<Tegra::GPUVAddr, Surface>;
+using SurfaceCache = boost::icl::interval_map<Tegra::GPUVAddr, SurfaceSet>;
using SurfaceInterval = SurfaceCache::interval_type;
static_assert(std::is_same<SurfaceRegions::interval_type, SurfaceCache::interval_type>() &&
@@ -82,23 +84,49 @@ struct SurfaceParams {
Invalid = 4,
};
- static constexpr unsigned int GetFormatBpp(PixelFormat format) {
+ /**
+ * Gets the compression factor for the specified PixelFormat. This applies to just the
+ * "compressed width" and "compressed height", not the overall compression factor of a
+ * compressed image. This is used for maintaining proper surface sizes for compressed texture
+ * formats.
+ */
+ static constexpr u32 GetCompresssionFactor(PixelFormat format) {
if (format == PixelFormat::Invalid)
return 0;
- constexpr std::array<unsigned int, MaxPixelFormat> bpp_table = {
+ constexpr std::array<u32, MaxPixelFormat> compression_factor_table = {{
+ 1, // ABGR8
+ 1, // B5G6R5
+ 1, // A2B10G10R10
+ 4, // DXT1
+ 4, // DXT23
+ 4, // DXT45
+ }};
+
+ ASSERT(static_cast<size_t>(format) < compression_factor_table.size());
+ return compression_factor_table[static_cast<size_t>(format)];
+ }
+ u32 GetCompresssionFactor() const {
+ return GetCompresssionFactor(pixel_format);
+ }
+
+ static constexpr u32 GetFormatBpp(PixelFormat format) {
+ if (format == PixelFormat::Invalid)
+ return 0;
+
+ constexpr std::array<u32, MaxPixelFormat> bpp_table = {{
32, // ABGR8
16, // B5G6R5
32, // A2B10G10R10
64, // DXT1
128, // DXT23
128, // DXT45
- };
+ }};
ASSERT(static_cast<size_t>(format) < bpp_table.size());
return bpp_table[static_cast<size_t>(format)];
}
- unsigned int GetFormatBpp() const {
+ u32 GetFormatBpp() const {
return GetFormatBpp(pixel_format);
}
@@ -106,6 +134,8 @@ struct SurfaceParams {
switch (format) {
case Tegra::RenderTargetFormat::RGBA8_UNORM:
return PixelFormat::ABGR8;
+ case Tegra::RenderTargetFormat::RGB10_A2_UNORM:
+ return PixelFormat::A2B10G10R10;
default:
NGLOG_CRITICAL(HW_GPU, "Unimplemented format={}", static_cast<u32>(format));
UNREACHABLE();
@@ -251,6 +281,24 @@ struct SurfaceParams {
// Returns the region of the biggest valid rectange within interval
SurfaceInterval GetCopyableInterval(const Surface& src_surface) const;
+ /**
+ * Gets the actual width (in pixels) of the surface. This is provided because `width` is used
+ * for tracking the surface region in memory, which may be compressed for certain formats. In
+ * this scenario, `width` is actually the compressed width.
+ */
+ u32 GetActualWidth() const {
+ return width * GetCompresssionFactor();
+ }
+
+ /**
+ * Gets the actual height (in pixels) of the surface. This is provided because `height` is used
+ * for tracking the surface region in memory, which may be compressed for certain formats. In
+ * this scenario, `height` is actually the compressed height.
+ */
+ u32 GetActualHeight() const {
+ return height * GetCompresssionFactor();
+ }
+
u32 GetScaledWidth() const {
return width * res_scale;
}
@@ -275,6 +323,8 @@ struct SurfaceParams {
return pixels * GetFormatBpp(pixel_format) / CHAR_BIT;
}
+ VAddr GetCpuAddr() const;
+
bool ExactMatch(const SurfaceParams& other_surface) const;
bool CanSubRect(const SurfaceParams& sub_surface) const;
bool CanExpand(const SurfaceParams& expanded_surface) const;
@@ -283,8 +333,9 @@ struct SurfaceParams {
MathUtil::Rectangle<u32> GetSubRect(const SurfaceParams& sub_surface) const;
MathUtil::Rectangle<u32> GetScaledSubRect(const SurfaceParams& sub_surface) const;
- VAddr addr = 0;
- VAddr end = 0;
+ Tegra::GPUVAddr addr = 0;
+ Tegra::GPUVAddr end = 0;
+ boost::optional<VAddr> cpu_addr;
u64 size = 0;
u32 width = 0;
@@ -323,15 +374,15 @@ struct CachedSurface : SurfaceParams {
if (format == PixelFormat::Invalid)
return 0;
- return SurfaceParams::GetFormatBpp(format) / 8;
+ return SurfaceParams::GetFormatBpp(format) / CHAR_BIT;
}
std::unique_ptr<u8[]> gl_buffer;
size_t gl_buffer_size = 0;
// Read/Write data in Switch memory to/from gl_buffer
- void LoadGLBuffer(VAddr load_start, VAddr load_end);
- void FlushGLBuffer(VAddr flush_start, VAddr flush_end);
+ void LoadGLBuffer(Tegra::GPUVAddr load_start, Tegra::GPUVAddr load_end);
+ void FlushGLBuffer(Tegra::GPUVAddr flush_start, Tegra::GPUVAddr flush_end);
// Upload/Download data in gl_buffer in/to this surface's texture
void UploadGLTexture(const MathUtil::Rectangle<u32>& rect, GLuint read_fb_handle,
@@ -360,6 +411,9 @@ public:
Surface GetSurface(const SurfaceParams& params, ScaleMatch match_res_scale,
bool load_if_create);
+ /// Tries to find a framebuffer GPU address based on the provided CPU address
+ boost::optional<Tegra::GPUVAddr> TryFindFramebufferGpuAddress(VAddr cpu_addr) const;
+
/// Attempt to find a subrect (resolution scaled) of a surface, otherwise loads a texture from
/// Switch memory to OpenGL and caches it (if not already cached)
SurfaceRect_Tuple GetSurfaceSubRect(const SurfaceParams& params, ScaleMatch match_res_scale,
@@ -379,10 +433,10 @@ public:
SurfaceRect_Tuple GetTexCopySurface(const SurfaceParams& params);
/// Write any cached resources overlapping the region back to memory (if dirty)
- void FlushRegion(VAddr addr, u64 size, Surface flush_surface = nullptr);
+ void FlushRegion(Tegra::GPUVAddr addr, u64 size, Surface flush_surface = nullptr);
/// Mark region as being invalidated by region_owner (nullptr if Switch memory)
- void InvalidateRegion(VAddr addr, u64 size, const Surface& region_owner);
+ void InvalidateRegion(Tegra::GPUVAddr addr, u64 size, const Surface& region_owner);
/// Flush all cached resources tracked by this cache manager
void FlushAll();
@@ -391,7 +445,7 @@ private:
void DuplicateSurface(const Surface& src_surface, const Surface& dest_surface);
/// Update surface's texture for given region when necessary
- void ValidateSurface(const Surface& surface, VAddr addr, u64 size);
+ void ValidateSurface(const Surface& surface, Tegra::GPUVAddr addr, u64 size);
/// Create a new surface
Surface CreateSurface(const SurfaceParams& params);
@@ -403,7 +457,7 @@ private:
void UnregisterSurface(const Surface& surface);
/// Increase/decrease the number of surface in pages touching the specified region
- void UpdatePagesCachedCount(VAddr addr, u64 size, int delta);
+ void UpdatePagesCachedCount(Tegra::GPUVAddr addr, u64 size, int delta);
SurfaceCache surface_cache;
PageMap cached_pages;
diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
index 086424395..3dffb205d 100644
--- a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
@@ -519,7 +519,7 @@ private:
}
break;
}
- case OpCode::Type::FloatPredicate: {
+ case OpCode::Type::FloatSetPredicate: {
std::string op_a = instr.fsetp.neg_a ? "-" : "";
op_a += GetRegister(instr.gpr8);
@@ -570,6 +570,59 @@ private:
}
break;
}
+ case OpCode::Type::FloatSet: {
+ std::string dest = GetRegister(instr.gpr0);
+ std::string op_a = instr.fset.neg_a ? "-" : "";
+ op_a += GetRegister(instr.gpr8);
+
+ if (instr.fset.abs_a) {
+ op_a = "abs(" + op_a + ')';
+ }
+
+ std::string op_b = instr.fset.neg_b ? "-" : "";
+
+ if (instr.is_b_imm) {
+ std::string imm = GetImmediate19(instr);
+ if (instr.fset.neg_imm)
+ op_b += "(-" + imm + ')';
+ else
+ op_b += imm;
+ } else {
+ if (instr.is_b_gpr) {
+ op_b += GetRegister(instr.gpr20);
+ } else {
+ op_b += GetUniform(instr.uniform);
+ }
+ }
+
+ if (instr.fset.abs_b) {
+ op_b = "abs(" + op_b + ")";
+ }
+
+ using Tegra::Shader::Pred;
+ ASSERT_MSG(instr.fset.pred39 == static_cast<u64>(Pred::UnusedIndex),
+ "Compound predicates are not implemented");
+
+ // The fset instruction sets a register to 1.0 if the condition is true, and to 0
+ // otherwise.
+ using Tegra::Shader::PredCondition;
+ switch (instr.fset.cond) {
+ case PredCondition::LessThan:
+ SetDest(0, dest, "((" + op_a + ") < (" + op_b + ")) ? 1.0 : 0", 1, 1);
+ break;
+ case PredCondition::Equal:
+ SetDest(0, dest, "((" + op_a + ") == (" + op_b + ")) ? 1.0 : 0", 1, 1);
+ break;
+ case PredCondition::GreaterThan:
+ SetDest(0, dest, "((" + op_a + ") > (" + op_b + ")) ? 1.0 : 0", 1, 1);
+ break;
+ default:
+ NGLOG_CRITICAL(HW_GPU, "Unhandled predicate condition: {} (a: {}, b: {})",
+ static_cast<unsigned>(instr.fset.cond.Value()), op_a, op_b);
+ UNREACHABLE();
+ }
+ break;
+ }
default: {
switch (opcode->GetId()) {
case OpCode::Id::EXIT: {
diff --git a/src/video_core/renderer_opengl/renderer_opengl.cpp b/src/video_core/renderer_opengl/renderer_opengl.cpp
index ab0acb20a..77d1692f4 100644
--- a/src/video_core/renderer_opengl/renderer_opengl.cpp
+++ b/src/video_core/renderer_opengl/renderer_opengl.cpp
@@ -152,7 +152,8 @@ void RendererOpenGL::LoadFBToScreenInfo(const Tegra::FramebufferConfig& framebuf
screen_info.display_texture = screen_info.texture.resource.handle;
screen_info.display_texcoords = MathUtil::Rectangle<float>(0.f, 0.f, 1.f, 1.f);
- Rasterizer()->FlushRegion(framebuffer_addr, size_in_bytes);
+ Memory::RasterizerFlushVirtualRegion(framebuffer_addr, size_in_bytes,
+ Memory::FlushMode::Flush);
VideoCore::MortonCopyPixels128(framebuffer.width, framebuffer.height, bytes_per_pixel, 4,
Memory::GetPointer(framebuffer_addr),
@@ -269,10 +270,9 @@ void RendererOpenGL::ConfigureFramebufferTexture(TextureInfo& texture,
GLint internal_format;
switch (framebuffer.pixel_format) {
case Tegra::FramebufferConfig::PixelFormat::ABGR8:
- // Use RGBA8 and swap in the fragment shader
internal_format = GL_RGBA;
texture.gl_format = GL_RGBA;
- texture.gl_type = GL_UNSIGNED_INT_8_8_8_8;
+ texture.gl_type = GL_UNSIGNED_INT_8_8_8_8_REV;
gl_framebuffer_data.resize(texture.width * texture.height * 4);
break;
default:
@@ -295,17 +295,18 @@ void RendererOpenGL::DrawScreenTriangles(const ScreenInfo& screen_info, float x,
const auto& texcoords = screen_info.display_texcoords;
auto left = texcoords.left;
auto right = texcoords.right;
- if (framebuffer_transform_flags != Tegra::FramebufferConfig::TransformFlags::Unset)
+ if (framebuffer_transform_flags != Tegra::FramebufferConfig::TransformFlags::Unset) {
if (framebuffer_transform_flags == Tegra::FramebufferConfig::TransformFlags::FlipV) {
// Flip the framebuffer vertically
left = texcoords.right;
right = texcoords.left;
} else {
// Other transformations are unsupported
- LOG_CRITICAL(Render_OpenGL, "Unsupported framebuffer_transform_flags=%d",
- framebuffer_transform_flags);
+ NGLOG_CRITICAL(Render_OpenGL, "Unsupported framebuffer_transform_flags={}",
+ static_cast<u32>(framebuffer_transform_flags));
UNIMPLEMENTED();
}
+ }
std::array<ScreenRectVertex, 4> vertices = {{
ScreenRectVertex(x, y, texcoords.top, left),
@@ -427,9 +428,9 @@ bool RendererOpenGL::Init() {
const char* gpu_vendor{reinterpret_cast<char const*>(glGetString(GL_VENDOR))};
const char* gpu_model{reinterpret_cast<char const*>(glGetString(GL_RENDERER))};
- LOG_INFO(Render_OpenGL, "GL_VERSION: %s", gl_version);
- LOG_INFO(Render_OpenGL, "GL_VENDOR: %s", gpu_vendor);
- LOG_INFO(Render_OpenGL, "GL_RENDERER: %s", gpu_model);
+ NGLOG_INFO(Render_OpenGL, "GL_VERSION: {}", gl_version);
+ NGLOG_INFO(Render_OpenGL, "GL_VENDOR: {}", gpu_vendor);
+ NGLOG_INFO(Render_OpenGL, "GL_RENDERER: {}", gpu_model);
Core::Telemetry().AddField(Telemetry::FieldType::UserSystem, "GPU_Vendor", gpu_vendor);
Core::Telemetry().AddField(Telemetry::FieldType::UserSystem, "GPU_Model", gpu_model);