From b56e5edafcc18901c08634b1730f1e1870a14891 Mon Sep 17 00:00:00 2001 From: bunnei Date: Fri, 31 Aug 2018 23:54:31 -0400 Subject: [PATCH 01/10] gl_state: Keep track of texture target. --- .../renderer_opengl/gl_rasterizer.cpp | 6 +++--- .../renderer_opengl/gl_rasterizer_cache.cpp | 12 +++++------ src/video_core/renderer_opengl/gl_state.cpp | 8 ++++---- src/video_core/renderer_opengl/gl_state.h | 8 +++++--- .../renderer_opengl/renderer_opengl.cpp | 20 +++++++++---------- 5 files changed, 28 insertions(+), 26 deletions(-) diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp index 6e89fa6e31..d5bbfbd1c7 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp @@ -692,14 +692,14 @@ u32 RasterizerOpenGL::SetupTextures(Maxwell::ShaderStage stage, Shader& shader, const auto texture = maxwell3d.GetStageTexture(entry.GetStage(), entry.GetOffset()); if (!texture.enabled) { - state.texture_units[current_bindpoint].texture_2d = 0; + state.texture_units[current_bindpoint].texture = 0; continue; } texture_samplers[current_bindpoint].SyncWithConfig(texture.tsc); Surface surface = res_cache.GetTextureSurface(texture); if (surface != nullptr) { - state.texture_units[current_bindpoint].texture_2d = surface->Texture().handle; + state.texture_units[current_bindpoint].texture = surface->Texture().handle; state.texture_units[current_bindpoint].swizzle.r = MaxwellToGL::SwizzleSource(texture.tic.x_source); state.texture_units[current_bindpoint].swizzle.g = @@ -710,7 +710,7 @@ u32 RasterizerOpenGL::SetupTextures(Maxwell::ShaderStage stage, Shader& shader, MaxwellToGL::SwizzleSource(texture.tic.w_source); } else { // Can occur when texture addr is null or its memory is unmapped/invalid - state.texture_units[current_bindpoint].texture_2d = 0; + state.texture_units[current_bindpoint].texture = 0; } } diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp index f6b2c5a861..ea2e6a3a2f 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp @@ -363,8 +363,8 @@ static void AllocateSurfaceTexture(GLuint texture, const FormatTuple& format_tup OpenGLState cur_state = OpenGLState::GetCurState(); // Keep track of previous texture bindings - GLuint old_tex = cur_state.texture_units[0].texture_2d; - cur_state.texture_units[0].texture_2d = texture; + GLuint old_tex = cur_state.texture_units[0].texture; + cur_state.texture_units[0].texture = texture; cur_state.Apply(); glActiveTexture(GL_TEXTURE0); @@ -380,7 +380,7 @@ static void AllocateSurfaceTexture(GLuint texture, const FormatTuple& format_tup glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); // Restore previous texture bindings - cur_state.texture_units[0].texture_2d = old_tex; + cur_state.texture_units[0].texture = old_tex; cur_state.Apply(); } @@ -600,8 +600,8 @@ void CachedSurface::UploadGLTexture(GLuint read_fb_handle, GLuint draw_fb_handle GLuint target_tex = texture.handle; OpenGLState cur_state = OpenGLState::GetCurState(); - GLuint old_tex = cur_state.texture_units[0].texture_2d; - cur_state.texture_units[0].texture_2d = target_tex; + GLuint old_tex = cur_state.texture_units[0].texture; + cur_state.texture_units[0].texture = target_tex; cur_state.Apply(); // Ensure no bad interactions with GL_UNPACK_ALIGNMENT @@ -622,7 +622,7 @@ void CachedSurface::UploadGLTexture(GLuint read_fb_handle, GLuint draw_fb_handle glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); - cur_state.texture_units[0].texture_2d = old_tex; + cur_state.texture_units[0].texture = old_tex; cur_state.Apply(); } diff --git a/src/video_core/renderer_opengl/gl_state.cpp b/src/video_core/renderer_opengl/gl_state.cpp index 60a4defd1b..6f70deb962 100644 --- a/src/video_core/renderer_opengl/gl_state.cpp +++ b/src/video_core/renderer_opengl/gl_state.cpp @@ -200,9 +200,9 @@ void OpenGLState::Apply() const { const auto& texture_unit = texture_units[i]; const auto& cur_state_texture_unit = cur_state.texture_units[i]; - if (texture_unit.texture_2d != cur_state_texture_unit.texture_2d) { + if (texture_unit.texture != cur_state_texture_unit.texture) { glActiveTexture(TextureUnits::MaxwellTexture(static_cast(i)).Enum()); - glBindTexture(GL_TEXTURE_2D, texture_unit.texture_2d); + glBindTexture(texture_unit.target, texture_unit.texture); } if (texture_unit.sampler != cur_state_texture_unit.sampler) { glBindSampler(static_cast(i), texture_unit.sampler); @@ -214,7 +214,7 @@ void OpenGLState::Apply() const { texture_unit.swizzle.a != cur_state_texture_unit.swizzle.a) { std::array mask = {texture_unit.swizzle.r, texture_unit.swizzle.g, texture_unit.swizzle.b, texture_unit.swizzle.a}; - glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, mask.data()); + glTexParameteriv(texture_unit.target, GL_TEXTURE_SWIZZLE_RGBA, mask.data()); } } @@ -287,7 +287,7 @@ void OpenGLState::Apply() const { OpenGLState& OpenGLState::UnbindTexture(GLuint handle) { for (auto& unit : texture_units) { - if (unit.texture_2d == handle) { + if (unit.texture == handle) { unit.Unbind(); } } diff --git a/src/video_core/renderer_opengl/gl_state.h b/src/video_core/renderer_opengl/gl_state.h index 46e96a97d5..e3e24b9e73 100644 --- a/src/video_core/renderer_opengl/gl_state.h +++ b/src/video_core/renderer_opengl/gl_state.h @@ -94,8 +94,9 @@ public: // 3 texture units - one for each that is used in PICA fragment shader emulation struct TextureUnit { - GLuint texture_2d; // GL_TEXTURE_BINDING_2D - GLuint sampler; // GL_SAMPLER_BINDING + GLuint texture; // GL_TEXTURE_BINDING_2D + GLuint sampler; // GL_SAMPLER_BINDING + GLenum target; struct { GLint r; // GL_TEXTURE_SWIZZLE_R GLint g; // GL_TEXTURE_SWIZZLE_G @@ -104,7 +105,7 @@ public: } swizzle; void Unbind() { - texture_2d = 0; + texture = 0; swizzle.r = GL_RED; swizzle.g = GL_GREEN; swizzle.b = GL_BLUE; @@ -114,6 +115,7 @@ public: void Reset() { Unbind(); sampler = 0; + target = GL_TEXTURE_2D; } }; std::array texture_units; diff --git a/src/video_core/renderer_opengl/renderer_opengl.cpp b/src/video_core/renderer_opengl/renderer_opengl.cpp index 411a73d50f..ccff3e3429 100644 --- a/src/video_core/renderer_opengl/renderer_opengl.cpp +++ b/src/video_core/renderer_opengl/renderer_opengl.cpp @@ -177,7 +177,7 @@ void RendererOpenGL::LoadFBToScreenInfo(const Tegra::FramebufferConfig& framebuf Memory::GetPointer(framebuffer_addr), gl_framebuffer_data.data(), true); - state.texture_units[0].texture_2d = screen_info.texture.resource.handle; + state.texture_units[0].texture = screen_info.texture.resource.handle; state.Apply(); glActiveTexture(GL_TEXTURE0); @@ -194,7 +194,7 @@ void RendererOpenGL::LoadFBToScreenInfo(const Tegra::FramebufferConfig& framebuf glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); - state.texture_units[0].texture_2d = 0; + state.texture_units[0].texture = 0; state.Apply(); } } @@ -205,7 +205,7 @@ void RendererOpenGL::LoadFBToScreenInfo(const Tegra::FramebufferConfig& framebuf */ void RendererOpenGL::LoadColorToActiveGLTexture(u8 color_r, u8 color_g, u8 color_b, u8 color_a, const TextureInfo& texture) { - state.texture_units[0].texture_2d = texture.resource.handle; + state.texture_units[0].texture = texture.resource.handle; state.Apply(); glActiveTexture(GL_TEXTURE0); @@ -214,7 +214,7 @@ void RendererOpenGL::LoadColorToActiveGLTexture(u8 color_r, u8 color_g, u8 color // Update existing texture glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, framebuffer_data); - state.texture_units[0].texture_2d = 0; + state.texture_units[0].texture = 0; state.Apply(); } @@ -260,7 +260,7 @@ void RendererOpenGL::InitOpenGLObjects() { // Allocation of storage is deferred until the first frame, when we // know the framebuffer size. - state.texture_units[0].texture_2d = screen_info.texture.resource.handle; + state.texture_units[0].texture = screen_info.texture.resource.handle; state.Apply(); glActiveTexture(GL_TEXTURE0); @@ -272,7 +272,7 @@ void RendererOpenGL::InitOpenGLObjects() { screen_info.display_texture = screen_info.texture.resource.handle; - state.texture_units[0].texture_2d = 0; + state.texture_units[0].texture = 0; state.Apply(); // Clear screen to black @@ -305,14 +305,14 @@ void RendererOpenGL::ConfigureFramebufferTexture(TextureInfo& texture, UNREACHABLE(); } - state.texture_units[0].texture_2d = texture.resource.handle; + state.texture_units[0].texture = texture.resource.handle; state.Apply(); glActiveTexture(GL_TEXTURE0); glTexImage2D(GL_TEXTURE_2D, 0, internal_format, texture.width, texture.height, 0, texture.gl_format, texture.gl_type, nullptr); - state.texture_units[0].texture_2d = 0; + state.texture_units[0].texture = 0; state.Apply(); } @@ -354,14 +354,14 @@ void RendererOpenGL::DrawScreenTriangles(const ScreenInfo& screen_info, float x, ScreenRectVertex(x + w, y + h, texcoords.bottom * scale_u, right * scale_v), }}; - state.texture_units[0].texture_2d = screen_info.display_texture; + state.texture_units[0].texture = screen_info.display_texture; state.texture_units[0].swizzle = {GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA}; state.Apply(); glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(vertices), vertices.data()); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); - state.texture_units[0].texture_2d = 0; + state.texture_units[0].texture = 0; state.Apply(); } From a439f7b6e1ecbaebdba5396fea1c7b171fcd17e8 Mon Sep 17 00:00:00 2001 From: bunnei Date: Sat, 1 Sep 2018 02:09:26 -0400 Subject: [PATCH 02/10] gl_rasterizer_cache: Remove unused DownloadGLTexture. --- .../renderer_opengl/gl_rasterizer_cache.cpp | 50 ------------------- .../renderer_opengl/gl_rasterizer_cache.h | 1 - 2 files changed, 51 deletions(-) diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp index ea2e6a3a2f..0df1bbf6b3 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp @@ -626,55 +626,6 @@ void CachedSurface::UploadGLTexture(GLuint read_fb_handle, GLuint draw_fb_handle cur_state.Apply(); } -MICROPROFILE_DEFINE(OpenGL_TextureDL, "OpenGL", "Texture Download", MP_RGB(128, 192, 64)); -void CachedSurface::DownloadGLTexture(GLuint read_fb_handle, GLuint draw_fb_handle) { - if (params.type == SurfaceType::Fill) - return; - - MICROPROFILE_SCOPE(OpenGL_TextureDL); - - gl_buffer.resize(params.width * params.height * GetGLBytesPerPixel(params.pixel_format)); - - OpenGLState state = OpenGLState::GetCurState(); - OpenGLState prev_state = state; - SCOPE_EXIT({ prev_state.Apply(); }); - - const FormatTuple& tuple = GetFormatTuple(params.pixel_format, params.component_type); - - // Ensure no bad interactions with GL_PACK_ALIGNMENT - ASSERT(params.width * GetGLBytesPerPixel(params.pixel_format) % 4 == 0); - glPixelStorei(GL_PACK_ROW_LENGTH, static_cast(params.width)); - - const auto& rect{params.GetRect()}; - size_t buffer_offset = - (rect.bottom * params.width + rect.left) * GetGLBytesPerPixel(params.pixel_format); - - state.UnbindTexture(texture.handle); - state.draw.read_framebuffer = read_fb_handle; - state.Apply(); - - if (params.type == SurfaceType::ColorTexture) { - glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, - texture.handle, 0); - glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0, - 0); - } else if (params.type == SurfaceType::Depth) { - glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0); - glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, - texture.handle, 0); - glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0, 0); - } else { - glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0); - glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, - texture.handle, 0); - } - glReadPixels(static_cast(rect.left), static_cast(rect.bottom), - static_cast(rect.GetWidth()), static_cast(rect.GetHeight()), - tuple.format, tuple.type, &gl_buffer[buffer_offset]); - - glPixelStorei(GL_PACK_ROW_LENGTH, 0); -} - RasterizerCacheOpenGL::RasterizerCacheOpenGL() { read_framebuffer.Create(); draw_framebuffer.Create(); @@ -748,7 +699,6 @@ void RasterizerCacheOpenGL::LoadSurface(const Surface& surface) { } void RasterizerCacheOpenGL::FlushSurface(const Surface& surface) { - surface->DownloadGLTexture(read_framebuffer.handle, draw_framebuffer.handle); surface->FlushGLBuffer(); } diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.h b/src/video_core/renderer_opengl/gl_rasterizer_cache.h index aad75f2006..b17867f647 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer_cache.h +++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.h @@ -726,7 +726,6 @@ public: // Upload/Download data in gl_buffer in/to this surface's texture void UploadGLTexture(GLuint read_fb_handle, GLuint draw_fb_handle); - void DownloadGLTexture(GLuint read_fb_handle, GLuint draw_fb_handle); private: OGLTexture texture; From 030676b95d8f0c0cd6c288f59daf94bbda6c7133 Mon Sep 17 00:00:00 2001 From: bunnei Date: Sat, 1 Sep 2018 02:42:43 -0400 Subject: [PATCH 03/10] gl_rasterizer_cache: Keep track of texture type per surface. --- .../renderer_opengl/gl_rasterizer.cpp | 1 + .../renderer_opengl/gl_rasterizer_cache.cpp | 80 ++++++++++++------- .../renderer_opengl/gl_rasterizer_cache.h | 35 +++++++- 3 files changed, 84 insertions(+), 32 deletions(-) diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp index d5bbfbd1c7..5deee20dd9 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp @@ -700,6 +700,7 @@ u32 RasterizerOpenGL::SetupTextures(Maxwell::ShaderStage stage, Shader& shader, Surface surface = res_cache.GetTextureSurface(texture); if (surface != nullptr) { state.texture_units[current_bindpoint].texture = surface->Texture().handle; + state.texture_units[current_bindpoint].target = surface->Target(); state.texture_units[current_bindpoint].swizzle.r = MaxwellToGL::SwizzleSource(texture.tic.x_source); state.texture_units[current_bindpoint].swizzle.g = diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp index 0df1bbf6b3..4d6fd8b8be 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp @@ -55,6 +55,7 @@ static VAddr TryGetCpuAddr(Tegra::GPUVAddr gpu_addr) { params.size_in_bytes = params.SizeInBytes(); params.cache_width = Common::AlignUp(params.width, 16); params.cache_height = Common::AlignUp(params.height, 16); + params.target = SurfaceTargetFromTextureType(config.tic.texture_type); return params; } @@ -73,6 +74,7 @@ static VAddr TryGetCpuAddr(Tegra::GPUVAddr gpu_addr) { params.size_in_bytes = params.SizeInBytes(); params.cache_width = Common::AlignUp(params.width, 16); params.cache_height = Common::AlignUp(params.height, 16); + params.target = SurfaceTarget::Texture2D; return params; } @@ -93,6 +95,7 @@ static VAddr TryGetCpuAddr(Tegra::GPUVAddr gpu_addr) { params.size_in_bytes = params.SizeInBytes(); params.cache_width = Common::AlignUp(params.width, 16); params.cache_height = Common::AlignUp(params.height, 16); + params.target = SurfaceTarget::Texture2D; return params; } @@ -166,6 +169,26 @@ static constexpr std::array tex_form ComponentType::Float, false}, // Z32FS8 }}; +static GLenum SurfaceTargetToGL(SurfaceParams::SurfaceTarget target) { + switch (target) { + case SurfaceParams::SurfaceTarget::Texture1D: + return GL_TEXTURE_1D; + case SurfaceParams::SurfaceTarget::Texture2D: + return GL_TEXTURE_2D; + case SurfaceParams::SurfaceTarget::Texture3D: + return GL_TEXTURE_3D; + case SurfaceParams::SurfaceTarget::Texture1DArray: + return GL_TEXTURE_1D_ARRAY; + case SurfaceParams::SurfaceTarget::Texture2DArray: + return GL_TEXTURE_2D_ARRAY; + case SurfaceParams::SurfaceTarget::TextureCubemap: + return GL_TEXTURE_CUBE_MAP; + } + LOG_CRITICAL(Render_OpenGL, "Unimplemented texture target={}", static_cast(target)); + UNREACHABLE(); + return {}; +} + static const FormatTuple& GetFormatTuple(PixelFormat pixel_format, ComponentType component_type) { ASSERT(static_cast(pixel_format) < tex_format_tuples.size()); auto& format = tex_format_tuples[static_cast(pixel_format)]; @@ -357,33 +380,6 @@ static constexpr std::array&, VAddr), // clang-format on }; -// Allocate an uninitialized texture of appropriate size and format for the surface -static void AllocateSurfaceTexture(GLuint texture, const FormatTuple& format_tuple, u32 width, - u32 height) { - OpenGLState cur_state = OpenGLState::GetCurState(); - - // Keep track of previous texture bindings - GLuint old_tex = cur_state.texture_units[0].texture; - cur_state.texture_units[0].texture = texture; - cur_state.Apply(); - glActiveTexture(GL_TEXTURE0); - - if (!format_tuple.compressed) { - // Only pre-create the texture for non-compressed textures. - glTexImage2D(GL_TEXTURE_2D, 0, format_tuple.internal_format, width, height, 0, - format_tuple.format, format_tuple.type, nullptr); - } - - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - - // Restore previous texture bindings - cur_state.texture_units[0].texture = old_tex; - cur_state.Apply(); -} - static bool BlitTextures(GLuint src_tex, const MathUtil::Rectangle& src_rect, GLuint dst_tex, const MathUtil::Rectangle& dst_rect, SurfaceType type, GLuint read_fb_handle, GLuint draw_fb_handle) { @@ -438,12 +434,34 @@ static bool BlitTextures(GLuint src_tex, const MathUtil::Rectangle& src_rec return true; } -CachedSurface::CachedSurface(const SurfaceParams& params) : params(params) { +CachedSurface::CachedSurface(const SurfaceParams& params) + : params(params), gl_target(SurfaceTargetToGL(params.target)) { texture.Create(); const auto& rect{params.GetRect()}; - AllocateSurfaceTexture(texture.handle, - GetFormatTuple(params.pixel_format, params.component_type), - rect.GetWidth(), rect.GetHeight()); + + OpenGLState cur_state = OpenGLState::GetCurState(); + + // Keep track of previous texture bindings + GLuint old_tex = cur_state.texture_units[0].texture; + cur_state.texture_units[0].texture = texture.handle; + cur_state.Apply(); + glActiveTexture(GL_TEXTURE0); + + const auto& format_tuple = GetFormatTuple(params.pixel_format, params.component_type); + if (!format_tuple.compressed) { + // Only pre-create the texture for non-compressed textures. + glTexImage2D(GL_TEXTURE_2D, 0, format_tuple.internal_format, rect.GetWidth(), + rect.GetHeight(), 0, format_tuple.format, format_tuple.type, nullptr); + } + + glTexParameteri(SurfaceTargetToGL(params.target), GL_TEXTURE_MAX_LEVEL, 0); + glTexParameteri(SurfaceTargetToGL(params.target), GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(SurfaceTargetToGL(params.target), GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(SurfaceTargetToGL(params.target), GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + + // Restore previous texture bindings + cur_state.texture_units[0].texture = old_tex; + cur_state.Apply(); } static void ConvertS8Z24ToZ24S8(std::vector& data, u32 width, u32 height) { diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.h b/src/video_core/renderer_opengl/gl_rasterizer_cache.h index b17867f647..6693b5cdaf 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer_cache.h +++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.h @@ -109,6 +109,33 @@ struct SurfaceParams { Invalid = 4, }; + enum class SurfaceTarget { + Texture1D, + Texture2D, + Texture3D, + Texture1DArray, + Texture2DArray, + TextureCubemap, + }; + + static SurfaceTarget SurfaceTargetFromTextureType(Tegra::Texture::TextureType texture_type) { + switch (texture_type) { + case Tegra::Texture::TextureType::Texture1D: + return SurfaceTarget::Texture1D; + case Tegra::Texture::TextureType::Texture2D: + case Tegra::Texture::TextureType::Texture2DNoMipmap: + return SurfaceTarget::Texture2D; + case Tegra::Texture::TextureType::Texture1DArray: + return SurfaceTarget::Texture1DArray; + case Tegra::Texture::TextureType::Texture2DArray: + return SurfaceTarget::Texture2DArray; + default: + LOG_CRITICAL(HW_GPU, "Unimplemented texture_type={}", static_cast(texture_type)); + UNREACHABLE(); + return SurfaceTarget::Texture2D; + } + } + /** * 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 @@ -666,6 +693,7 @@ struct SurfaceParams { u32 height; u32 unaligned_height; size_t size_in_bytes; + SurfaceTarget target; // Parameters used for caching only u32 cache_width; @@ -709,6 +737,10 @@ public: return texture; } + GLenum Target() const { + return gl_target; + } + static constexpr unsigned int GetGLBytesPerPixel(SurfaceParams::PixelFormat format) { if (format == SurfaceParams::PixelFormat::Invalid) return 0; @@ -724,13 +756,14 @@ public: void LoadGLBuffer(); void FlushGLBuffer(); - // Upload/Download data in gl_buffer in/to this surface's texture + // Upload data in gl_buffer to this surface's texture void UploadGLTexture(GLuint read_fb_handle, GLuint draw_fb_handle); private: OGLTexture texture; std::vector gl_buffer; SurfaceParams params; + GLenum gl_target; }; class RasterizerCacheOpenGL final : public RasterizerCache { From 9dccf7e1fadb8c54d3afe09be53e75d8ac461d3d Mon Sep 17 00:00:00 2001 From: bunnei Date: Tue, 4 Sep 2018 19:24:54 -0400 Subject: [PATCH 04/10] gl_rasterizer_cache: Remove impl. of FlushGLBuffer. - Will not work for non-2d textures, and was not used anyways. --- .../renderer_opengl/gl_rasterizer_cache.cpp | 35 +------------------ 1 file changed, 1 insertion(+), 34 deletions(-) diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp index 4d6fd8b8be..df99dd521b 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp @@ -532,23 +532,6 @@ static void ConvertFormatAsNeeded_LoadGLBuffer(std::vector& data, PixelForma } } -/** - * Helper function to perform software conversion (as needed) when flushing a buffer to Switch - * memory. This is for Maxwell pixel formats that cannot be represented as-is in OpenGL or with - * typical desktop GPUs. - */ -static void ConvertFormatAsNeeded_FlushGLBuffer(std::vector& /*data*/, PixelFormat pixel_format, - u32 /*width*/, u32 /*height*/) { - switch (pixel_format) { - case PixelFormat::ASTC_2D_4X4: - case PixelFormat::S8Z24: - LOG_CRITICAL(Render_OpenGL, "Unimplemented pixel_format={}", - static_cast(pixel_format)); - UNREACHABLE(); - break; - } -} - MICROPROFILE_DEFINE(OpenGL_SurfaceLoad, "OpenGL", "Surface Load", MP_RGB(128, 64, 192)); void CachedSurface::LoadGLBuffer() { ASSERT(params.type != SurfaceType::Fill); @@ -578,23 +561,7 @@ void CachedSurface::LoadGLBuffer() { MICROPROFILE_DEFINE(OpenGL_SurfaceFlush, "OpenGL", "Surface Flush", MP_RGB(128, 192, 64)); void CachedSurface::FlushGLBuffer() { - u8* const dst_buffer = Memory::GetPointer(params.addr); - - ASSERT(dst_buffer); - ASSERT(gl_buffer.size() == - params.width * params.height * GetGLBytesPerPixel(params.pixel_format)); - - MICROPROFILE_SCOPE(OpenGL_SurfaceFlush); - - ConvertFormatAsNeeded_FlushGLBuffer(gl_buffer, params.pixel_format, params.width, - params.height); - - if (!params.is_tiled) { - std::memcpy(dst_buffer, gl_buffer.data(), params.size_in_bytes); - } else { - gl_to_morton_fns[static_cast(params.pixel_format)]( - params.width, params.block_height, params.height, gl_buffer, params.addr); - } + ASSERT_MSG(false, "Unimplemented"); } MICROPROFILE_DEFINE(OpenGL_TextureUL, "OpenGL", "Texture Upload", MP_RGB(128, 64, 192)); From ce8291f6c5a7e0dba5e7d72e94de06bf4423d539 Mon Sep 17 00:00:00 2001 From: bunnei Date: Tue, 4 Sep 2018 22:00:24 -0400 Subject: [PATCH 05/10] gl_rasterizer_cache: Track texture depth. --- .../renderer_opengl/gl_rasterizer_cache.cpp | 4 +++- src/video_core/renderer_opengl/gl_rasterizer_cache.h | 3 ++- src/video_core/textures/texture.h | 12 ++++++++++-- 3 files changed, 15 insertions(+), 4 deletions(-) diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp index df99dd521b..1a44de332a 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp @@ -51,6 +51,7 @@ static VAddr TryGetCpuAddr(Tegra::GPUVAddr gpu_addr) { params.type = GetFormatType(params.pixel_format); params.width = Common::AlignUp(config.tic.Width(), GetCompressionFactor(params.pixel_format)); params.height = Common::AlignUp(config.tic.Height(), GetCompressionFactor(params.pixel_format)); + params.depth = config.tic.Depth(); params.unaligned_height = config.tic.Height(); params.size_in_bytes = params.SizeInBytes(); params.cache_width = Common::AlignUp(params.width, 16); @@ -70,6 +71,7 @@ static VAddr TryGetCpuAddr(Tegra::GPUVAddr gpu_addr) { params.type = GetFormatType(params.pixel_format); params.width = config.width; params.height = config.height; + params.depth = 1; params.unaligned_height = config.height; params.size_in_bytes = params.SizeInBytes(); params.cache_width = Common::AlignUp(params.width, 16); @@ -88,9 +90,9 @@ static VAddr TryGetCpuAddr(Tegra::GPUVAddr gpu_addr) { params.pixel_format = PixelFormatFromDepthFormat(format); params.component_type = ComponentTypeFromDepthFormat(format); params.type = GetFormatType(params.pixel_format); - params.size_in_bytes = params.SizeInBytes(); params.width = zeta_width; params.height = zeta_height; + params.depth = 1; params.unaligned_height = zeta_height; params.size_in_bytes = params.SizeInBytes(); params.cache_width = Common::AlignUp(params.width, 16); diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.h b/src/video_core/renderer_opengl/gl_rasterizer_cache.h index 6693b5cdaf..56022ea01e 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer_cache.h +++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.h @@ -662,7 +662,7 @@ struct SurfaceParams { ASSERT(width % compression_factor == 0); ASSERT(height % compression_factor == 0); return (width / compression_factor) * (height / compression_factor) * - GetFormatBpp(pixel_format) / CHAR_BIT; + GetFormatBpp(pixel_format) * depth / CHAR_BIT; } /// Creates SurfaceParams from a texture configuration @@ -691,6 +691,7 @@ struct SurfaceParams { SurfaceType type; u32 width; u32 height; + u32 depth; u32 unaligned_height; size_t size_in_bytes; SurfaceTarget target; diff --git a/src/video_core/textures/texture.h b/src/video_core/textures/texture.h index c6bd2f4b9d..c2fb824b2a 100644 --- a/src/video_core/textures/texture.h +++ b/src/video_core/textures/texture.h @@ -170,8 +170,12 @@ struct TICEntry { BitField<0, 16, u32> width_minus_1; BitField<23, 4, TextureType> texture_type; }; - u16 height_minus_1; - INSERT_PADDING_BYTES(10); + union { + BitField<0, 16, u32> height_minus_1; + BitField<16, 15, u32> depth_minus_1; + }; + + INSERT_PADDING_BYTES(8); GPUVAddr Address() const { return static_cast((static_cast(address_high) << 32) | address_low); @@ -192,6 +196,10 @@ struct TICEntry { return height_minus_1 + 1; } + u32 Depth() const { + return depth_minus_1 + 1; + } + u32 BlockHeight() const { ASSERT(header_version == TICHeaderVersion::BlockLinear || header_version == TICHeaderVersion::BlockLinearColorKey); From 05f6f59ffba2253e7c47263c919ef374e53571e5 Mon Sep 17 00:00:00 2001 From: bunnei Date: Wed, 5 Sep 2018 23:25:06 -0400 Subject: [PATCH 06/10] gl_rasterizer: Implement texture wrap mode p. --- src/video_core/renderer_opengl/gl_rasterizer.cpp | 9 +++++++-- src/video_core/renderer_opengl/gl_rasterizer.h | 1 + 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp index 5deee20dd9..e6eb829eb8 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp @@ -580,7 +580,7 @@ bool RasterizerOpenGL::AccelerateDisplay(const Tegra::FramebufferConfig& config, void RasterizerOpenGL::SamplerInfo::Create() { sampler.Create(); mag_filter = min_filter = Tegra::Texture::TextureFilter::Linear; - wrap_u = wrap_v = Tegra::Texture::WrapMode::Wrap; + wrap_u = wrap_v = wrap_p = Tegra::Texture::WrapMode::Wrap; // default is GL_LINEAR_MIPMAP_LINEAR glSamplerParameteri(sampler.handle, GL_TEXTURE_MIN_FILTER, GL_LINEAR); @@ -607,8 +607,13 @@ void RasterizerOpenGL::SamplerInfo::SyncWithConfig(const Tegra::Texture::TSCEntr wrap_v = config.wrap_v; glSamplerParameteri(s, GL_TEXTURE_WRAP_T, MaxwellToGL::WrapMode(wrap_v)); } + if (wrap_p != config.wrap_p) { + wrap_p = config.wrap_p; + glSamplerParameteri(s, GL_TEXTURE_WRAP_R, MaxwellToGL::WrapMode(wrap_p)); + } - if (wrap_u == Tegra::Texture::WrapMode::Border || wrap_v == Tegra::Texture::WrapMode::Border) { + if (wrap_u == Tegra::Texture::WrapMode::Border || wrap_v == Tegra::Texture::WrapMode::Border || + wrap_p == Tegra::Texture::WrapMode::Border) { const GLvec4 new_border_color = {{config.border_color_r, config.border_color_g, config.border_color_b, config.border_color_a}}; if (border_color != new_border_color) { diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h index 9c30dc0e8f..c6bb1516bf 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.h +++ b/src/video_core/renderer_opengl/gl_rasterizer.h @@ -93,6 +93,7 @@ private: Tegra::Texture::TextureFilter min_filter; Tegra::Texture::WrapMode wrap_u; Tegra::Texture::WrapMode wrap_v; + Tegra::Texture::WrapMode wrap_p; GLvec4 border_color; }; From 07313831240243396c212ece04d25c976eaa5381 Mon Sep 17 00:00:00 2001 From: bunnei Date: Thu, 6 Sep 2018 18:45:49 -0400 Subject: [PATCH 07/10] gl_shader_decompiler: Partially implement several non-2D texture types (Subv). --- .../renderer_opengl/gl_shader_decompiler.cpp | 125 ++++++++++++++---- .../renderer_opengl/gl_shader_gen.h | 50 ++++++- 2 files changed, 143 insertions(+), 32 deletions(-) diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp index 841647ebee..172ba83356 100644 --- a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp +++ b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp @@ -443,13 +443,12 @@ public: } declarations.AddNewLine(); - // Append the sampler2D array for the used textures. - const size_t num_samplers = used_samplers.size(); - if (num_samplers > 0) { - declarations.AddLine("uniform sampler2D " + SamplerEntry::GetArrayName(stage) + '[' + - std::to_string(num_samplers) + "];"); - declarations.AddNewLine(); + const auto& samplers = GetSamplers(); + for (const auto& sampler : samplers) { + declarations.AddLine("uniform " + sampler.GetTypeString() + ' ' + sampler.GetName() + + ';'); } + declarations.AddNewLine(); } /// Returns a list of constant buffer declarations @@ -461,13 +460,14 @@ public: } /// Returns a list of samplers used in the shader - std::vector GetSamplers() const { + const std::vector& GetSamplers() const { return used_samplers; } /// Returns the GLSL sampler used for the input shader sampler, and creates a new one if /// necessary. - std::string AccessSampler(const Sampler& sampler) { + std::string AccessSampler(const Sampler& sampler, Tegra::Shader::TextureType type, + bool is_array) { size_t offset = static_cast(sampler.index.Value()); // If this sampler has already been used, return the existing mapping. @@ -476,12 +476,13 @@ public: [&](const SamplerEntry& entry) { return entry.GetOffset() == offset; }); if (itr != used_samplers.end()) { + ASSERT(itr->GetType() == type && itr->IsArray() == is_array); return itr->GetName(); } // Otherwise create a new mapping for this sampler size_t next_index = used_samplers.size(); - SamplerEntry entry{stage, offset, next_index}; + SamplerEntry entry{stage, offset, next_index, type, is_array}; used_samplers.emplace_back(entry); return entry.GetName(); } @@ -722,8 +723,8 @@ private: } /// Generates code representing a texture sampler. - std::string GetSampler(const Sampler& sampler) { - return regs.AccessSampler(sampler); + std::string GetSampler(const Sampler& sampler, Tegra::Shader::TextureType type, bool is_array) { + return regs.AccessSampler(sampler, type, is_array); } /** @@ -1753,10 +1754,35 @@ private: break; } case OpCode::Id::TEX: { - const std::string op_a = regs.GetRegisterAsFloat(instr.gpr8); - const std::string op_b = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1); - const std::string sampler = GetSampler(instr.sampler); - const std::string coord = "vec2 coords = vec2(" + op_a + ", " + op_b + ");"; + ASSERT_MSG(instr.tex.array == 0, "TEX arrays unimplemented"); + Tegra::Shader::TextureType texture_type{instr.tex.texture_type}; + std::string coord; + + switch (texture_type) { + case Tegra::Shader::TextureType::Texture1D: { + std::string x = regs.GetRegisterAsFloat(instr.gpr8); + coord = "float coords = " + x + ';'; + break; + } + case Tegra::Shader::TextureType::Texture2D: { + std::string x = regs.GetRegisterAsFloat(instr.gpr8); + std::string y = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1); + coord = "vec2 coords = vec2(" + x + ", " + y + ");"; + break; + } + default: + LOG_CRITICAL(HW_GPU, "Unhandled texture type {}", + static_cast(texture_type)); + UNREACHABLE(); + + // Fallback to interpreting as a 2D texture for now + std::string x = regs.GetRegisterAsFloat(instr.gpr8); + std::string y = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1); + coord = "vec2 coords = vec2(" + x + ", " + y + ");"; + texture_type = Tegra::Shader::TextureType::Texture2D; + } + + const std::string sampler = GetSampler(instr.sampler, texture_type, false); // Add an extra scope and declare the texture coords inside to prevent // overwriting them in case they are used as outputs of the texs instruction. shader.AddLine("{"); @@ -1778,20 +1804,65 @@ private: break; } case OpCode::Id::TEXS: { - const std::string op_a = regs.GetRegisterAsFloat(instr.gpr8); - const std::string op_b = regs.GetRegisterAsFloat(instr.gpr20); - const std::string sampler = GetSampler(instr.sampler); - const std::string coord = "vec2 coords = vec2(" + op_a + ", " + op_b + ");"; + std::string coord; + Tegra::Shader::TextureType texture_type{instr.texs.GetTextureType()}; + bool is_array{instr.texs.IsArrayTexture()}; + switch (texture_type) { + case Tegra::Shader::TextureType::Texture2D: { + if (is_array) { + std::string index = regs.GetRegisterAsInteger(instr.gpr8); + std::string x = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1); + std::string y = regs.GetRegisterAsFloat(instr.gpr20); + coord = "vec3 coords = vec3(" + x + ", " + y + ", " + index + ");"; + } else { + std::string x = regs.GetRegisterAsFloat(instr.gpr8); + std::string y = regs.GetRegisterAsFloat(instr.gpr20); + coord = "vec2 coords = vec2(" + x + ", " + y + ");"; + } + break; + } + default: + LOG_CRITICAL(HW_GPU, "Unhandled texture type {}", + static_cast(texture_type)); + UNREACHABLE(); + + // Fallback to interpreting as a 2D texture for now + std::string x = regs.GetRegisterAsFloat(instr.gpr8); + std::string y = regs.GetRegisterAsFloat(instr.gpr20); + coord = "vec2 coords = vec2(" + x + ", " + y + ");"; + texture_type = Tegra::Shader::TextureType::Texture2D; + is_array = false; + } + const std::string sampler = GetSampler(instr.sampler, texture_type, is_array); const std::string texture = "texture(" + sampler + ", coords)"; WriteTexsInstruction(instr, coord, texture); break; } case OpCode::Id::TLDS: { - const std::string op_a = regs.GetRegisterAsInteger(instr.gpr8); - const std::string op_b = regs.GetRegisterAsInteger(instr.gpr20); - const std::string sampler = GetSampler(instr.sampler); - const std::string coord = "ivec2 coords = ivec2(" + op_a + ", " + op_b + ");"; + ASSERT(instr.tlds.GetTextureType() == Tegra::Shader::TextureType::Texture2D); + ASSERT(instr.tlds.IsArrayTexture() == false); + std::string coord; + + switch (instr.tlds.GetTextureType()) { + case Tegra::Shader::TextureType::Texture2D: { + if (instr.tlds.IsArrayTexture()) { + LOG_CRITICAL(HW_GPU, "Unhandled 2d array texture"); + UNREACHABLE(); + } else { + std::string x = regs.GetRegisterAsInteger(instr.gpr8); + std::string y = regs.GetRegisterAsInteger(instr.gpr20); + coord = "ivec2 coords = ivec2(" + x + ", " + y + ");"; + } + break; + } + default: + LOG_CRITICAL(HW_GPU, "Unhandled texture type {}", + static_cast(instr.tlds.GetTextureType())); + UNREACHABLE(); + } + const std::string sampler = GetSampler(instr.sampler, instr.tlds.GetTextureType(), + instr.tlds.IsArrayTexture()); const std::string texture = "texelFetch(" + sampler + ", coords, 0)"; WriteTexsInstruction(instr, coord, texture); break; @@ -1799,7 +1870,7 @@ private: case OpCode::Id::TLD4: { ASSERT(instr.tld4.texture_type == Tegra::Shader::TextureType::Texture2D); ASSERT(instr.tld4.array == 0); - std::string coord{}; + std::string coord; switch (instr.tld4.texture_type) { case Tegra::Shader::TextureType::Texture2D: { @@ -1814,7 +1885,8 @@ private: UNREACHABLE(); } - const std::string sampler = GetSampler(instr.sampler); + const std::string sampler = + GetSampler(instr.sampler, instr.tld4.texture_type, false); // Add an extra scope and declare the texture coords inside to prevent // overwriting them in case they are used as outputs of the texs instruction. shader.AddLine("{"); @@ -1840,7 +1912,8 @@ private: const std::string op_a = regs.GetRegisterAsFloat(instr.gpr8); const std::string op_b = regs.GetRegisterAsFloat(instr.gpr20); // TODO(Subv): Figure out how the sampler type is encoded in the TLD4S instruction. - const std::string sampler = GetSampler(instr.sampler); + const std::string sampler = + GetSampler(instr.sampler, Tegra::Shader::TextureType::Texture2D, false); const std::string coord = "vec2 coords = vec2(" + op_a + ", " + op_b + ");"; const std::string texture = "textureGather(" + sampler + ", coords, " + std::to_string(instr.tld4s.component) + ')'; diff --git a/src/video_core/renderer_opengl/gl_shader_gen.h b/src/video_core/renderer_opengl/gl_shader_gen.h index cbb2090ea2..a43e2997b5 100644 --- a/src/video_core/renderer_opengl/gl_shader_gen.h +++ b/src/video_core/renderer_opengl/gl_shader_gen.h @@ -9,6 +9,7 @@ #include #include "common/common_types.h" +#include "video_core/engines/shader_bytecode.h" namespace OpenGL::GLShader { @@ -73,8 +74,9 @@ class SamplerEntry { using Maxwell = Tegra::Engines::Maxwell3D::Regs; public: - SamplerEntry(Maxwell::ShaderStage stage, size_t offset, size_t index) - : offset(offset), stage(stage), sampler_index(index) {} + SamplerEntry(Maxwell::ShaderStage stage, size_t offset, size_t index, + Tegra::Shader::TextureType type, bool is_array) + : offset(offset), stage(stage), sampler_index(index), type(type), is_array(is_array) {} size_t GetOffset() const { return offset; @@ -89,8 +91,41 @@ public: } std::string GetName() const { - return std::string(TextureSamplerNames[static_cast(stage)]) + '[' + - std::to_string(sampler_index) + ']'; + return std::string(TextureSamplerNames[static_cast(stage)]) + '_' + + std::to_string(sampler_index); + } + + std::string GetTypeString() const { + using Tegra::Shader::TextureType; + std::string glsl_type; + + switch (type) { + case TextureType::Texture1D: + glsl_type = "sampler1D"; + break; + case TextureType::Texture2D: + glsl_type = "sampler2D"; + break; + case TextureType::Texture3D: + glsl_type = "sampler3D"; + break; + case TextureType::TextureCube: + glsl_type = "samplerCube"; + break; + default: + UNIMPLEMENTED(); + } + if (is_array) + glsl_type += "Array"; + return glsl_type; + } + + Tegra::Shader::TextureType GetType() const { + return type; + } + + bool IsArray() const { + return is_array; } u32 GetHash() const { @@ -105,11 +140,14 @@ private: static constexpr std::array TextureSamplerNames = { "tex_vs", "tex_tessc", "tex_tesse", "tex_gs", "tex_fs", }; + /// Offset in TSC memory from which to read the sampler object, as specified by the sampling /// instruction. size_t offset; - Maxwell::ShaderStage stage; ///< Shader stage where this sampler was used. - size_t sampler_index; ///< Value used to index into the generated GLSL sampler array. + Maxwell::ShaderStage stage; ///< Shader stage where this sampler was used. + size_t sampler_index; ///< Value used to index into the generated GLSL sampler array. + Tegra::Shader::TextureType type; ///< The type used to sample this texture (Texture2D, etc) + bool is_array; ///< Whether the texture is being sampled as an array texture or not. }; struct ShaderEntries { From f165a85398f48504541a7ab9aedee1b517dfd863 Mon Sep 17 00:00:00 2001 From: bunnei Date: Thu, 6 Sep 2018 19:08:45 -0400 Subject: [PATCH 08/10] gl_rasterizer_cache: Partially implement several non-2D texture types. --- .../renderer_opengl/gl_rasterizer_cache.cpp | 143 ++++++++++++++---- 1 file changed, 112 insertions(+), 31 deletions(-) diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp index 1a44de332a..e9fd67d004 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp @@ -245,7 +245,8 @@ static bool IsFormatBCn(PixelFormat format) { } template -void MortonCopy(u32 stride, u32 block_height, u32 height, std::vector& gl_buffer, VAddr addr) { +void MortonCopy(u32 stride, u32 block_height, u32 height, u8* gl_buffer, size_t gl_buffer_size, + VAddr addr) { constexpr u32 bytes_per_pixel = SurfaceParams::GetFormatBpp(format) / CHAR_BIT; constexpr u32 gl_bytes_per_pixel = CachedSurface::GetGLBytesPerPixel(format); @@ -255,18 +256,18 @@ void MortonCopy(u32 stride, u32 block_height, u32 height, std::vector& gl_bu const u32 tile_size{IsFormatBCn(format) ? 4U : 1U}; const std::vector data = Tegra::Texture::UnswizzleTexture( addr, tile_size, bytes_per_pixel, stride, height, block_height); - const size_t size_to_copy{std::min(gl_buffer.size(), data.size())}; - gl_buffer.assign(data.begin(), data.begin() + size_to_copy); + const size_t size_to_copy{std::min(gl_buffer_size, data.size())}; + memcpy(gl_buffer, data.data(), size_to_copy); } 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(addr), gl_buffer.data(), morton_to_gl); + Memory::GetPointer(addr), gl_buffer, morton_to_gl); } } -static constexpr std::array&, VAddr), +static constexpr std::array morton_to_gl_fns = { // clang-format off @@ -323,7 +324,7 @@ static constexpr std::array&, VAddr), // clang-format on }; -static constexpr std::array&, VAddr), +static constexpr std::array gl_to_morton_fns = { // clang-format off @@ -441,29 +442,51 @@ CachedSurface::CachedSurface(const SurfaceParams& params) texture.Create(); const auto& rect{params.GetRect()}; - OpenGLState cur_state = OpenGLState::GetCurState(); - // Keep track of previous texture bindings - GLuint old_tex = cur_state.texture_units[0].texture; + OpenGLState cur_state = OpenGLState::GetCurState(); + const auto& old_tex = cur_state.texture_units[0]; + SCOPE_EXIT({ + cur_state.texture_units[0] = old_tex; + cur_state.Apply(); + }); + cur_state.texture_units[0].texture = texture.handle; + cur_state.texture_units[0].target = SurfaceTargetToGL(params.target); cur_state.Apply(); glActiveTexture(GL_TEXTURE0); const auto& format_tuple = GetFormatTuple(params.pixel_format, params.component_type); if (!format_tuple.compressed) { // Only pre-create the texture for non-compressed textures. - glTexImage2D(GL_TEXTURE_2D, 0, format_tuple.internal_format, rect.GetWidth(), - rect.GetHeight(), 0, format_tuple.format, format_tuple.type, nullptr); + switch (params.target) { + case SurfaceParams::SurfaceTarget::Texture1D: + glTexImage1D(SurfaceTargetToGL(params.target), 0, format_tuple.internal_format, + rect.GetWidth(), 0, format_tuple.format, format_tuple.type, nullptr); + break; + case SurfaceParams::SurfaceTarget::Texture2D: + glTexImage2D(SurfaceTargetToGL(params.target), 0, format_tuple.internal_format, + rect.GetWidth(), rect.GetHeight(), 0, format_tuple.format, + format_tuple.type, nullptr); + break; + case SurfaceParams::SurfaceTarget::Texture3D: + case SurfaceParams::SurfaceTarget::Texture2DArray: + glTexImage3D(SurfaceTargetToGL(params.target), 0, format_tuple.internal_format, + rect.GetWidth(), rect.GetHeight(), params.depth, 0, format_tuple.format, + format_tuple.type, nullptr); + break; + default: + LOG_CRITICAL(Render_OpenGL, "Unimplemented surface target={}", + static_cast(params.target)); + UNREACHABLE(); + glTexImage2D(GL_TEXTURE_2D, 0, format_tuple.internal_format, rect.GetWidth(), + rect.GetHeight(), 0, format_tuple.format, format_tuple.type, nullptr); + } } glTexParameteri(SurfaceTargetToGL(params.target), GL_TEXTURE_MAX_LEVEL, 0); glTexParameteri(SurfaceTargetToGL(params.target), GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(SurfaceTargetToGL(params.target), GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(SurfaceTargetToGL(params.target), GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - - // Restore previous texture bindings - cur_state.texture_units[0].texture = old_tex; - cur_state.Apply(); } static void ConvertS8Z24ToZ24S8(std::vector& data, u32 width, u32 height) { @@ -548,13 +571,24 @@ void CachedSurface::LoadGLBuffer() { MICROPROFILE_SCOPE(OpenGL_SurfaceLoad); if (params.is_tiled) { - gl_buffer.resize(copy_size); + // TODO(bunnei): This only unswizzles and copies a 2D texture - we do not yet know how to do + // this for 3D textures, etc. + switch (params.target) { + case SurfaceParams::SurfaceTarget::Texture2D: + // Pass impl. to the fallback code below + break; + default: + LOG_CRITICAL(HW_GPU, "Unimplemented tiled load for target={}", + static_cast(params.target)); + UNREACHABLE(); + } + gl_buffer.resize(params.depth * copy_size); morton_to_gl_fns[static_cast(params.pixel_format)]( - params.width, params.block_height, params.height, gl_buffer, params.addr); + params.width, params.block_height, params.height, gl_buffer.data(), copy_size, + params.addr); } else { - const u8* const texture_src_data_end = texture_src_data + copy_size; - + const u8* const texture_src_data_end{texture_src_data + (params.depth * copy_size)}; gl_buffer.assign(texture_src_data, texture_src_data_end); } @@ -574,7 +608,7 @@ void CachedSurface::UploadGLTexture(GLuint read_fb_handle, GLuint draw_fb_handle MICROPROFILE_SCOPE(OpenGL_TextureUL); ASSERT(gl_buffer.size() == - params.width * params.height * GetGLBytesPerPixel(params.pixel_format)); + params.width * params.height * GetGLBytesPerPixel(params.pixel_format) * params.depth); const auto& rect{params.GetRect()}; @@ -587,8 +621,13 @@ void CachedSurface::UploadGLTexture(GLuint read_fb_handle, GLuint draw_fb_handle GLuint target_tex = texture.handle; OpenGLState cur_state = OpenGLState::GetCurState(); - GLuint old_tex = cur_state.texture_units[0].texture; + const auto& old_tex = cur_state.texture_units[0]; + SCOPE_EXIT({ + cur_state.texture_units[0] = old_tex; + cur_state.Apply(); + }); cur_state.texture_units[0].texture = target_tex; + cur_state.texture_units[0].target = SurfaceTargetToGL(params.target); cur_state.Apply(); // Ensure no bad interactions with GL_UNPACK_ALIGNMENT @@ -597,20 +636,62 @@ void CachedSurface::UploadGLTexture(GLuint read_fb_handle, GLuint draw_fb_handle glActiveTexture(GL_TEXTURE0); if (tuple.compressed) { - glCompressedTexImage2D( - GL_TEXTURE_2D, 0, tuple.internal_format, static_cast(params.width), - static_cast(params.height), 0, static_cast(params.size_in_bytes), - &gl_buffer[buffer_offset]); + switch (params.target) { + case SurfaceParams::SurfaceTarget::Texture2D: + glCompressedTexImage2D( + SurfaceTargetToGL(params.target), 0, tuple.internal_format, + static_cast(params.width), static_cast(params.height), 0, + static_cast(params.size_in_bytes), &gl_buffer[buffer_offset]); + break; + case SurfaceParams::SurfaceTarget::Texture3D: + case SurfaceParams::SurfaceTarget::Texture2DArray: + glCompressedTexImage3D( + SurfaceTargetToGL(params.target), 0, tuple.internal_format, + static_cast(params.width), static_cast(params.height), + static_cast(params.depth), 0, static_cast(params.size_in_bytes), + &gl_buffer[buffer_offset]); + break; + default: + LOG_CRITICAL(Render_OpenGL, "Unimplemented surface target={}", + static_cast(params.target)); + UNREACHABLE(); + glCompressedTexImage2D( + GL_TEXTURE_2D, 0, tuple.internal_format, static_cast(params.width), + static_cast(params.height), 0, static_cast(params.size_in_bytes), + &gl_buffer[buffer_offset]); + } } else { - glTexSubImage2D(GL_TEXTURE_2D, 0, x0, y0, static_cast(rect.GetWidth()), - static_cast(rect.GetHeight()), tuple.format, tuple.type, - &gl_buffer[buffer_offset]); + + switch (params.target) { + case SurfaceParams::SurfaceTarget::Texture1D: + glTexSubImage1D(SurfaceTargetToGL(params.target), 0, x0, + static_cast(rect.GetWidth()), tuple.format, tuple.type, + &gl_buffer[buffer_offset]); + break; + case SurfaceParams::SurfaceTarget::Texture2D: + glTexSubImage2D(SurfaceTargetToGL(params.target), 0, x0, y0, + static_cast(rect.GetWidth()), + static_cast(rect.GetHeight()), tuple.format, tuple.type, + &gl_buffer[buffer_offset]); + break; + case SurfaceParams::SurfaceTarget::Texture3D: + case SurfaceParams::SurfaceTarget::Texture2DArray: + glTexSubImage3D(SurfaceTargetToGL(params.target), 0, x0, y0, 0, + static_cast(rect.GetWidth()), + static_cast(rect.GetHeight()), params.depth, tuple.format, + tuple.type, &gl_buffer[buffer_offset]); + break; + default: + LOG_CRITICAL(Render_OpenGL, "Unimplemented surface target={}", + static_cast(params.target)); + UNREACHABLE(); + glTexSubImage2D(GL_TEXTURE_2D, 0, x0, y0, static_cast(rect.GetWidth()), + static_cast(rect.GetHeight()), tuple.format, tuple.type, + &gl_buffer[buffer_offset]); + } } glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); - - cur_state.texture_units[0].texture = old_tex; - cur_state.Apply(); } RasterizerCacheOpenGL::RasterizerCacheOpenGL() { From fdd5c97a149724fedfede83b630a0a93e51f1c63 Mon Sep 17 00:00:00 2001 From: bunnei Date: Thu, 6 Sep 2018 19:53:44 -0400 Subject: [PATCH 09/10] maxwell_3d: Remove assert that no longer applies. --- src/video_core/engines/maxwell_3d.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/video_core/engines/maxwell_3d.cpp b/src/video_core/engines/maxwell_3d.cpp index e63ad4d46b..1308080b5e 100644 --- a/src/video_core/engines/maxwell_3d.cpp +++ b/src/video_core/engines/maxwell_3d.cpp @@ -293,10 +293,6 @@ Texture::TICEntry Maxwell3D::GetTICEntry(u32 tic_index) const { tic_entry.header_version == Texture::TICHeaderVersion::Pitch, "TIC versions other than BlockLinear or Pitch are unimplemented"); - ASSERT_MSG((tic_entry.texture_type == Texture::TextureType::Texture2D) || - (tic_entry.texture_type == Texture::TextureType::Texture2DNoMipmap), - "Texture types other than Texture2D are unimplemented"); - auto r_type = tic_entry.r_type.Value(); auto g_type = tic_entry.g_type.Value(); auto b_type = tic_entry.b_type.Value(); From 23ae7cf9dbdfc7924974a6e418207443f5839d75 Mon Sep 17 00:00:00 2001 From: bunnei Date: Sat, 8 Sep 2018 01:04:47 -0400 Subject: [PATCH 10/10] gl_rasterizer_cache: Improve accuracy of RecreateSurface for non-2D textures. --- .../renderer_opengl/gl_rasterizer_cache.cpp | 68 +++++++++++-------- .../renderer_opengl/gl_rasterizer_cache.h | 4 ++ 2 files changed, 45 insertions(+), 27 deletions(-) diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp index e9fd67d004..360fb0cd56 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp @@ -7,6 +7,7 @@ #include "common/alignment.h" #include "common/assert.h" +#include "common/logging/log.h" #include "common/microprofile.h" #include "common/scope_exit.h" #include "core/core.h" @@ -54,8 +55,8 @@ static VAddr TryGetCpuAddr(Tegra::GPUVAddr gpu_addr) { params.depth = config.tic.Depth(); params.unaligned_height = config.tic.Height(); params.size_in_bytes = params.SizeInBytes(); - params.cache_width = Common::AlignUp(params.width, 16); - params.cache_height = Common::AlignUp(params.height, 16); + params.cache_width = Common::AlignUp(params.width, 8); + params.cache_height = Common::AlignUp(params.height, 8); params.target = SurfaceTargetFromTextureType(config.tic.texture_type); return params; } @@ -74,8 +75,8 @@ static VAddr TryGetCpuAddr(Tegra::GPUVAddr gpu_addr) { params.depth = 1; params.unaligned_height = config.height; params.size_in_bytes = params.SizeInBytes(); - params.cache_width = Common::AlignUp(params.width, 16); - params.cache_height = Common::AlignUp(params.height, 16); + params.cache_width = Common::AlignUp(params.width, 8); + params.cache_height = Common::AlignUp(params.height, 8); params.target = SurfaceTarget::Texture2D; return params; } @@ -95,8 +96,8 @@ static VAddr TryGetCpuAddr(Tegra::GPUVAddr gpu_addr) { params.depth = 1; params.unaligned_height = zeta_height; params.size_in_bytes = params.SizeInBytes(); - params.cache_width = Common::AlignUp(params.width, 16); - params.cache_height = Common::AlignUp(params.height, 16); + params.cache_width = Common::AlignUp(params.width, 8); + params.cache_height = Common::AlignUp(params.height, 8); params.target = SurfaceTarget::Texture2D; return params; } @@ -697,6 +698,7 @@ void CachedSurface::UploadGLTexture(GLuint read_fb_handle, GLuint draw_fb_handle RasterizerCacheOpenGL::RasterizerCacheOpenGL() { read_framebuffer.Create(); draw_framebuffer.Create(); + copy_pbo.Create(); } Surface RasterizerCacheOpenGL::GetTextureSurface(const Tegra::Texture::FullTextureInfo& config) { @@ -827,8 +829,8 @@ Surface RasterizerCacheOpenGL::RecreateSurface(const Surface& surface, // If format is unchanged, we can do a faster blit without reinterpreting pixel data if (params.pixel_format == new_params.pixel_format) { BlitTextures(surface->Texture().handle, params.GetRect(), new_surface->Texture().handle, - new_surface->GetSurfaceParams().GetRect(), params.type, - read_framebuffer.handle, draw_framebuffer.handle); + params.GetRect(), params.type, read_framebuffer.handle, + draw_framebuffer.handle); return new_surface; } @@ -839,12 +841,7 @@ Surface RasterizerCacheOpenGL::RecreateSurface(const Surface& surface, size_t buffer_size = std::max(params.SizeInBytes(), new_params.SizeInBytes()); - // Use a Pixel Buffer Object to download the previous texture and then upload it to the new - // one using the new format. - OGLBuffer pbo; - pbo.Create(); - - glBindBuffer(GL_PIXEL_PACK_BUFFER, pbo.handle); + glBindBuffer(GL_PIXEL_PACK_BUFFER, copy_pbo.handle); glBufferData(GL_PIXEL_PACK_BUFFER, buffer_size, nullptr, GL_STREAM_DRAW_ARB); if (source_format.compressed) { glGetCompressedTextureImage(surface->Texture().handle, 0, @@ -863,8 +860,8 @@ Surface RasterizerCacheOpenGL::RecreateSurface(const Surface& surface, // of the data in this case. Games like Super Mario Odyssey seem to hit this case // when drawing, it re-uses the memory of a previous texture as a bigger framebuffer // but it doesn't clear it beforehand, the texture is already full of zeros. - LOG_CRITICAL(HW_GPU, "Trying to upload extra texture data from the CPU during " - "reinterpretation but the texture is tiled."); + LOG_DEBUG(HW_GPU, "Trying to upload extra texture data from the CPU during " + "reinterpretation but the texture is tiled."); } size_t remaining_size = new_params.SizeInBytes() - params.SizeInBytes(); std::vector data(remaining_size); @@ -877,21 +874,38 @@ Surface RasterizerCacheOpenGL::RecreateSurface(const Surface& surface, const auto& dest_rect{new_params.GetRect()}; - glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pbo.handle); + glBindBuffer(GL_PIXEL_UNPACK_BUFFER, copy_pbo.handle); if (dest_format.compressed) { - glCompressedTexSubImage2D( - GL_TEXTURE_2D, 0, 0, 0, static_cast(dest_rect.GetWidth()), - static_cast(dest_rect.GetHeight()), dest_format.format, - static_cast(new_params.SizeInBytes()), nullptr); + LOG_CRITICAL(HW_GPU, "Compressed copy is unimplemented!"); + UNREACHABLE(); } else { - glTextureSubImage2D(new_surface->Texture().handle, 0, 0, 0, - static_cast(dest_rect.GetWidth()), - static_cast(dest_rect.GetHeight()), dest_format.format, - dest_format.type, nullptr); + switch (new_params.target) { + case SurfaceParams::SurfaceTarget::Texture1D: + glTextureSubImage1D(new_surface->Texture().handle, 0, 0, + static_cast(dest_rect.GetWidth()), dest_format.format, + dest_format.type, nullptr); + break; + case SurfaceParams::SurfaceTarget::Texture2D: + glTextureSubImage2D(new_surface->Texture().handle, 0, 0, 0, + static_cast(dest_rect.GetWidth()), + static_cast(dest_rect.GetHeight()), dest_format.format, + dest_format.type, nullptr); + break; + case SurfaceParams::SurfaceTarget::Texture3D: + case SurfaceParams::SurfaceTarget::Texture2DArray: + glTextureSubImage3D(new_surface->Texture().handle, 0, 0, 0, 0, + static_cast(dest_rect.GetWidth()), + static_cast(dest_rect.GetHeight()), + static_cast(new_params.depth), dest_format.format, + dest_format.type, nullptr); + break; + default: + LOG_CRITICAL(Render_OpenGL, "Unimplemented surface target={}", + static_cast(params.target)); + UNREACHABLE(); + } } glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); - - pbo.Release(); } return new_surface; diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.h b/src/video_core/renderer_opengl/gl_rasterizer_cache.h index 56022ea01e..8312b2c7a5 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer_cache.h +++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.h @@ -807,6 +807,10 @@ private: OGLFramebuffer read_framebuffer; OGLFramebuffer draw_framebuffer; + + /// Use a Pixel Buffer Object to download the previous texture and then upload it to the new one + /// using the new format. + OGLBuffer copy_pbo; }; } // namespace OpenGL