|
|
@ -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) {
|
|
|
|
|
|
|
|
info.physical_address = addr_override;
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Surface RasterizerCacheOpenGL::GetTextureSurface(const Pica::Texture::TextureInfo& info) {
|
|
|
|
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{
|
|
|
|