diff options
Diffstat (limited to '')
-rw-r--r-- | src/video_core/engines/maxwell_3d.cpp | 4 | ||||
-rw-r--r-- | src/video_core/renderer_opengl/gl_rasterizer.cpp | 16 | ||||
-rw-r--r-- | src/video_core/renderer_opengl/gl_rasterizer.h | 1 | ||||
-rw-r--r-- | src/video_core/renderer_opengl/gl_rasterizer_cache.cpp | 364 | ||||
-rw-r--r-- | src/video_core/renderer_opengl/gl_rasterizer_cache.h | 43 | ||||
-rw-r--r-- | src/video_core/renderer_opengl/gl_shader_decompiler.cpp | 125 | ||||
-rw-r--r-- | src/video_core/renderer_opengl/gl_shader_gen.h | 50 | ||||
-rw-r--r-- | src/video_core/renderer_opengl/gl_state.cpp | 8 | ||||
-rw-r--r-- | src/video_core/renderer_opengl/gl_state.h | 8 | ||||
-rw-r--r-- | src/video_core/renderer_opengl/renderer_opengl.cpp | 20 | ||||
-rw-r--r-- | src/video_core/textures/texture.h | 12 |
11 files changed, 422 insertions, 229 deletions
diff --git a/src/video_core/engines/maxwell_3d.cpp b/src/video_core/engines/maxwell_3d.cpp index e63ad4d46..1308080b5 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(); diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp index 0c3bbc475..e6d6917fa 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp @@ -586,7 +586,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); @@ -613,8 +613,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) { @@ -698,14 +703,15 @@ 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].target = surface->Target(); state.texture_units[current_bindpoint].swizzle.r = MaxwellToGL::SwizzleSource(texture.tic.x_source); state.texture_units[current_bindpoint].swizzle.g = @@ -716,7 +722,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.h b/src/video_core/renderer_opengl/gl_rasterizer.h index 9c30dc0e8..c6bb1516b 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; }; diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp index f6b2c5a86..360fb0cd5 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" @@ -51,10 +52,12 @@ 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); - 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; } @@ -69,10 +72,12 @@ 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); - 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; } @@ -86,13 +91,14 @@ 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); - 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; } @@ -166,6 +172,26 @@ static constexpr std::array<FormatTuple, SurfaceParams::MaxPixelFormat> 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<u32>(target)); + UNREACHABLE(); + return {}; +} + static const FormatTuple& GetFormatTuple(PixelFormat pixel_format, ComponentType component_type) { ASSERT(static_cast<size_t>(pixel_format) < tex_format_tuples.size()); auto& format = tex_format_tuples[static_cast<unsigned int>(pixel_format)]; @@ -220,7 +246,8 @@ static bool IsFormatBCn(PixelFormat format) { } template <bool morton_to_gl, PixelFormat format> -void MortonCopy(u32 stride, u32 block_height, u32 height, std::vector<u8>& 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); @@ -230,18 +257,18 @@ void MortonCopy(u32 stride, u32 block_height, u32 height, std::vector<u8>& gl_bu const u32 tile_size{IsFormatBCn(format) ? 4U : 1U}; const std::vector<u8> 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<void (*)(u32, u32, u32, std::vector<u8>&, VAddr), +static constexpr std::array<void (*)(u32, u32, u32, u8*, size_t, VAddr), SurfaceParams::MaxPixelFormat> morton_to_gl_fns = { // clang-format off @@ -298,7 +325,7 @@ static constexpr std::array<void (*)(u32, u32, u32, std::vector<u8>&, VAddr), // clang-format on }; -static constexpr std::array<void (*)(u32, u32, u32, std::vector<u8>&, VAddr), +static constexpr std::array<void (*)(u32, u32, u32, u8*, size_t, VAddr), SurfaceParams::MaxPixelFormat> gl_to_morton_fns = { // clang-format off @@ -357,33 +384,6 @@ static constexpr std::array<void (*)(u32, u32, u32, std::vector<u8>&, 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_2d; - cur_state.texture_units[0].texture_2d = 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_2d = old_tex; - cur_state.Apply(); -} - static bool BlitTextures(GLuint src_tex, const MathUtil::Rectangle<u32>& src_rect, GLuint dst_tex, const MathUtil::Rectangle<u32>& dst_rect, SurfaceType type, GLuint read_fb_handle, GLuint draw_fb_handle) { @@ -438,12 +438,56 @@ static bool BlitTextures(GLuint src_tex, const MathUtil::Rectangle<u32>& 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()); + + // Keep track of previous texture bindings + 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. + 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<u32>(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); } static void ConvertS8Z24ToZ24S8(std::vector<u8>& data, u32 width, u32 height) { @@ -514,23 +558,6 @@ static void ConvertFormatAsNeeded_LoadGLBuffer(std::vector<u8>& 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<u8>& /*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<u32>(pixel_format)); - UNREACHABLE(); - break; - } -} - MICROPROFILE_DEFINE(OpenGL_SurfaceLoad, "OpenGL", "Surface Load", MP_RGB(128, 64, 192)); void CachedSurface::LoadGLBuffer() { ASSERT(params.type != SurfaceType::Fill); @@ -545,13 +572,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<u32>(params.target)); + UNREACHABLE(); + } + gl_buffer.resize(params.depth * copy_size); morton_to_gl_fns[static_cast<size_t>(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); } @@ -560,23 +598,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<size_t>(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)); @@ -587,7 +609,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()}; @@ -600,8 +622,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_2d; - cur_state.texture_units[0].texture_2d = target_tex; + 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 @@ -610,74 +637,68 @@ 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<GLsizei>(params.width), - static_cast<GLsizei>(params.height), 0, static_cast<GLsizei>(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<GLsizei>(params.width), static_cast<GLsizei>(params.height), 0, + static_cast<GLsizei>(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<GLsizei>(params.width), static_cast<GLsizei>(params.height), + static_cast<GLsizei>(params.depth), 0, static_cast<GLsizei>(params.size_in_bytes), + &gl_buffer[buffer_offset]); + break; + default: + LOG_CRITICAL(Render_OpenGL, "Unimplemented surface target={}", + static_cast<u32>(params.target)); + UNREACHABLE(); + glCompressedTexImage2D( + GL_TEXTURE_2D, 0, tuple.internal_format, static_cast<GLsizei>(params.width), + static_cast<GLsizei>(params.height), 0, static_cast<GLsizei>(params.size_in_bytes), + &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, - &gl_buffer[buffer_offset]); - } - - glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); - - cur_state.texture_units[0].texture_2d = old_tex; - 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<GLint>(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); + switch (params.target) { + case SurfaceParams::SurfaceTarget::Texture1D: + glTexSubImage1D(SurfaceTargetToGL(params.target), 0, x0, + static_cast<GLsizei>(rect.GetWidth()), tuple.format, tuple.type, + &gl_buffer[buffer_offset]); + break; + case SurfaceParams::SurfaceTarget::Texture2D: + glTexSubImage2D(SurfaceTargetToGL(params.target), 0, x0, y0, + static_cast<GLsizei>(rect.GetWidth()), + static_cast<GLsizei>(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<GLsizei>(rect.GetWidth()), + static_cast<GLsizei>(rect.GetHeight()), params.depth, tuple.format, + tuple.type, &gl_buffer[buffer_offset]); + break; + default: + LOG_CRITICAL(Render_OpenGL, "Unimplemented surface target={}", + static_cast<u32>(params.target)); + UNREACHABLE(); + glTexSubImage2D(GL_TEXTURE_2D, 0, x0, y0, static_cast<GLsizei>(rect.GetWidth()), + static_cast<GLsizei>(rect.GetHeight()), tuple.format, tuple.type, + &gl_buffer[buffer_offset]); + } } - glReadPixels(static_cast<GLint>(rect.left), static_cast<GLint>(rect.bottom), - static_cast<GLsizei>(rect.GetWidth()), static_cast<GLsizei>(rect.GetHeight()), - tuple.format, tuple.type, &gl_buffer[buffer_offset]); - glPixelStorei(GL_PACK_ROW_LENGTH, 0); + glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); } RasterizerCacheOpenGL::RasterizerCacheOpenGL() { read_framebuffer.Create(); draw_framebuffer.Create(); + copy_pbo.Create(); } Surface RasterizerCacheOpenGL::GetTextureSurface(const Tegra::Texture::FullTextureInfo& config) { @@ -748,7 +769,6 @@ void RasterizerCacheOpenGL::LoadSurface(const Surface& surface) { } void RasterizerCacheOpenGL::FlushSurface(const Surface& surface) { - surface->DownloadGLTexture(read_framebuffer.handle, draw_framebuffer.handle); surface->FlushGLBuffer(); } @@ -809,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; } @@ -821,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, @@ -845,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<u8> data(remaining_size); @@ -859,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<GLsizei>(dest_rect.GetWidth()), - static_cast<GLsizei>(dest_rect.GetHeight()), dest_format.format, - static_cast<GLsizei>(new_params.SizeInBytes()), nullptr); + LOG_CRITICAL(HW_GPU, "Compressed copy is unimplemented!"); + UNREACHABLE(); } else { - glTextureSubImage2D(new_surface->Texture().handle, 0, 0, 0, - static_cast<GLsizei>(dest_rect.GetWidth()), - static_cast<GLsizei>(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<GLsizei>(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<GLsizei>(dest_rect.GetWidth()), + static_cast<GLsizei>(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<GLsizei>(dest_rect.GetWidth()), + static_cast<GLsizei>(dest_rect.GetHeight()), + static_cast<GLsizei>(new_params.depth), dest_format.format, + dest_format.type, nullptr); + break; + default: + LOG_CRITICAL(Render_OpenGL, "Unimplemented surface target={}", + static_cast<u32>(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 aad75f200..8312b2c7a 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<u32>(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 @@ -635,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 @@ -664,8 +691,10 @@ struct SurfaceParams { SurfaceType type; u32 width; u32 height; + u32 depth; u32 unaligned_height; size_t size_in_bytes; + SurfaceTarget target; // Parameters used for caching only u32 cache_width; @@ -709,6 +738,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,14 +757,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); - void DownloadGLTexture(GLuint read_fb_handle, GLuint draw_fb_handle); private: OGLTexture texture; std::vector<u8> gl_buffer; SurfaceParams params; + GLenum gl_target; }; class RasterizerCacheOpenGL final : public RasterizerCache<Surface> { @@ -774,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 diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp index 841647ebe..172ba8335 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<SamplerEntry> GetSamplers() const { + const std::vector<SamplerEntry>& 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<size_t>(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<u32>(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<u32>(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<u32>(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 cbb2090ea..a43e2997b 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 <vector> #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<size_t>(stage)]) + '[' + - std::to_string(sampler_index) + ']'; + return std::string(TextureSamplerNames[static_cast<size_t>(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<const char*, Maxwell::MaxShaderStage> 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 { diff --git a/src/video_core/renderer_opengl/gl_state.cpp b/src/video_core/renderer_opengl/gl_state.cpp index 60a4defd1..6f70deb96 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<int>(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<GLuint>(i), texture_unit.sampler); @@ -214,7 +214,7 @@ void OpenGLState::Apply() const { texture_unit.swizzle.a != cur_state_texture_unit.swizzle.a) { std::array<GLint, 4> 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 46e96a97d..e3e24b9e7 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<TextureUnit, 32> texture_units; diff --git a/src/video_core/renderer_opengl/renderer_opengl.cpp b/src/video_core/renderer_opengl/renderer_opengl.cpp index 411a73d50..ccff3e342 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(); } diff --git a/src/video_core/textures/texture.h b/src/video_core/textures/texture.h index c6bd2f4b9..c2fb824b2 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<GPUVAddr>((static_cast<GPUVAddr>(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); |