Merge pull request #3700 from wwylele/texcache-watcher
gl_rasterizer_cache: cache texture cube
This commit is contained in:
commit
0da3b75c9e
@ -45,7 +45,6 @@ RasterizerOpenGL::RasterizerOpenGL()
|
|||||||
// Create cubemap texture and sampler objects
|
// Create cubemap texture and sampler objects
|
||||||
texture_cube_sampler.Create();
|
texture_cube_sampler.Create();
|
||||||
state.texture_cube_unit.sampler = texture_cube_sampler.sampler.handle;
|
state.texture_cube_unit.sampler = texture_cube_sampler.sampler.handle;
|
||||||
texture_cube.Create();
|
|
||||||
|
|
||||||
// Generate VBO, VAO and UBO
|
// Generate VBO, VAO and UBO
|
||||||
vertex_array.Create();
|
vertex_array.Create();
|
||||||
@ -393,19 +392,18 @@ void RasterizerOpenGL::DrawTriangles() {
|
|||||||
switch (texture.config.type.Value()) {
|
switch (texture.config.type.Value()) {
|
||||||
case TextureType::TextureCube:
|
case TextureType::TextureCube:
|
||||||
using CubeFace = Pica::TexturingRegs::CubeFace;
|
using CubeFace = Pica::TexturingRegs::CubeFace;
|
||||||
if (res_cache.FillTextureCube(
|
TextureCubeConfig config;
|
||||||
texture_cube.handle, texture,
|
config.px = regs.texturing.GetCubePhysicalAddress(CubeFace::PositiveX);
|
||||||
regs.texturing.GetCubePhysicalAddress(CubeFace::PositiveX),
|
config.nx = regs.texturing.GetCubePhysicalAddress(CubeFace::NegativeX);
|
||||||
regs.texturing.GetCubePhysicalAddress(CubeFace::NegativeX),
|
config.py = regs.texturing.GetCubePhysicalAddress(CubeFace::PositiveY);
|
||||||
regs.texturing.GetCubePhysicalAddress(CubeFace::PositiveY),
|
config.ny = regs.texturing.GetCubePhysicalAddress(CubeFace::NegativeY);
|
||||||
regs.texturing.GetCubePhysicalAddress(CubeFace::NegativeY),
|
config.pz = regs.texturing.GetCubePhysicalAddress(CubeFace::PositiveZ);
|
||||||
regs.texturing.GetCubePhysicalAddress(CubeFace::PositiveZ),
|
config.nz = regs.texturing.GetCubePhysicalAddress(CubeFace::NegativeZ);
|
||||||
regs.texturing.GetCubePhysicalAddress(CubeFace::NegativeZ))) {
|
config.width = texture.config.width;
|
||||||
state.texture_cube_unit.texture_cube = texture_cube.handle;
|
config.format = texture.format;
|
||||||
} else {
|
state.texture_cube_unit.texture_cube =
|
||||||
// Can occur when texture addr is null or its memory is unmapped/invalid
|
res_cache.GetTextureCube(config).texture.handle;
|
||||||
state.texture_cube_unit.texture_cube = 0;
|
|
||||||
}
|
|
||||||
texture_cube_sampler.SyncWithConfig(texture.config);
|
texture_cube_sampler.SyncWithConfig(texture.config);
|
||||||
state.texture_units[texture_index].texture_2d = 0;
|
state.texture_units[texture_index].texture_2d = 0;
|
||||||
continue; // Texture unit 0 setup finished. Continue to next unit
|
continue; // Texture unit 0 setup finished. Continue to next unit
|
||||||
|
@ -252,8 +252,6 @@ private:
|
|||||||
GLint uniform_buffer_alignment;
|
GLint uniform_buffer_alignment;
|
||||||
size_t uniform_size_aligned_fs;
|
size_t uniform_size_aligned_fs;
|
||||||
|
|
||||||
// TODO (wwylele): consider caching texture cube in the rasterizer cache
|
|
||||||
OGLTexture texture_cube;
|
|
||||||
SamplerInfo texture_cube_sampler;
|
SamplerInfo texture_cube_sampler;
|
||||||
|
|
||||||
OGLBuffer lighting_lut_buffer;
|
OGLBuffer lighting_lut_buffer;
|
||||||
|
@ -28,7 +28,6 @@
|
|||||||
#include "video_core/pica_state.h"
|
#include "video_core/pica_state.h"
|
||||||
#include "video_core/renderer_opengl/gl_rasterizer_cache.h"
|
#include "video_core/renderer_opengl/gl_rasterizer_cache.h"
|
||||||
#include "video_core/renderer_opengl/gl_state.h"
|
#include "video_core/renderer_opengl/gl_state.h"
|
||||||
#include "video_core/texture/texture_decode.h"
|
|
||||||
#include "video_core/utils.h"
|
#include "video_core/utils.h"
|
||||||
#include "video_core/video_core.h"
|
#include "video_core/video_core.h"
|
||||||
|
|
||||||
@ -231,6 +230,32 @@ static void AllocateSurfaceTexture(GLuint texture, const FormatTuple& format_tup
|
|||||||
cur_state.Apply();
|
cur_state.Apply();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void AllocateTextureCube(GLuint texture, const FormatTuple& format_tuple, u32 width) {
|
||||||
|
OpenGLState cur_state = OpenGLState::GetCurState();
|
||||||
|
|
||||||
|
// Keep track of previous texture bindings
|
||||||
|
GLuint old_tex = cur_state.texture_cube_unit.texture_cube;
|
||||||
|
cur_state.texture_cube_unit.texture_cube = texture;
|
||||||
|
cur_state.Apply();
|
||||||
|
glActiveTexture(TextureUnits::TextureCube.Enum());
|
||||||
|
|
||||||
|
for (auto faces : {
|
||||||
|
GL_TEXTURE_CUBE_MAP_POSITIVE_X,
|
||||||
|
GL_TEXTURE_CUBE_MAP_POSITIVE_Y,
|
||||||
|
GL_TEXTURE_CUBE_MAP_POSITIVE_Z,
|
||||||
|
GL_TEXTURE_CUBE_MAP_NEGATIVE_X,
|
||||||
|
GL_TEXTURE_CUBE_MAP_NEGATIVE_Y,
|
||||||
|
GL_TEXTURE_CUBE_MAP_NEGATIVE_Z,
|
||||||
|
}) {
|
||||||
|
glTexImage2D(faces, 0, format_tuple.internal_format, width, width, 0, format_tuple.format,
|
||||||
|
format_tuple.type, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Restore previous texture bindings
|
||||||
|
cur_state.texture_cube_unit.texture_cube = old_tex;
|
||||||
|
cur_state.Apply();
|
||||||
|
}
|
||||||
|
|
||||||
static bool BlitTextures(GLuint src_tex, const MathUtil::Rectangle<u32>& src_rect, GLuint dst_tex,
|
static bool BlitTextures(GLuint src_tex, const MathUtil::Rectangle<u32>& src_rect, GLuint dst_tex,
|
||||||
const MathUtil::Rectangle<u32>& dst_rect, SurfaceType type,
|
const MathUtil::Rectangle<u32>& dst_rect, SurfaceType type,
|
||||||
GLuint read_fb_handle, GLuint draw_fb_handle) {
|
GLuint read_fb_handle, GLuint draw_fb_handle) {
|
||||||
@ -761,6 +786,8 @@ void CachedSurface::UploadGLTexture(const MathUtil::Rectangle<u32>& rect, GLuint
|
|||||||
BlitTextures(unscaled_tex.handle, {0, rect.GetHeight(), rect.GetWidth(), 0}, texture.handle,
|
BlitTextures(unscaled_tex.handle, {0, rect.GetHeight(), rect.GetWidth(), 0}, texture.handle,
|
||||||
scaled_rect, type, read_fb_handle, draw_fb_handle);
|
scaled_rect, type, read_fb_handle, draw_fb_handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
InvalidateAllWatcher();
|
||||||
}
|
}
|
||||||
|
|
||||||
MICROPROFILE_DEFINE(OpenGL_TextureDL, "OpenGL", "Texture Download", MP_RGB(128, 192, 64));
|
MICROPROFILE_DEFINE(OpenGL_TextureDL, "OpenGL", "Texture Download", MP_RGB(128, 192, 64));
|
||||||
@ -1193,14 +1220,13 @@ SurfaceRect_Tuple RasterizerCacheOpenGL::GetSurfaceSubRect(const SurfaceParams&
|
|||||||
}
|
}
|
||||||
|
|
||||||
Surface RasterizerCacheOpenGL::GetTextureSurface(
|
Surface RasterizerCacheOpenGL::GetTextureSurface(
|
||||||
const Pica::TexturingRegs::FullTextureConfig& config, PAddr addr_override) {
|
const Pica::TexturingRegs::FullTextureConfig& config) {
|
||||||
Pica::Texture::TextureInfo info =
|
Pica::Texture::TextureInfo info =
|
||||||
Pica::Texture::TextureInfo::FromPicaRegister(config.config, config.format);
|
Pica::Texture::TextureInfo::FromPicaRegister(config.config, config.format);
|
||||||
|
return GetTextureSurface(info);
|
||||||
|
}
|
||||||
|
|
||||||
if (addr_override != 0) {
|
Surface RasterizerCacheOpenGL::GetTextureSurface(const Pica::Texture::TextureInfo& info) {
|
||||||
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;
|
||||||
@ -1228,80 +1254,94 @@ Surface RasterizerCacheOpenGL::GetTextureSurface(
|
|||||||
return GetSurface(params, ScaleMatch::Ignore, true);
|
return GetSurface(params, ScaleMatch::Ignore, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RasterizerCacheOpenGL::FillTextureCube(GLuint dest_handle,
|
const CachedTextureCube& RasterizerCacheOpenGL::GetTextureCube(const TextureCubeConfig& config) {
|
||||||
const Pica::TexturingRegs::FullTextureConfig& config,
|
auto& cube = texture_cube_cache[config];
|
||||||
PAddr px, PAddr nx, PAddr py, PAddr ny, PAddr pz,
|
|
||||||
PAddr nz) {
|
struct Face {
|
||||||
ASSERT(config.config.width == config.config.height);
|
Face(std::shared_ptr<SurfaceWatcher>& watcher, PAddr address, GLenum gl_face)
|
||||||
struct FaceTuple {
|
: watcher(watcher), address(address), gl_face(gl_face) {}
|
||||||
|
std::shared_ptr<SurfaceWatcher>& watcher;
|
||||||
PAddr address;
|
PAddr address;
|
||||||
GLenum gl_face;
|
GLenum gl_face;
|
||||||
Surface surface;
|
|
||||||
};
|
};
|
||||||
std::array<FaceTuple, 6> faces{{
|
|
||||||
{px, GL_TEXTURE_CUBE_MAP_POSITIVE_X},
|
const std::array<Face, 6> faces{{
|
||||||
{nx, GL_TEXTURE_CUBE_MAP_NEGATIVE_X},
|
{cube.px, config.px, GL_TEXTURE_CUBE_MAP_POSITIVE_X},
|
||||||
{py, GL_TEXTURE_CUBE_MAP_POSITIVE_Y},
|
{cube.nx, config.nx, GL_TEXTURE_CUBE_MAP_NEGATIVE_X},
|
||||||
{ny, GL_TEXTURE_CUBE_MAP_NEGATIVE_Y},
|
{cube.py, config.py, GL_TEXTURE_CUBE_MAP_POSITIVE_Y},
|
||||||
{pz, GL_TEXTURE_CUBE_MAP_POSITIVE_Z},
|
{cube.ny, config.ny, GL_TEXTURE_CUBE_MAP_NEGATIVE_Y},
|
||||||
{nz, GL_TEXTURE_CUBE_MAP_NEGATIVE_Z},
|
{cube.pz, config.pz, GL_TEXTURE_CUBE_MAP_POSITIVE_Z},
|
||||||
|
{cube.nz, config.nz, GL_TEXTURE_CUBE_MAP_NEGATIVE_Z},
|
||||||
}};
|
}};
|
||||||
|
|
||||||
u16 res_scale = 1;
|
for (const Face& face : faces) {
|
||||||
for (auto& face : faces) {
|
if (!face.watcher || !face.watcher->Get()) {
|
||||||
face.surface = GetTextureSurface(config, face.address);
|
Pica::Texture::TextureInfo info;
|
||||||
if (face.surface == nullptr)
|
info.physical_address = face.address;
|
||||||
return false;
|
info.height = info.width = config.width;
|
||||||
res_scale = std::max(res_scale, face.surface->res_scale);
|
info.format = config.format;
|
||||||
|
info.SetDefaultStride();
|
||||||
|
auto surface = GetTextureSurface(info);
|
||||||
|
if (surface) {
|
||||||
|
face.watcher = surface->CreateWatcher();
|
||||||
|
} else {
|
||||||
|
// Can occur when texture address is invalid. We mark the watcher with nullptr in
|
||||||
|
// this case and the content of the face wouldn't get updated. These are usually
|
||||||
|
// leftover setup in the texture unit and games are not supposed to draw using them.
|
||||||
|
face.watcher = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 scaled_size = res_scale * config.config.width;
|
if (cube.texture.handle == 0) {
|
||||||
|
for (const Face& face : faces) {
|
||||||
|
if (face.watcher) {
|
||||||
|
auto surface = face.watcher->Get();
|
||||||
|
cube.res_scale = std::max(cube.res_scale, surface->res_scale);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cube.texture.Create();
|
||||||
|
AllocateTextureCube(
|
||||||
|
cube.texture.handle,
|
||||||
|
GetFormatTuple(CachedSurface::PixelFormatFromTextureFormat(config.format)),
|
||||||
|
cube.res_scale * config.width);
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 scaled_size = cube.res_scale * config.width;
|
||||||
|
|
||||||
OpenGLState state = OpenGLState::GetCurState();
|
OpenGLState state = OpenGLState::GetCurState();
|
||||||
|
|
||||||
OpenGLState prev_state = state;
|
OpenGLState prev_state = state;
|
||||||
SCOPE_EXIT({ prev_state.Apply(); });
|
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.read_framebuffer = read_framebuffer.handle;
|
||||||
state.draw.draw_framebuffer = draw_framebuffer.handle;
|
state.draw.draw_framebuffer = draw_framebuffer.handle;
|
||||||
state.ResetTexture(dest_handle);
|
state.ResetTexture(cube.texture.handle);
|
||||||
|
|
||||||
for (auto& face : faces) {
|
for (const Face& face : faces) {
|
||||||
state.ResetTexture(face.surface->texture.handle);
|
if (face.watcher && !face.watcher->IsValid()) {
|
||||||
|
auto surface = face.watcher->Get();
|
||||||
|
state.ResetTexture(surface->texture.handle);
|
||||||
state.Apply();
|
state.Apply();
|
||||||
glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
|
glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
|
||||||
face.surface->texture.handle, 0);
|
surface->texture.handle, 0);
|
||||||
glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0,
|
glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D,
|
||||||
0);
|
0, 0);
|
||||||
|
|
||||||
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, face.gl_face, dest_handle,
|
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, face.gl_face,
|
||||||
0);
|
cube.texture.handle, 0);
|
||||||
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0,
|
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D,
|
||||||
0);
|
0, 0);
|
||||||
|
|
||||||
auto src_rect = face.surface->GetScaledRect();
|
auto src_rect = surface->GetScaledRect();
|
||||||
glBlitFramebuffer(src_rect.left, src_rect.bottom, src_rect.right, src_rect.top, 0, 0,
|
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);
|
scaled_size, scaled_size, GL_COLOR_BUFFER_BIT, GL_LINEAR);
|
||||||
|
face.watcher->Validate();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return cube;
|
||||||
}
|
}
|
||||||
|
|
||||||
SurfaceSurfaceRect_Tuple RasterizerCacheOpenGL::GetFramebufferSurfaces(
|
SurfaceSurfaceRect_Tuple RasterizerCacheOpenGL::GetFramebufferSurfaces(
|
||||||
@ -1316,6 +1356,7 @@ SurfaceSurfaceRect_Tuple RasterizerCacheOpenGL::GetFramebufferSurfaces(
|
|||||||
FlushAll();
|
FlushAll();
|
||||||
while (!surface_cache.empty())
|
while (!surface_cache.empty())
|
||||||
UnregisterSurface(*surface_cache.begin()->second.begin());
|
UnregisterSurface(*surface_cache.begin()->second.begin());
|
||||||
|
texture_cube_cache.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
MathUtil::Rectangle<u32> viewport_clamped{
|
MathUtil::Rectangle<u32> viewport_clamped{
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <array>
|
#include <array>
|
||||||
|
#include <list>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <set>
|
#include <set>
|
||||||
#include <tuple>
|
#include <tuple>
|
||||||
@ -17,6 +18,8 @@
|
|||||||
#ifdef __GNUC__
|
#ifdef __GNUC__
|
||||||
#pragma GCC diagnostic pop
|
#pragma GCC diagnostic pop
|
||||||
#endif
|
#endif
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <boost/functional/hash.hpp>
|
||||||
#include <glad/glad.h>
|
#include <glad/glad.h>
|
||||||
#include "common/assert.h"
|
#include "common/assert.h"
|
||||||
#include "common/common_funcs.h"
|
#include "common/common_funcs.h"
|
||||||
@ -26,6 +29,7 @@
|
|||||||
#include "video_core/regs_framebuffer.h"
|
#include "video_core/regs_framebuffer.h"
|
||||||
#include "video_core/regs_texturing.h"
|
#include "video_core/regs_texturing.h"
|
||||||
#include "video_core/renderer_opengl/gl_resource_manager.h"
|
#include "video_core/renderer_opengl/gl_resource_manager.h"
|
||||||
|
#include "video_core/texture/texture_decode.h"
|
||||||
|
|
||||||
struct CachedSurface;
|
struct CachedSurface;
|
||||||
using Surface = std::shared_ptr<CachedSurface>;
|
using Surface = std::shared_ptr<CachedSurface>;
|
||||||
@ -253,7 +257,41 @@ struct SurfaceParams {
|
|||||||
SurfaceType type = SurfaceType::Invalid;
|
SurfaceType type = SurfaceType::Invalid;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct CachedSurface : SurfaceParams {
|
/**
|
||||||
|
* A watcher that notifies whether a cached surface has been changed. This is useful for caching
|
||||||
|
* surface collection objects, including texture cube and mipmap.
|
||||||
|
*/
|
||||||
|
struct SurfaceWatcher {
|
||||||
|
public:
|
||||||
|
explicit SurfaceWatcher(std::weak_ptr<CachedSurface>&& surface) : surface(std::move(surface)) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks whether the surface has been changed.
|
||||||
|
* @return false if the surface content has been changed since last Validate() call or has been
|
||||||
|
* destroyed; otherwise true
|
||||||
|
*/
|
||||||
|
bool IsValid() const {
|
||||||
|
return !surface.expired() && valid;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Marks that the content of the referencing surface has been updated to the watcher user.
|
||||||
|
void Validate() {
|
||||||
|
ASSERT(!surface.expired());
|
||||||
|
valid = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets the referencing surface. Returns null if the surface has been destroyed
|
||||||
|
Surface Get() const {
|
||||||
|
return surface.lock();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
friend struct CachedSurface;
|
||||||
|
std::weak_ptr<CachedSurface> surface;
|
||||||
|
bool valid = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct CachedSurface : SurfaceParams, std::enable_shared_from_this<CachedSurface> {
|
||||||
bool CanFill(const SurfaceParams& dest_surface, SurfaceInterval fill_interval) const;
|
bool CanFill(const SurfaceParams& dest_surface, SurfaceInterval fill_interval) const;
|
||||||
bool CanCopy(const SurfaceParams& dest_surface, SurfaceInterval copy_interval) const;
|
bool CanCopy(const SurfaceParams& dest_surface, SurfaceInterval copy_interval) const;
|
||||||
|
|
||||||
@ -294,6 +332,72 @@ struct CachedSurface : SurfaceParams {
|
|||||||
GLuint draw_fb_handle);
|
GLuint draw_fb_handle);
|
||||||
void DownloadGLTexture(const MathUtil::Rectangle<u32>& rect, GLuint read_fb_handle,
|
void DownloadGLTexture(const MathUtil::Rectangle<u32>& rect, GLuint read_fb_handle,
|
||||||
GLuint draw_fb_handle);
|
GLuint draw_fb_handle);
|
||||||
|
|
||||||
|
std::shared_ptr<SurfaceWatcher> CreateWatcher() {
|
||||||
|
auto watcher = std::make_shared<SurfaceWatcher>(weak_from_this());
|
||||||
|
watchers.push_front(watcher);
|
||||||
|
return watcher;
|
||||||
|
}
|
||||||
|
|
||||||
|
void InvalidateAllWatcher() {
|
||||||
|
for (const auto& watcher : watchers) {
|
||||||
|
if (auto locked = watcher.lock()) {
|
||||||
|
locked->valid = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::list<std::weak_ptr<SurfaceWatcher>> watchers;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct TextureCubeConfig {
|
||||||
|
PAddr px;
|
||||||
|
PAddr nx;
|
||||||
|
PAddr py;
|
||||||
|
PAddr ny;
|
||||||
|
PAddr pz;
|
||||||
|
PAddr nz;
|
||||||
|
u32 width;
|
||||||
|
Pica::TexturingRegs::TextureFormat format;
|
||||||
|
|
||||||
|
bool operator==(const TextureCubeConfig& rhs) const {
|
||||||
|
return std::tie(px, nx, py, ny, pz, nz, width, format) ==
|
||||||
|
std::tie(rhs.px, rhs.nx, rhs.py, rhs.ny, rhs.pz, rhs.nz, rhs.width, rhs.format);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator!=(const TextureCubeConfig& rhs) const {
|
||||||
|
return !(*this == rhs);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
namespace std {
|
||||||
|
template <>
|
||||||
|
struct hash<TextureCubeConfig> {
|
||||||
|
size_t operator()(const TextureCubeConfig& config) const {
|
||||||
|
std::size_t hash = 0;
|
||||||
|
boost::hash_combine(hash, config.px);
|
||||||
|
boost::hash_combine(hash, config.nx);
|
||||||
|
boost::hash_combine(hash, config.py);
|
||||||
|
boost::hash_combine(hash, config.ny);
|
||||||
|
boost::hash_combine(hash, config.pz);
|
||||||
|
boost::hash_combine(hash, config.nz);
|
||||||
|
boost::hash_combine(hash, config.width);
|
||||||
|
boost::hash_combine(hash, static_cast<u32>(config.format));
|
||||||
|
return hash;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
} // namespace std
|
||||||
|
|
||||||
|
struct CachedTextureCube {
|
||||||
|
OGLTexture texture;
|
||||||
|
u16 res_scale = 1;
|
||||||
|
std::shared_ptr<SurfaceWatcher> px;
|
||||||
|
std::shared_ptr<SurfaceWatcher> nx;
|
||||||
|
std::shared_ptr<SurfaceWatcher> py;
|
||||||
|
std::shared_ptr<SurfaceWatcher> ny;
|
||||||
|
std::shared_ptr<SurfaceWatcher> pz;
|
||||||
|
std::shared_ptr<SurfaceWatcher> nz;
|
||||||
};
|
};
|
||||||
|
|
||||||
class RasterizerCacheOpenGL : NonCopyable {
|
class RasterizerCacheOpenGL : NonCopyable {
|
||||||
@ -322,12 +426,11 @@ 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);
|
Surface GetTextureSurface(const Pica::Texture::TextureInfo& info);
|
||||||
|
|
||||||
/// Copy surfaces to a cubemap texture based on the texture configuration
|
/// Get a texture cube based on the texture configuration
|
||||||
bool FillTextureCube(GLuint dest_handle, const Pica::TexturingRegs::FullTextureConfig& config,
|
const CachedTextureCube& GetTextureCube(const TextureCubeConfig& 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,
|
||||||
@ -380,4 +483,6 @@ private:
|
|||||||
OGLProgram d24s8_abgr_shader;
|
OGLProgram d24s8_abgr_shader;
|
||||||
GLint d24s8_abgr_tbo_size_u_id;
|
GLint d24s8_abgr_tbo_size_u_id;
|
||||||
GLint d24s8_abgr_viewport_u_id;
|
GLint d24s8_abgr_viewport_u_id;
|
||||||
|
|
||||||
|
std::unordered_map<TextureCubeConfig, CachedTextureCube> texture_cube_cache;
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user