citra-emu
/
citra-canary
Archived
1
0
Fork 0

gl_rasterizer: implement texture cube

This commit is contained in:
wwylele 2018-03-09 16:46:34 +02:00
parent 33a0e87ac2
commit 15e8664ef7
7 changed files with 134 additions and 2 deletions

View File

@ -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.Create(); vertex_buffer.Create();
vertex_array.Create(); vertex_array.Create();
@ -352,6 +358,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) {
@ -1225,6 +1250,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");

View File

@ -287,6 +287,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{};

View File

@ -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,70 @@ 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);
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;

View File

@ -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,

View File

@ -202,6 +202,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));
@ -1060,6 +1062,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;

View File

@ -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;
} }

View File

@ -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;