gl_rasterizer: implement texture cube
This commit is contained in:
parent
33a0e87ac2
commit
15e8664ef7
|
@ -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");
|
||||||
|
|
|
@ -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{};
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
Reference in New Issue