mirror of
				https://git.zaroz.cloud/nintendo-back-up/yuzu/yuzu.git
				synced 2025-05-12 00:45:25 +00:00 
			
		
		
		
	Merge pull request #314 from jroweboy/tegra-progress-3b
GPU: Bind uploaded textures when drawing (Rebased)
This commit is contained in:
		
						commit
						227bc78cbe
					
				| @ -231,6 +231,8 @@ Texture::TICEntry Maxwell3D::GetTICEntry(u32 tic_index) const { | ||||
| 
 | ||||
|     // TODO(Subv): Different data types for separate components are not supported
 | ||||
|     ASSERT(r_type == g_type && r_type == b_type && r_type == a_type); | ||||
|     // TODO(Subv): Only UNORM formats are supported for now.
 | ||||
|     ASSERT(r_type == Texture::ComponentType::UNORM); | ||||
| 
 | ||||
|     return tic_entry; | ||||
| } | ||||
|  | ||||
| @ -66,6 +66,12 @@ RasterizerOpenGL::RasterizerOpenGL() { | ||||
|     has_ARB_separate_shader_objects = false; | ||||
|     has_ARB_vertex_attrib_binding = false; | ||||
| 
 | ||||
|     // Create sampler objects
 | ||||
|     for (size_t i = 0; i < texture_samplers.size(); ++i) { | ||||
|         texture_samplers[i].Create(); | ||||
|         state.texture_units[i].sampler = texture_samplers[i].sampler.handle; | ||||
|     } | ||||
| 
 | ||||
|     GLint ext_num; | ||||
|     glGetIntegerv(GL_NUM_EXTENSIONS, &ext_num); | ||||
|     for (GLint i = 0; i < ext_num; i++) { | ||||
| @ -270,7 +276,9 @@ void RasterizerOpenGL::DrawArrays() { | ||||
| 
 | ||||
|     // TODO(bunnei): Sync framebuffer_scale uniform here
 | ||||
|     // TODO(bunnei): Sync scissorbox uniform(s) here
 | ||||
|     // TODO(bunnei): Sync and bind the texture surfaces
 | ||||
| 
 | ||||
|     // Sync and bind the texture surfaces
 | ||||
|     BindTextures(); | ||||
| 
 | ||||
|     // Sync and bind the shader
 | ||||
|     if (shader_dirty) { | ||||
| @ -374,6 +382,39 @@ void RasterizerOpenGL::DrawArrays() { | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void RasterizerOpenGL::BindTextures() { | ||||
|     using Regs = Tegra::Engines::Maxwell3D::Regs; | ||||
|     auto maxwell3d = Core::System::GetInstance().GPU().Get3DEngine(); | ||||
| 
 | ||||
|     // Each Maxwell shader stage can have an arbitrary number of textures, but we're limited to a
 | ||||
|     // certain number in OpenGL. We try to only use the minimum amount of host textures by not
 | ||||
|     // keeping a 1:1 relation between guest texture ids and host texture ids, ie, guest texture id 8
 | ||||
|     // can be host texture id 0 if it's the only texture used in the guest shader program.
 | ||||
|     u32 host_texture_index = 0; | ||||
|     for (u32 stage = 0; stage < Regs::MaxShaderStage; ++stage) { | ||||
|         ASSERT(host_texture_index < texture_samplers.size()); | ||||
|         const auto textures = maxwell3d.GetStageTextures(static_cast<Regs::ShaderStage>(stage)); | ||||
|         for (unsigned texture_index = 0; texture_index < textures.size(); ++texture_index) { | ||||
|             const auto& texture = textures[texture_index]; | ||||
| 
 | ||||
|             if (texture.enabled) { | ||||
|                 texture_samplers[host_texture_index].SyncWithConfig(texture.tsc); | ||||
|                 Surface surface = res_cache.GetTextureSurface(texture); | ||||
|                 if (surface != nullptr) { | ||||
|                     state.texture_units[host_texture_index].texture_2d = surface->texture.handle; | ||||
|                 } else { | ||||
|                     // Can occur when texture addr is null or its memory is unmapped/invalid
 | ||||
|                     state.texture_units[texture_index].texture_2d = 0; | ||||
|                 } | ||||
| 
 | ||||
|                 ++host_texture_index; | ||||
|             } else { | ||||
|                 state.texture_units[texture_index].texture_2d = 0; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void RasterizerOpenGL::NotifyMaxwellRegisterChanged(u32 id) {} | ||||
| 
 | ||||
| void RasterizerOpenGL::FlushAll() { | ||||
| @ -452,6 +493,44 @@ bool RasterizerOpenGL::AccelerateDisplay(const Tegra::FramebufferConfig& framebu | ||||
|     return true; | ||||
| } | ||||
| 
 | ||||
| void RasterizerOpenGL::SamplerInfo::Create() { | ||||
|     sampler.Create(); | ||||
|     mag_filter = min_filter = Tegra::Texture::TextureFilter::Linear; | ||||
|     wrap_u = wrap_v = Tegra::Texture::WrapMode::Wrap; | ||||
|     border_color_r = border_color_g = border_color_b = border_color_a = 0; | ||||
| 
 | ||||
|     // default is GL_LINEAR_MIPMAP_LINEAR
 | ||||
|     glSamplerParameteri(sampler.handle, GL_TEXTURE_MIN_FILTER, GL_LINEAR); | ||||
|     // Other attributes have correct defaults
 | ||||
| } | ||||
| 
 | ||||
| void RasterizerOpenGL::SamplerInfo::SyncWithConfig(const Tegra::Texture::TSCEntry& config) { | ||||
|     GLuint s = sampler.handle; | ||||
| 
 | ||||
|     if (mag_filter != config.mag_filter) { | ||||
|         mag_filter = config.mag_filter; | ||||
|         glSamplerParameteri(s, GL_TEXTURE_MAG_FILTER, MaxwellToGL::TextureFilterMode(mag_filter)); | ||||
|     } | ||||
|     if (min_filter != config.min_filter) { | ||||
|         min_filter = config.min_filter; | ||||
|         glSamplerParameteri(s, GL_TEXTURE_MIN_FILTER, MaxwellToGL::TextureFilterMode(min_filter)); | ||||
|     } | ||||
| 
 | ||||
|     if (wrap_u != config.wrap_u) { | ||||
|         wrap_u = config.wrap_u; | ||||
|         glSamplerParameteri(s, GL_TEXTURE_WRAP_S, MaxwellToGL::WrapMode(wrap_u)); | ||||
|     } | ||||
|     if (wrap_v != config.wrap_v) { | ||||
|         wrap_v = config.wrap_v; | ||||
|         glSamplerParameteri(s, GL_TEXTURE_WRAP_T, MaxwellToGL::WrapMode(wrap_v)); | ||||
|     } | ||||
| 
 | ||||
|     if (wrap_u == Tegra::Texture::WrapMode::Border || wrap_v == Tegra::Texture::WrapMode::Border) { | ||||
|         // TODO(Subv): Implement border color
 | ||||
|         ASSERT(false); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void RasterizerOpenGL::SetShader() { | ||||
|     // TODO(bunnei): The below sets up a static test shader for passing untransformed vertices to
 | ||||
|     // OpenGL for rendering. This should be removed/replaced when we start emulating Maxwell
 | ||||
| @ -479,10 +558,10 @@ void main() { | ||||
| in vec2 frag_tex_coord; | ||||
| out vec4 color; | ||||
| 
 | ||||
| uniform sampler2D color_texture; | ||||
| uniform sampler2D tex[32]; | ||||
| 
 | ||||
| void main() { | ||||
|     color = vec4(1.0, 0.0, 1.0, 0.0); | ||||
|     color = texture(tex[0], frag_tex_coord); | ||||
| } | ||||
| )"; | ||||
| 
 | ||||
| @ -503,6 +582,15 @@ void main() { | ||||
|     state.draw.shader_program = test_shader.shader.handle; | ||||
|     state.Apply(); | ||||
| 
 | ||||
|     for (u32 texture = 0; texture < texture_samplers.size(); ++texture) { | ||||
|         // Set the texture samplers to correspond to different texture units
 | ||||
|         std::string uniform_name = "tex[" + std::to_string(texture) + "]"; | ||||
|         GLint uniform_tex = glGetUniformLocation(test_shader.shader.handle, uniform_name.c_str()); | ||||
|         if (uniform_tex != -1) { | ||||
|             glUniform1i(uniform_tex, TextureUnits::MaxwellTexture(texture).id); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     if (has_ARB_separate_shader_objects) { | ||||
|         state.draw.shader_program = 0; | ||||
|         state.Apply(); | ||||
|  | ||||
| @ -85,12 +85,34 @@ public: | ||||
|                   "FSUniformData structure must be less than 16kb as per the OpenGL spec"); | ||||
| 
 | ||||
| private: | ||||
|     struct SamplerInfo {}; | ||||
|     class SamplerInfo { | ||||
|     public: | ||||
|         OGLSampler sampler; | ||||
| 
 | ||||
|         /// Creates the sampler object, initializing its state so that it's in sync with the
 | ||||
|         /// SamplerInfo struct.
 | ||||
|         void Create(); | ||||
|         /// Syncs the sampler object with the config, updating any necessary state.
 | ||||
|         void SyncWithConfig(const Tegra::Texture::TSCEntry& config); | ||||
| 
 | ||||
|     private: | ||||
|         Tegra::Texture::TextureFilter mag_filter; | ||||
|         Tegra::Texture::TextureFilter min_filter; | ||||
|         Tegra::Texture::WrapMode wrap_u; | ||||
|         Tegra::Texture::WrapMode wrap_v; | ||||
|         u32 border_color_r; | ||||
|         u32 border_color_g; | ||||
|         u32 border_color_b; | ||||
|         u32 border_color_a; | ||||
|     }; | ||||
| 
 | ||||
|     /// Binds the framebuffer color and depth surface
 | ||||
|     void BindFramebufferSurfaces(const Surface& color_surface, const Surface& depth_surface, | ||||
|                                  bool has_stencil); | ||||
| 
 | ||||
|     /// Binds the required textures to OpenGL before drawing a batch.
 | ||||
|     void BindTextures(); | ||||
| 
 | ||||
|     /// Syncs the viewport to match the guest state
 | ||||
|     void SyncViewport(const MathUtil::Rectangle<u32>& surfaces_rect, u16 res_scale); | ||||
| 
 | ||||
|  | ||||
| @ -30,6 +30,7 @@ | ||||
| #include "video_core/engines/maxwell_3d.h" | ||||
| #include "video_core/renderer_opengl/gl_rasterizer_cache.h" | ||||
| #include "video_core/renderer_opengl/gl_state.h" | ||||
| #include "video_core/textures/decoders.h" | ||||
| #include "video_core/utils.h" | ||||
| #include "video_core/video_core.h" | ||||
| 
 | ||||
| @ -40,36 +41,36 @@ struct FormatTuple { | ||||
|     GLint internal_format; | ||||
|     GLenum format; | ||||
|     GLenum type; | ||||
|     bool compressed; | ||||
|     // How many pixels in the original texture are equivalent to one pixel in the compressed
 | ||||
|     // texture.
 | ||||
|     u32 compression_factor; | ||||
| }; | ||||
| 
 | ||||
| static constexpr std::array<FormatTuple, 5> fb_format_tuples = {{ | ||||
|     {GL_RGBA8, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8},     // RGBA8
 | ||||
|     {GL_RGB8, GL_BGR, GL_UNSIGNED_BYTE},              // RGB8
 | ||||
|     {GL_RGB5_A1, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1}, // RGB5A1
 | ||||
|     {GL_RGB565, GL_RGB, GL_UNSIGNED_SHORT_5_6_5},     // RGB565
 | ||||
|     {GL_RGBA4, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4},   // RGBA4
 | ||||
| static constexpr std::array<FormatTuple, 1> fb_format_tuples = {{ | ||||
|     {GL_RGBA8, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, false, 1}, // RGBA8
 | ||||
| }}; | ||||
| 
 | ||||
| static constexpr std::array<FormatTuple, 4> depth_format_tuples = {{ | ||||
|     {GL_DEPTH_COMPONENT16, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT}, // D16
 | ||||
|     {}, | ||||
|     {GL_DEPTH_COMPONENT24, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT},   // D24
 | ||||
|     {GL_DEPTH24_STENCIL8, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8}, // D24S8
 | ||||
| static constexpr std::array<FormatTuple, 2> tex_format_tuples = {{ | ||||
|     {GL_RGBA8, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, false, 1},                       // RGBA8
 | ||||
|     {GL_COMPRESSED_RGB_S3TC_DXT1_EXT, GL_RGB, GL_UNSIGNED_INT_8_8_8_8, true, 16}, // DXT1
 | ||||
| }}; | ||||
| 
 | ||||
| static constexpr FormatTuple tex_tuple = {GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE}; | ||||
| 
 | ||||
| static const FormatTuple& GetFormatTuple(PixelFormat pixel_format) { | ||||
|     const SurfaceType type = SurfaceParams::GetFormatType(pixel_format); | ||||
|     if (type == SurfaceType::Color) { | ||||
|         ASSERT(static_cast<size_t>(pixel_format) < fb_format_tuples.size()); | ||||
|         return fb_format_tuples[static_cast<unsigned int>(pixel_format)]; | ||||
|     } else if (type == SurfaceType::Depth || type == SurfaceType::DepthStencil) { | ||||
|         size_t tuple_idx = static_cast<size_t>(pixel_format) - 14; | ||||
|         ASSERT(tuple_idx < depth_format_tuples.size()); | ||||
|         return depth_format_tuples[tuple_idx]; | ||||
|         // TODO(Subv): Implement depth formats
 | ||||
|         ASSERT_MSG(false, "Unimplemented"); | ||||
|     } else if (type == SurfaceType::Texture) { | ||||
|         ASSERT(static_cast<size_t>(pixel_format) < tex_format_tuples.size()); | ||||
|         return tex_format_tuples[static_cast<unsigned int>(pixel_format)]; | ||||
|     } | ||||
|     return tex_tuple; | ||||
| 
 | ||||
|     UNREACHABLE(); | ||||
|     return {}; | ||||
| } | ||||
| 
 | ||||
| template <typename Map, typename Interval> | ||||
| @ -92,26 +93,16 @@ static void MortonCopyTile(u32 stride, u8* tile_buffer, u8* gl_buffer) { | ||||
|             u8* tile_ptr = tile_buffer + VideoCore::MortonInterleave(x, y) * bytes_per_pixel; | ||||
|             u8* gl_ptr = gl_buffer + ((7 - y) * stride + x) * gl_bytes_per_pixel; | ||||
|             if (morton_to_gl) { | ||||
|                 if (format == PixelFormat::D24S8) { | ||||
|                     gl_ptr[0] = tile_ptr[3]; | ||||
|                     std::memcpy(gl_ptr + 1, tile_ptr, 3); | ||||
|                 } else { | ||||
|                 std::memcpy(gl_ptr, tile_ptr, bytes_per_pixel); | ||||
|                 } | ||||
|             } else { | ||||
|                 if (format == PixelFormat::D24S8) { | ||||
|                     std::memcpy(tile_ptr, gl_ptr + 1, 3); | ||||
|                     tile_ptr[3] = gl_ptr[0]; | ||||
|             } else { | ||||
|                 std::memcpy(tile_ptr, gl_ptr, bytes_per_pixel); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
| } | ||||
| 
 | ||||
| template <bool morton_to_gl, PixelFormat format> | ||||
| static void MortonCopy(u32 stride, u32 height, u8* gl_buffer, VAddr base, VAddr start, VAddr end) { | ||||
| void MortonCopy(u32 stride, u32 height, u8* gl_buffer, VAddr base, VAddr start, VAddr end) { | ||||
|     constexpr u32 bytes_per_pixel = SurfaceParams::GetFormatBpp(format) / 8; | ||||
|     constexpr u32 gl_bytes_per_pixel = CachedSurface::GetGLBytesPerPixel(format); | ||||
| 
 | ||||
| @ -122,46 +113,28 @@ static void MortonCopy(u32 stride, u32 height, u8* gl_buffer, VAddr base, VAddr | ||||
|                                    Memory::GetPointer(base), gl_buffer, morton_to_gl); | ||||
| } | ||||
| 
 | ||||
| static constexpr std::array<void (*)(u32, u32, u8*, VAddr, VAddr, VAddr), 18> morton_to_gl_fns = { | ||||
| template <> | ||||
| void MortonCopy<true, PixelFormat::DXT1>(u32 stride, u32 height, u8* gl_buffer, VAddr base, | ||||
|                                          VAddr start, VAddr end) { | ||||
|     constexpr u32 bytes_per_pixel = SurfaceParams::GetFormatBpp(PixelFormat::DXT1) / 8; | ||||
|     constexpr u32 gl_bytes_per_pixel = CachedSurface::GetGLBytesPerPixel(PixelFormat::DXT1); | ||||
| 
 | ||||
|     // 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!"); | ||||
|     auto data = | ||||
|         Tegra::Texture::UnswizzleTexture(base, Tegra::Texture::TextureFormat::DXT1, stride, height); | ||||
|     std::memcpy(gl_buffer, data.data(), data.size()); | ||||
| } | ||||
| 
 | ||||
| static constexpr std::array<void (*)(u32, u32, u8*, VAddr, VAddr, VAddr), 2> morton_to_gl_fns = { | ||||
|     MortonCopy<true, PixelFormat::RGBA8>, | ||||
|     nullptr, | ||||
|     nullptr, | ||||
|     nullptr, | ||||
|     nullptr, | ||||
|     nullptr, | ||||
|     nullptr, | ||||
|     nullptr, | ||||
|     nullptr, | ||||
|     nullptr, | ||||
|     nullptr, | ||||
|     nullptr, | ||||
|     nullptr, | ||||
|     nullptr, | ||||
|     nullptr, | ||||
|     nullptr, | ||||
|     nullptr, | ||||
|     nullptr, | ||||
|     MortonCopy<true, PixelFormat::DXT1>, | ||||
| }; | ||||
| 
 | ||||
| static constexpr std::array<void (*)(u32, u32, u8*, VAddr, VAddr, VAddr), 18> gl_to_morton_fns = { | ||||
| static constexpr std::array<void (*)(u32, u32, u8*, VAddr, VAddr, VAddr), 2> gl_to_morton_fns = { | ||||
|     MortonCopy<false, PixelFormat::RGBA8>, | ||||
|     nullptr, | ||||
|     nullptr, | ||||
|     nullptr, | ||||
|     nullptr, | ||||
|     nullptr, | ||||
|     nullptr, | ||||
|     nullptr, | ||||
|     nullptr, | ||||
|     nullptr, | ||||
|     nullptr, | ||||
|     nullptr, | ||||
|     nullptr, | ||||
|     nullptr, | ||||
|     nullptr, | ||||
|     nullptr, | ||||
|     nullptr, | ||||
|     nullptr, | ||||
|     MortonCopy<false, PixelFormat::DXT1>, | ||||
| }; | ||||
| 
 | ||||
| // Allocate an uninitialized texture of appropriate size and format for the surface
 | ||||
| @ -175,8 +148,11 @@ static void AllocateSurfaceTexture(GLuint texture, const FormatTuple& format_tup | ||||
|     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); | ||||
| @ -606,9 +582,18 @@ void CachedSurface::UploadGLTexture(const MathUtil::Rectangle<u32>& rect, GLuint | ||||
|     glPixelStorei(GL_UNPACK_ROW_LENGTH, static_cast<GLint>(stride)); | ||||
| 
 | ||||
|     glActiveTexture(GL_TEXTURE0); | ||||
|     if (tuple.compressed) { | ||||
|         glCompressedTexImage2D(GL_TEXTURE_2D, 0, tuple.internal_format, | ||||
|                                static_cast<GLsizei>(rect.GetWidth()), | ||||
|                                static_cast<GLsizei>(rect.GetHeight()), 0, | ||||
|                                rect.GetWidth() * rect.GetHeight() * | ||||
|                                    GetGLBytesPerPixel(pixel_format) / tuple.compression_factor, | ||||
|                                &gl_buffer[buffer_offset]); | ||||
|     } 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); | ||||
| 
 | ||||
| @ -954,15 +939,6 @@ Surface RasterizerCacheOpenGL::GetSurface(const SurfaceParams& params, ScaleMatc | ||||
|             if (expandable != nullptr && expandable->res_scale > target_res_scale) { | ||||
|                 target_res_scale = expandable->res_scale; | ||||
|             } | ||||
|             // Keep res_scale when reinterpreting d24s8 -> rgba8
 | ||||
|             if (params.pixel_format == PixelFormat::RGBA8) { | ||||
|                 find_params.pixel_format = PixelFormat::D24S8; | ||||
|                 expandable = FindMatch<MatchFlags::Expand | MatchFlags::Invalid>( | ||||
|                     surface_cache, find_params, match_res_scale); | ||||
|                 if (expandable != nullptr && expandable->res_scale > target_res_scale) { | ||||
|                     target_res_scale = expandable->res_scale; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|         SurfaceParams new_params = params; | ||||
|         new_params.res_scale = target_res_scale; | ||||
| @ -1056,9 +1032,34 @@ SurfaceRect_Tuple RasterizerCacheOpenGL::GetSurfaceSubRect(const SurfaceParams& | ||||
|     return std::make_tuple(surface, surface->GetScaledSubRect(params)); | ||||
| } | ||||
| 
 | ||||
| Surface RasterizerCacheOpenGL::GetTextureSurface(const void* config) { | ||||
|     UNREACHABLE(); | ||||
|     return {}; | ||||
| Surface RasterizerCacheOpenGL::GetTextureSurface(const Tegra::Texture::FullTextureInfo& config) { | ||||
|     auto& gpu = Core::System::GetInstance().GPU(); | ||||
| 
 | ||||
|     SurfaceParams params; | ||||
|     params.addr = gpu.memory_manager->PhysicalToVirtualAddress(config.tic.Address()); | ||||
|     params.width = config.tic.Width(); | ||||
|     params.height = config.tic.Height(); | ||||
|     params.is_tiled = config.tic.IsTiled(); | ||||
|     params.pixel_format = SurfaceParams::PixelFormatFromTextureFormat(config.tic.format); | ||||
|     params.UpdateParams(); | ||||
| 
 | ||||
|     if (config.tic.Width() % 8 != 0 || config.tic.Height() % 8 != 0) { | ||||
|         Surface src_surface; | ||||
|         MathUtil::Rectangle<u32> rect; | ||||
|         std::tie(src_surface, rect) = GetSurfaceSubRect(params, ScaleMatch::Ignore, true); | ||||
| 
 | ||||
|         params.res_scale = src_surface->res_scale; | ||||
|         Surface tmp_surface = CreateSurface(params); | ||||
|         BlitTextures(src_surface->texture.handle, rect, tmp_surface->texture.handle, | ||||
|                      tmp_surface->GetScaledRect(), | ||||
|                      SurfaceParams::GetFormatType(params.pixel_format), read_framebuffer.handle, | ||||
|                      draw_framebuffer.handle); | ||||
| 
 | ||||
|         remove_surfaces.emplace(tmp_surface); | ||||
|         return tmp_surface; | ||||
|     } | ||||
| 
 | ||||
|     return GetSurface(params, ScaleMatch::Ignore, true); | ||||
| } | ||||
| 
 | ||||
| SurfaceSurfaceRect_Tuple RasterizerCacheOpenGL::GetFramebufferSurfaces( | ||||
| @ -1240,27 +1241,6 @@ void RasterizerCacheOpenGL::ValidateSurface(const Surface& surface, VAddr addr, | ||||
|             continue; | ||||
|         } | ||||
| 
 | ||||
|         // D24S8 to RGBA8
 | ||||
|         if (surface->pixel_format == PixelFormat::RGBA8) { | ||||
|             params.pixel_format = PixelFormat::D24S8; | ||||
|             Surface reinterpret_surface = | ||||
|                 FindMatch<MatchFlags::Copy>(surface_cache, params, ScaleMatch::Ignore, interval); | ||||
|             if (reinterpret_surface != nullptr) { | ||||
|                 ASSERT(reinterpret_surface->pixel_format == PixelFormat::D24S8); | ||||
| 
 | ||||
|                 SurfaceInterval convert_interval = params.GetCopyableInterval(reinterpret_surface); | ||||
|                 SurfaceParams convert_params = surface->FromInterval(convert_interval); | ||||
|                 auto src_rect = reinterpret_surface->GetScaledSubRect(convert_params); | ||||
|                 auto dest_rect = surface->GetScaledSubRect(convert_params); | ||||
| 
 | ||||
|                 ConvertD24S8toABGR(reinterpret_surface->texture.handle, src_rect, | ||||
|                                    surface->texture.handle, dest_rect); | ||||
| 
 | ||||
|                 surface->invalid_regions.erase(convert_interval); | ||||
|                 continue; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         // Load data from Switch memory
 | ||||
|         FlushRegion(params.addr, params.size); | ||||
|         surface->LoadGLBuffer(params.addr, params.end); | ||||
|  | ||||
| @ -24,6 +24,7 @@ | ||||
| #include "common/math_util.h" | ||||
| #include "video_core/gpu.h" | ||||
| #include "video_core/renderer_opengl/gl_resource_manager.h" | ||||
| #include "video_core/textures/texture.h" | ||||
| 
 | ||||
| struct CachedSurface; | ||||
| using Surface = std::shared_ptr<CachedSurface>; | ||||
| @ -51,30 +52,8 @@ enum class ScaleMatch { | ||||
| 
 | ||||
| struct SurfaceParams { | ||||
|     enum class PixelFormat { | ||||
|         // First 5 formats are shared between textures and color buffers
 | ||||
|         RGBA8 = 0, | ||||
|         RGB8 = 1, | ||||
|         RGB5A1 = 2, | ||||
|         RGB565 = 3, | ||||
|         RGBA4 = 4, | ||||
| 
 | ||||
|         // Texture-only formats
 | ||||
|         IA8 = 5, | ||||
|         RG8 = 6, | ||||
|         I8 = 7, | ||||
|         A8 = 8, | ||||
|         IA4 = 9, | ||||
|         I4 = 10, | ||||
|         A4 = 11, | ||||
|         ETC1 = 12, | ||||
|         ETC1A4 = 13, | ||||
| 
 | ||||
|         // Depth buffer-only formats
 | ||||
|         D16 = 14, | ||||
|         // gap
 | ||||
|         D24 = 16, | ||||
|         D24S8 = 17, | ||||
| 
 | ||||
|         DXT1 = 1, | ||||
|         Invalid = 255, | ||||
|     }; | ||||
| 
 | ||||
| @ -88,28 +67,15 @@ struct SurfaceParams { | ||||
|     }; | ||||
| 
 | ||||
|     static constexpr unsigned int GetFormatBpp(PixelFormat format) { | ||||
|         constexpr std::array<unsigned int, 18> bpp_table = { | ||||
|         if (format == PixelFormat::Invalid) | ||||
|             return 0; | ||||
| 
 | ||||
|         constexpr std::array<unsigned int, 2> bpp_table = { | ||||
|             32, // RGBA8
 | ||||
|             24, // RGB8
 | ||||
|             16, // RGB5A1
 | ||||
|             16, // RGB565
 | ||||
|             16, // RGBA4
 | ||||
|             16, // IA8
 | ||||
|             16, // RG8
 | ||||
|             8,  // I8
 | ||||
|             8,  // A8
 | ||||
|             8,  // IA4
 | ||||
|             4,  // I4
 | ||||
|             4,  // A4
 | ||||
|             4,  // ETC1
 | ||||
|             8,  // ETC1A4
 | ||||
|             16, // D16
 | ||||
|             0, | ||||
|             24, // D24
 | ||||
|             32, // D24S8
 | ||||
|             64, // DXT1
 | ||||
|         }; | ||||
| 
 | ||||
|         assert(static_cast<size_t>(format) < bpp_table.size()); | ||||
|         ASSERT(static_cast<size_t>(format) < bpp_table.size()); | ||||
|         return bpp_table[static_cast<size_t>(format)]; | ||||
|     } | ||||
|     unsigned int GetFormatBpp() const { | ||||
| @ -134,6 +100,18 @@ struct SurfaceParams { | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     static PixelFormat PixelFormatFromTextureFormat(Tegra::Texture::TextureFormat format) { | ||||
|         // TODO(Subv): Properly implement this
 | ||||
|         switch (format) { | ||||
|         case Tegra::Texture::TextureFormat::A8R8G8B8: | ||||
|             return PixelFormat::RGBA8; | ||||
|         case Tegra::Texture::TextureFormat::DXT1: | ||||
|             return PixelFormat::DXT1; | ||||
|         default: | ||||
|             UNREACHABLE(); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     static bool CheckFormatsBlittable(PixelFormat pixel_format_a, PixelFormat pixel_format_b) { | ||||
|         SurfaceType a_type = GetFormatType(pixel_format_a); | ||||
|         SurfaceType b_type = GetFormatType(pixel_format_b); | ||||
| @ -154,22 +132,17 @@ struct SurfaceParams { | ||||
|         return false; | ||||
|     } | ||||
| 
 | ||||
|     static constexpr SurfaceType GetFormatType(PixelFormat pixel_format) { | ||||
|         if ((unsigned int)pixel_format < 5) { | ||||
|     static SurfaceType GetFormatType(PixelFormat pixel_format) { | ||||
|         if ((unsigned int)pixel_format <= static_cast<unsigned int>(PixelFormat::RGBA8)) { | ||||
|             return SurfaceType::Color; | ||||
|         } | ||||
| 
 | ||||
|         if ((unsigned int)pixel_format < 14) { | ||||
|         if ((unsigned int)pixel_format <= static_cast<unsigned int>(PixelFormat::DXT1)) { | ||||
|             return SurfaceType::Texture; | ||||
|         } | ||||
| 
 | ||||
|         if (pixel_format == PixelFormat::D16 || pixel_format == PixelFormat::D24) { | ||||
|             return SurfaceType::Depth; | ||||
|         } | ||||
| 
 | ||||
|         if (pixel_format == PixelFormat::D24S8) { | ||||
|             return SurfaceType::DepthStencil; | ||||
|         } | ||||
|         // TODO(Subv): Implement the other formats
 | ||||
|         ASSERT(false); | ||||
| 
 | ||||
|         return SurfaceType::Invalid; | ||||
|     } | ||||
| @ -265,12 +238,10 @@ struct CachedSurface : SurfaceParams { | ||||
|     OGLTexture texture; | ||||
| 
 | ||||
|     static constexpr unsigned int GetGLBytesPerPixel(PixelFormat format) { | ||||
|         // OpenGL needs 4 bpp alignment for D24 since using GL_UNSIGNED_INT as type
 | ||||
|         return format == PixelFormat::Invalid | ||||
|                    ? 0 | ||||
|                    : (format == PixelFormat::D24 || GetFormatType(format) == SurfaceType::Texture) | ||||
|                          ? 4 | ||||
|                          : SurfaceParams::GetFormatBpp(format) / 8; | ||||
|         if (format == PixelFormat::Invalid) | ||||
|             return 0; | ||||
| 
 | ||||
|         return SurfaceParams::GetFormatBpp(format) / 8; | ||||
|     } | ||||
| 
 | ||||
|     std::unique_ptr<u8[]> gl_buffer; | ||||
| @ -313,7 +284,7 @@ public: | ||||
|                                         bool load_if_create); | ||||
| 
 | ||||
|     /// Get a surface based on the texture configuration
 | ||||
|     Surface GetTextureSurface(const void* config); | ||||
|     Surface GetTextureSurface(const Tegra::Texture::FullTextureInfo& config); | ||||
| 
 | ||||
|     /// Get the color and depth surfaces based on the framebuffer configuration
 | ||||
|     SurfaceSurfaceRect_Tuple GetFramebufferSurfaces(bool using_color_fb, bool using_depth_fb, | ||||
|  | ||||
| @ -194,7 +194,7 @@ void OpenGLState::Apply() const { | ||||
|     // Textures
 | ||||
|     for (unsigned i = 0; i < ARRAY_SIZE(texture_units); ++i) { | ||||
|         if (texture_units[i].texture_2d != cur_state.texture_units[i].texture_2d) { | ||||
|             glActiveTexture(TextureUnits::PicaTexture(i).Enum()); | ||||
|             glActiveTexture(TextureUnits::MaxwellTexture(i).Enum()); | ||||
|             glBindTexture(GL_TEXTURE_2D, texture_units[i].texture_2d); | ||||
|         } | ||||
|         if (texture_units[i].sampler != cur_state.texture_units[i].sampler) { | ||||
|  | ||||
| @ -16,7 +16,7 @@ struct TextureUnit { | ||||
|     } | ||||
| }; | ||||
| 
 | ||||
| constexpr TextureUnit PicaTexture(int unit) { | ||||
| constexpr TextureUnit MaxwellTexture(int unit) { | ||||
|     return TextureUnit{unit}; | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -47,4 +47,27 @@ inline GLenum PrimitiveTopology(Maxwell::PrimitiveTopology topology) { | ||||
|     return {}; | ||||
| } | ||||
| 
 | ||||
| inline GLenum TextureFilterMode(Tegra::Texture::TextureFilter filter_mode) { | ||||
|     switch (filter_mode) { | ||||
|     case Tegra::Texture::TextureFilter::Linear: | ||||
|         return GL_LINEAR; | ||||
|     case Tegra::Texture::TextureFilter::Nearest: | ||||
|         return GL_NEAREST; | ||||
|     } | ||||
|     LOG_CRITICAL(Render_OpenGL, "Unimplemented texture filter mode=%u", | ||||
|                  static_cast<u32>(filter_mode)); | ||||
|     UNREACHABLE(); | ||||
|     return {}; | ||||
| } | ||||
| 
 | ||||
| inline GLenum WrapMode(Tegra::Texture::WrapMode wrap_mode) { | ||||
|     switch (wrap_mode) { | ||||
|     case Tegra::Texture::WrapMode::ClampToEdge: | ||||
|         return GL_CLAMP_TO_EDGE; | ||||
|     } | ||||
|     LOG_CRITICAL(Render_OpenGL, "Unimplemented texture wrap mode=%u", static_cast<u32>(wrap_mode)); | ||||
|     UNREACHABLE(); | ||||
|     return {}; | ||||
| } | ||||
| 
 | ||||
| } // namespace MaxwellToGL
 | ||||
|  | ||||
| @ -37,6 +37,16 @@ enum class TICHeaderVersion : u32 { | ||||
|     BlockLinearColorKey = 4, | ||||
| }; | ||||
| 
 | ||||
| enum class ComponentType : u32 { | ||||
|     SNORM = 1, | ||||
|     UNORM = 2, | ||||
|     SINT = 3, | ||||
|     UINT = 4, | ||||
|     SNORM_FORCE_FP16 = 5, | ||||
|     UNORM_FORCE_FP16 = 6, | ||||
|     FLOAT = 7 | ||||
| }; | ||||
| 
 | ||||
| union TextureHandle { | ||||
|     u32 raw; | ||||
|     BitField<0, 20, u32> tic_id; | ||||
| @ -48,10 +58,10 @@ struct TICEntry { | ||||
|     union { | ||||
|         u32 raw; | ||||
|         BitField<0, 7, TextureFormat> format; | ||||
|         BitField<7, 3, u32> r_type; | ||||
|         BitField<10, 3, u32> g_type; | ||||
|         BitField<13, 3, u32> b_type; | ||||
|         BitField<16, 3, u32> a_type; | ||||
|         BitField<7, 3, ComponentType> r_type; | ||||
|         BitField<10, 3, ComponentType> g_type; | ||||
|         BitField<13, 3, ComponentType> b_type; | ||||
|         BitField<16, 3, ComponentType> a_type; | ||||
|     }; | ||||
|     u32 address_low; | ||||
|     union { | ||||
| @ -77,6 +87,11 @@ struct TICEntry { | ||||
|     u32 Height() const { | ||||
|         return height_minus_1 + 1; | ||||
|     } | ||||
| 
 | ||||
|     bool IsTiled() const { | ||||
|         return header_version == TICHeaderVersion::BlockLinear || | ||||
|                header_version == TICHeaderVersion::BlockLinearColorKey; | ||||
|     } | ||||
| }; | ||||
| static_assert(sizeof(TICEntry) == 0x20, "TICEntry has wrong size"); | ||||
| 
 | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user
	 bunnei
						bunnei