mirror of
				https://github.com/PabloMK7/citra.git
				synced 2025-10-31 13:50:03 +00:00 
			
		
		
		
	Merge pull request #3497 from wwylele/texture-cube-new
gl_rasterizer: implement TextureCube
This commit is contained in:
		
						commit
						972db17247
					
				
					 7 changed files with 142 additions and 2 deletions
				
			
		|  | @ -40,6 +40,12 @@ RasterizerOpenGL::RasterizerOpenGL() : shader_dirty(true) { | ||||||
|         state.texture_units[i].sampler = texture_samplers[i].sampler.handle; |         state.texture_units[i].sampler = texture_samplers[i].sampler.handle; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     // Create cubemap texture and sampler objects
 | ||||||
|  |     texture_cube_sampler.Create(); | ||||||
|  |     state.texture_cube_unit.sampler = texture_cube_sampler.sampler.handle; | ||||||
|  |     texture_cube.Create(); | ||||||
|  |     state.texture_cube_unit.texture_cube = texture_cube.handle; | ||||||
|  | 
 | ||||||
|     // Generate VBO, VAO and UBO
 |     // Generate VBO, VAO and UBO
 | ||||||
|     vertex_buffer = OGLStreamBuffer::MakeBuffer(GLAD_GL_ARB_buffer_storage, GL_ARRAY_BUFFER); |     vertex_buffer = OGLStreamBuffer::MakeBuffer(GLAD_GL_ARB_buffer_storage, GL_ARRAY_BUFFER); | ||||||
|     vertex_buffer->Create(VERTEX_BUFFER_SIZE, VERTEX_BUFFER_SIZE / 2); |     vertex_buffer->Create(VERTEX_BUFFER_SIZE, VERTEX_BUFFER_SIZE / 2); | ||||||
|  | @ -380,6 +386,25 @@ void RasterizerOpenGL::DrawTriangles() { | ||||||
|         const auto& texture = pica_textures[texture_index]; |         const auto& texture = pica_textures[texture_index]; | ||||||
| 
 | 
 | ||||||
|         if (texture.enabled) { |         if (texture.enabled) { | ||||||
|  |             if (texture_index == 0) { | ||||||
|  |                 using TextureType = Pica::TexturingRegs::TextureConfig::TextureType; | ||||||
|  |                 switch (texture.config.type.Value()) { | ||||||
|  |                 case TextureType::TextureCube: | ||||||
|  |                     using CubeFace = Pica::TexturingRegs::CubeFace; | ||||||
|  |                     res_cache.FillTextureCube( | ||||||
|  |                         texture_cube.handle, texture, | ||||||
|  |                         regs.texturing.GetCubePhysicalAddress(CubeFace::PositiveX), | ||||||
|  |                         regs.texturing.GetCubePhysicalAddress(CubeFace::NegativeX), | ||||||
|  |                         regs.texturing.GetCubePhysicalAddress(CubeFace::PositiveY), | ||||||
|  |                         regs.texturing.GetCubePhysicalAddress(CubeFace::NegativeY), | ||||||
|  |                         regs.texturing.GetCubePhysicalAddress(CubeFace::PositiveZ), | ||||||
|  |                         regs.texturing.GetCubePhysicalAddress(CubeFace::NegativeZ)); | ||||||
|  |                     texture_cube_sampler.SyncWithConfig(texture.config); | ||||||
|  |                     state.texture_units[texture_index].texture_2d = 0; | ||||||
|  |                     continue; // Texture unit 0 setup finished. Continue to next unit
 | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|             texture_samplers[texture_index].SyncWithConfig(texture.config); |             texture_samplers[texture_index].SyncWithConfig(texture.config); | ||||||
|             Surface surface = res_cache.GetTextureSurface(texture); |             Surface surface = res_cache.GetTextureSurface(texture); | ||||||
|             if (surface != nullptr) { |             if (surface != nullptr) { | ||||||
|  | @ -1259,6 +1284,10 @@ void RasterizerOpenGL::SetShader() { | ||||||
|         if (uniform_tex != -1) { |         if (uniform_tex != -1) { | ||||||
|             glUniform1i(uniform_tex, TextureUnits::PicaTexture(2).id); |             glUniform1i(uniform_tex, TextureUnits::PicaTexture(2).id); | ||||||
|         } |         } | ||||||
|  |         uniform_tex = glGetUniformLocation(shader->shader.handle, "tex_cube"); | ||||||
|  |         if (uniform_tex != -1) { | ||||||
|  |             glUniform1i(uniform_tex, TextureUnits::TextureCube.id); | ||||||
|  |         } | ||||||
| 
 | 
 | ||||||
|         // Set the texture samplers to correspond to different lookup table texture units
 |         // Set the texture samplers to correspond to different lookup table texture units
 | ||||||
|         GLint uniform_lut = glGetUniformLocation(shader->shader.handle, "lighting_lut"); |         GLint uniform_lut = glGetUniformLocation(shader->shader.handle, "lighting_lut"); | ||||||
|  |  | ||||||
|  | @ -292,6 +292,10 @@ private: | ||||||
|     OGLBuffer uniform_buffer; |     OGLBuffer uniform_buffer; | ||||||
|     OGLFramebuffer framebuffer; |     OGLFramebuffer framebuffer; | ||||||
| 
 | 
 | ||||||
|  |     // TODO (wwylele): consider caching texture cube in the rasterizer cache
 | ||||||
|  |     OGLTexture texture_cube; | ||||||
|  |     SamplerInfo texture_cube_sampler; | ||||||
|  | 
 | ||||||
|     OGLBuffer lighting_lut_buffer; |     OGLBuffer lighting_lut_buffer; | ||||||
|     OGLTexture lighting_lut; |     OGLTexture lighting_lut; | ||||||
|     std::array<std::array<GLvec2, 256>, Pica::LightingRegs::NumLightingSampler> lighting_lut_data{}; |     std::array<std::array<GLvec2, 256>, Pica::LightingRegs::NumLightingSampler> lighting_lut_data{}; | ||||||
|  |  | ||||||
|  | @ -3,6 +3,7 @@ | ||||||
| // Refer to the license.txt file included.
 | // Refer to the license.txt file included.
 | ||||||
| 
 | 
 | ||||||
| #include <algorithm> | #include <algorithm> | ||||||
|  | #include <array> | ||||||
| #include <atomic> | #include <atomic> | ||||||
| #include <cstring> | #include <cstring> | ||||||
| #include <iterator> | #include <iterator> | ||||||
|  | @ -1192,10 +1193,14 @@ SurfaceRect_Tuple RasterizerCacheOpenGL::GetSurfaceSubRect(const SurfaceParams& | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| Surface RasterizerCacheOpenGL::GetTextureSurface( | Surface RasterizerCacheOpenGL::GetTextureSurface( | ||||||
|     const Pica::TexturingRegs::FullTextureConfig& config) { |     const Pica::TexturingRegs::FullTextureConfig& config, PAddr addr_override) { | ||||||
|     Pica::Texture::TextureInfo info = |     Pica::Texture::TextureInfo info = | ||||||
|         Pica::Texture::TextureInfo::FromPicaRegister(config.config, config.format); |         Pica::Texture::TextureInfo::FromPicaRegister(config.config, config.format); | ||||||
| 
 | 
 | ||||||
|  |     if (addr_override != 0) { | ||||||
|  |         info.physical_address = addr_override; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     SurfaceParams params; |     SurfaceParams params; | ||||||
|     params.addr = info.physical_address; |     params.addr = info.physical_address; | ||||||
|     params.width = info.width; |     params.width = info.width; | ||||||
|  | @ -1223,6 +1228,78 @@ Surface RasterizerCacheOpenGL::GetTextureSurface( | ||||||
|     return GetSurface(params, ScaleMatch::Ignore, true); |     return GetSurface(params, ScaleMatch::Ignore, true); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | void RasterizerCacheOpenGL::FillTextureCube(GLuint dest_handle, | ||||||
|  |                                             const Pica::TexturingRegs::FullTextureConfig& config, | ||||||
|  |                                             PAddr px, PAddr nx, PAddr py, PAddr ny, PAddr pz, | ||||||
|  |                                             PAddr nz) { | ||||||
|  |     ASSERT(config.config.width == config.config.height); | ||||||
|  |     struct FaceTuple { | ||||||
|  |         PAddr address; | ||||||
|  |         GLenum gl_face; | ||||||
|  |         Surface surface; | ||||||
|  |     }; | ||||||
|  |     std::array<FaceTuple, 6> faces{{ | ||||||
|  |         {px, GL_TEXTURE_CUBE_MAP_POSITIVE_X}, | ||||||
|  |         {nx, GL_TEXTURE_CUBE_MAP_NEGATIVE_X}, | ||||||
|  |         {py, GL_TEXTURE_CUBE_MAP_POSITIVE_Y}, | ||||||
|  |         {ny, GL_TEXTURE_CUBE_MAP_NEGATIVE_Y}, | ||||||
|  |         {pz, GL_TEXTURE_CUBE_MAP_POSITIVE_Z}, | ||||||
|  |         {nz, GL_TEXTURE_CUBE_MAP_NEGATIVE_Z}, | ||||||
|  |     }}; | ||||||
|  | 
 | ||||||
|  |     u16 res_scale = 1; | ||||||
|  |     for (auto& face : faces) { | ||||||
|  |         face.surface = GetTextureSurface(config, face.address); | ||||||
|  |         res_scale = std::max(res_scale, face.surface->res_scale); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     u32 scaled_size = res_scale * config.config.width; | ||||||
|  | 
 | ||||||
|  |     OpenGLState state = OpenGLState::GetCurState(); | ||||||
|  | 
 | ||||||
|  |     OpenGLState prev_state = state; | ||||||
|  |     SCOPE_EXIT({ prev_state.Apply(); }); | ||||||
|  | 
 | ||||||
|  |     state.texture_cube_unit.texture_cube = dest_handle; | ||||||
|  |     state.Apply(); | ||||||
|  |     glActiveTexture(TextureUnits::TextureCube.Enum()); | ||||||
|  |     FormatTuple format_tuple = GetFormatTuple(faces[0].surface->pixel_format); | ||||||
|  | 
 | ||||||
|  |     GLint cur_size, cur_format; | ||||||
|  |     glGetTexLevelParameteriv(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0, GL_TEXTURE_WIDTH, &cur_size); | ||||||
|  |     glGetTexLevelParameteriv(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0, GL_TEXTURE_INTERNAL_FORMAT, | ||||||
|  |                              &cur_format); | ||||||
|  | 
 | ||||||
|  |     if (cur_size != scaled_size || cur_format != format_tuple.internal_format) { | ||||||
|  |         for (auto& face : faces) { | ||||||
|  |             glTexImage2D(face.gl_face, 0, format_tuple.internal_format, scaled_size, scaled_size, 0, | ||||||
|  |                          format_tuple.format, format_tuple.type, nullptr); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     state.draw.read_framebuffer = read_framebuffer.handle; | ||||||
|  |     state.draw.draw_framebuffer = draw_framebuffer.handle; | ||||||
|  |     state.ResetTexture(dest_handle); | ||||||
|  | 
 | ||||||
|  |     for (auto& face : faces) { | ||||||
|  |         state.ResetTexture(face.surface->texture.handle); | ||||||
|  |         state.Apply(); | ||||||
|  |         glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, | ||||||
|  |                                face.surface->texture.handle, 0); | ||||||
|  |         glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0, | ||||||
|  |                                0); | ||||||
|  | 
 | ||||||
|  |         glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, face.gl_face, dest_handle, | ||||||
|  |                                0); | ||||||
|  |         glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0, | ||||||
|  |                                0); | ||||||
|  | 
 | ||||||
|  |         auto src_rect = face.surface->GetScaledRect(); | ||||||
|  |         glBlitFramebuffer(src_rect.left, src_rect.bottom, src_rect.right, src_rect.top, 0, 0, | ||||||
|  |                           scaled_size, scaled_size, GL_COLOR_BUFFER_BIT, GL_LINEAR); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
| SurfaceSurfaceRect_Tuple RasterizerCacheOpenGL::GetFramebufferSurfaces( | SurfaceSurfaceRect_Tuple RasterizerCacheOpenGL::GetFramebufferSurfaces( | ||||||
|     bool using_color_fb, bool using_depth_fb, const MathUtil::Rectangle<s32>& viewport_rect) { |     bool using_color_fb, bool using_depth_fb, const MathUtil::Rectangle<s32>& viewport_rect) { | ||||||
|     const auto& regs = Pica::g_state.regs; |     const auto& regs = Pica::g_state.regs; | ||||||
|  |  | ||||||
|  | @ -322,7 +322,12 @@ public: | ||||||
|                                         bool load_if_create); |                                         bool load_if_create); | ||||||
| 
 | 
 | ||||||
|     /// Get a surface based on the texture configuration
 |     /// Get a surface based on the texture configuration
 | ||||||
|     Surface GetTextureSurface(const Pica::TexturingRegs::FullTextureConfig& config); |     Surface GetTextureSurface(const Pica::TexturingRegs::FullTextureConfig& config, | ||||||
|  |                               PAddr addr_override = 0); | ||||||
|  | 
 | ||||||
|  |     /// Copy surfaces to a cubemap texture based on the texture configuration
 | ||||||
|  |     void FillTextureCube(GLuint dest_handle, const Pica::TexturingRegs::FullTextureConfig& config, | ||||||
|  |                          PAddr px, PAddr nx, PAddr py, PAddr ny, PAddr pz, PAddr nz); | ||||||
| 
 | 
 | ||||||
|     /// Get the color and depth surfaces based on the framebuffer configuration
 |     /// Get the color and depth surfaces based on the framebuffer configuration
 | ||||||
|     SurfaceSurfaceRect_Tuple GetFramebufferSurfaces(bool using_color_fb, bool using_depth_fb, |     SurfaceSurfaceRect_Tuple GetFramebufferSurfaces(bool using_color_fb, bool using_depth_fb, | ||||||
|  |  | ||||||
|  | @ -200,6 +200,8 @@ static std::string SampleTexture(const PicaShaderConfig& config, unsigned textur | ||||||
|             return "texture(tex[0], texcoord[0])"; |             return "texture(tex[0], texcoord[0])"; | ||||||
|         case TexturingRegs::TextureConfig::Projection2D: |         case TexturingRegs::TextureConfig::Projection2D: | ||||||
|             return "textureProj(tex[0], vec3(texcoord[0], texcoord0_w))"; |             return "textureProj(tex[0], vec3(texcoord[0], texcoord0_w))"; | ||||||
|  |         case TexturingRegs::TextureConfig::TextureCube: | ||||||
|  |             return "texture(tex_cube, vec3(texcoord[0], texcoord0_w))"; | ||||||
|         default: |         default: | ||||||
|             LOG_CRITICAL(HW_GPU, "Unhandled texture type %x", |             LOG_CRITICAL(HW_GPU, "Unhandled texture type %x", | ||||||
|                          static_cast<int>(state.texture0_type)); |                          static_cast<int>(state.texture0_type)); | ||||||
|  | @ -1061,6 +1063,7 @@ in vec4 gl_FragCoord; | ||||||
| out vec4 color; | out vec4 color; | ||||||
| 
 | 
 | ||||||
| uniform sampler2D tex[3]; | uniform sampler2D tex[3]; | ||||||
|  | uniform samplerCube tex_cube; | ||||||
| uniform samplerBuffer lighting_lut; | uniform samplerBuffer lighting_lut; | ||||||
| uniform samplerBuffer fog_lut; | uniform samplerBuffer fog_lut; | ||||||
| uniform samplerBuffer proctex_noise_lut; | uniform samplerBuffer proctex_noise_lut; | ||||||
|  |  | ||||||
|  | @ -52,6 +52,9 @@ OpenGLState::OpenGLState() { | ||||||
|         texture_unit.sampler = 0; |         texture_unit.sampler = 0; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     texture_cube_unit.texture_cube = 0; | ||||||
|  |     texture_cube_unit.sampler = 0; | ||||||
|  | 
 | ||||||
|     lighting_lut.texture_buffer = 0; |     lighting_lut.texture_buffer = 0; | ||||||
| 
 | 
 | ||||||
|     fog_lut.texture_buffer = 0; |     fog_lut.texture_buffer = 0; | ||||||
|  | @ -201,6 +204,14 @@ void OpenGLState::Apply() const { | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     if (texture_cube_unit.texture_cube != cur_state.texture_cube_unit.texture_cube) { | ||||||
|  |         glActiveTexture(TextureUnits::TextureCube.Enum()); | ||||||
|  |         glBindTexture(GL_TEXTURE_CUBE_MAP, texture_cube_unit.texture_cube); | ||||||
|  |     } | ||||||
|  |     if (texture_cube_unit.sampler != cur_state.texture_cube_unit.sampler) { | ||||||
|  |         glBindSampler(TextureUnits::TextureCube.id, texture_cube_unit.sampler); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     // Lighting LUTs
 |     // Lighting LUTs
 | ||||||
|     if (lighting_lut.texture_buffer != cur_state.lighting_lut.texture_buffer) { |     if (lighting_lut.texture_buffer != cur_state.lighting_lut.texture_buffer) { | ||||||
|         glActiveTexture(TextureUnits::LightingLUT.Enum()); |         glActiveTexture(TextureUnits::LightingLUT.Enum()); | ||||||
|  | @ -311,6 +322,8 @@ OpenGLState& OpenGLState::ResetTexture(GLuint handle) { | ||||||
|             unit.texture_2d = 0; |             unit.texture_2d = 0; | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |     if (texture_cube_unit.texture_cube == handle) | ||||||
|  |         texture_cube_unit.texture_cube = 0; | ||||||
|     if (lighting_lut.texture_buffer == handle) |     if (lighting_lut.texture_buffer == handle) | ||||||
|         lighting_lut.texture_buffer = 0; |         lighting_lut.texture_buffer = 0; | ||||||
|     if (fog_lut.texture_buffer == handle) |     if (fog_lut.texture_buffer == handle) | ||||||
|  | @ -334,6 +347,9 @@ OpenGLState& OpenGLState::ResetSampler(GLuint handle) { | ||||||
|             unit.sampler = 0; |             unit.sampler = 0; | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |     if (texture_cube_unit.sampler == handle) { | ||||||
|  |         texture_cube_unit.sampler = 0; | ||||||
|  |     } | ||||||
|     return *this; |     return *this; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -27,6 +27,7 @@ constexpr TextureUnit ProcTexColorMap{6}; | ||||||
| constexpr TextureUnit ProcTexAlphaMap{7}; | constexpr TextureUnit ProcTexAlphaMap{7}; | ||||||
| constexpr TextureUnit ProcTexLUT{8}; | constexpr TextureUnit ProcTexLUT{8}; | ||||||
| constexpr TextureUnit ProcTexDiffLUT{9}; | constexpr TextureUnit ProcTexDiffLUT{9}; | ||||||
|  | constexpr TextureUnit TextureCube{10}; | ||||||
| 
 | 
 | ||||||
| } // namespace TextureUnits
 | } // namespace TextureUnits
 | ||||||
| 
 | 
 | ||||||
|  | @ -87,6 +88,11 @@ public: | ||||||
|         GLuint sampler;    // GL_SAMPLER_BINDING
 |         GLuint sampler;    // GL_SAMPLER_BINDING
 | ||||||
|     } texture_units[3]; |     } texture_units[3]; | ||||||
| 
 | 
 | ||||||
|  |     struct { | ||||||
|  |         GLuint texture_cube; // GL_TEXTURE_BINDING_CUBE_MAP
 | ||||||
|  |         GLuint sampler;      // GL_SAMPLER_BINDING
 | ||||||
|  |     } texture_cube_unit; | ||||||
|  | 
 | ||||||
|     struct { |     struct { | ||||||
|         GLuint texture_buffer; // GL_TEXTURE_BINDING_BUFFER
 |         GLuint texture_buffer; // GL_TEXTURE_BINDING_BUFFER
 | ||||||
|     } lighting_lut; |     } lighting_lut; | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue