Merge pull request #3497 from wwylele/texture-cube-new
gl_rasterizer: implement TextureCube
This commit is contained in:
commit
972db17247
|
@ -40,6 +40,12 @@ RasterizerOpenGL::RasterizerOpenGL() : shader_dirty(true) {
|
|||
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
|
||||
vertex_buffer = OGLStreamBuffer::MakeBuffer(GLAD_GL_ARB_buffer_storage, GL_ARRAY_BUFFER);
|
||||
vertex_buffer->Create(VERTEX_BUFFER_SIZE, VERTEX_BUFFER_SIZE / 2);
|
||||
|
@ -380,6 +386,25 @@ void RasterizerOpenGL::DrawTriangles() {
|
|||
const auto& texture = pica_textures[texture_index];
|
||||
|
||||
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);
|
||||
Surface surface = res_cache.GetTextureSurface(texture);
|
||||
if (surface != nullptr) {
|
||||
|
@ -1259,6 +1284,10 @@ void RasterizerOpenGL::SetShader() {
|
|||
if (uniform_tex != -1) {
|
||||
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
|
||||
GLint uniform_lut = glGetUniformLocation(shader->shader.handle, "lighting_lut");
|
||||
|
|
|
@ -292,6 +292,10 @@ private:
|
|||
OGLBuffer uniform_buffer;
|
||||
OGLFramebuffer framebuffer;
|
||||
|
||||
// TODO (wwylele): consider caching texture cube in the rasterizer cache
|
||||
OGLTexture texture_cube;
|
||||
SamplerInfo texture_cube_sampler;
|
||||
|
||||
OGLBuffer lighting_lut_buffer;
|
||||
OGLTexture lighting_lut;
|
||||
std::array<std::array<GLvec2, 256>, Pica::LightingRegs::NumLightingSampler> lighting_lut_data{};
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
// Refer to the license.txt file included.
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <atomic>
|
||||
#include <cstring>
|
||||
#include <iterator>
|
||||
|
@ -1192,10 +1193,14 @@ SurfaceRect_Tuple RasterizerCacheOpenGL::GetSurfaceSubRect(const SurfaceParams&
|
|||
}
|
||||
|
||||
Surface RasterizerCacheOpenGL::GetTextureSurface(
|
||||
const Pica::TexturingRegs::FullTextureConfig& config) {
|
||||
const Pica::TexturingRegs::FullTextureConfig& config, PAddr addr_override) {
|
||||
Pica::Texture::TextureInfo info =
|
||||
Pica::Texture::TextureInfo::FromPicaRegister(config.config, config.format);
|
||||
|
||||
if (addr_override != 0) {
|
||||
info.physical_address = addr_override;
|
||||
}
|
||||
|
||||
SurfaceParams params;
|
||||
params.addr = info.physical_address;
|
||||
params.width = info.width;
|
||||
|
@ -1223,6 +1228,78 @@ Surface RasterizerCacheOpenGL::GetTextureSurface(
|
|||
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(
|
||||
bool using_color_fb, bool using_depth_fb, const MathUtil::Rectangle<s32>& viewport_rect) {
|
||||
const auto& regs = Pica::g_state.regs;
|
||||
|
|
|
@ -322,7 +322,12 @@ public:
|
|||
bool load_if_create);
|
||||
|
||||
/// 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
|
||||
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])";
|
||||
case TexturingRegs::TextureConfig::Projection2D:
|
||||
return "textureProj(tex[0], vec3(texcoord[0], texcoord0_w))";
|
||||
case TexturingRegs::TextureConfig::TextureCube:
|
||||
return "texture(tex_cube, vec3(texcoord[0], texcoord0_w))";
|
||||
default:
|
||||
LOG_CRITICAL(HW_GPU, "Unhandled texture type %x",
|
||||
static_cast<int>(state.texture0_type));
|
||||
|
@ -1061,6 +1063,7 @@ in vec4 gl_FragCoord;
|
|||
out vec4 color;
|
||||
|
||||
uniform sampler2D tex[3];
|
||||
uniform samplerCube tex_cube;
|
||||
uniform samplerBuffer lighting_lut;
|
||||
uniform samplerBuffer fog_lut;
|
||||
uniform samplerBuffer proctex_noise_lut;
|
||||
|
|
|
@ -52,6 +52,9 @@ OpenGLState::OpenGLState() {
|
|||
texture_unit.sampler = 0;
|
||||
}
|
||||
|
||||
texture_cube_unit.texture_cube = 0;
|
||||
texture_cube_unit.sampler = 0;
|
||||
|
||||
lighting_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
|
||||
if (lighting_lut.texture_buffer != cur_state.lighting_lut.texture_buffer) {
|
||||
glActiveTexture(TextureUnits::LightingLUT.Enum());
|
||||
|
@ -311,6 +322,8 @@ OpenGLState& OpenGLState::ResetTexture(GLuint handle) {
|
|||
unit.texture_2d = 0;
|
||||
}
|
||||
}
|
||||
if (texture_cube_unit.texture_cube == handle)
|
||||
texture_cube_unit.texture_cube = 0;
|
||||
if (lighting_lut.texture_buffer == handle)
|
||||
lighting_lut.texture_buffer = 0;
|
||||
if (fog_lut.texture_buffer == handle)
|
||||
|
@ -334,6 +347,9 @@ OpenGLState& OpenGLState::ResetSampler(GLuint handle) {
|
|||
unit.sampler = 0;
|
||||
}
|
||||
}
|
||||
if (texture_cube_unit.sampler == handle) {
|
||||
texture_cube_unit.sampler = 0;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
|
|
@ -27,6 +27,7 @@ constexpr TextureUnit ProcTexColorMap{6};
|
|||
constexpr TextureUnit ProcTexAlphaMap{7};
|
||||
constexpr TextureUnit ProcTexLUT{8};
|
||||
constexpr TextureUnit ProcTexDiffLUT{9};
|
||||
constexpr TextureUnit TextureCube{10};
|
||||
|
||||
} // namespace TextureUnits
|
||||
|
||||
|
@ -87,6 +88,11 @@ public:
|
|||
GLuint sampler; // GL_SAMPLER_BINDING
|
||||
} texture_units[3];
|
||||
|
||||
struct {
|
||||
GLuint texture_cube; // GL_TEXTURE_BINDING_CUBE_MAP
|
||||
GLuint sampler; // GL_SAMPLER_BINDING
|
||||
} texture_cube_unit;
|
||||
|
||||
struct {
|
||||
GLuint texture_buffer; // GL_TEXTURE_BINDING_BUFFER
|
||||
} lighting_lut;
|
||||
|
|
Reference in New Issue