diff options
Diffstat (limited to 'src/video_core/renderer_opengl')
-rw-r--r-- | src/video_core/renderer_opengl/gl_rasterizer.cpp | 147 | ||||
-rw-r--r-- | src/video_core/renderer_opengl/gl_rasterizer.h | 13 | ||||
-rw-r--r-- | src/video_core/renderer_opengl/gl_rasterizer_cache.cpp | 147 | ||||
-rw-r--r-- | src/video_core/renderer_opengl/gl_rasterizer_cache.h | 86 | ||||
-rw-r--r-- | src/video_core/renderer_opengl/gl_shader_decompiler.cpp | 55 | ||||
-rw-r--r-- | src/video_core/renderer_opengl/renderer_opengl.cpp | 19 |
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); |