rasterizer_cache: Refactor texture cube interface
* Reuse our Surface class instead of having a separate one, to avoid reimplementing stuff in the backend
This commit is contained in:
@ -571,64 +571,62 @@ auto RasterizerCache<T>::GetTextureSurface(const Pica::Texture::TextureInfo& inf
|
|||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
auto RasterizerCache<T>::GetTextureCube(const TextureCubeConfig& config) -> const Surface& {
|
auto RasterizerCache<T>::GetTextureCube(const TextureCubeConfig& config) -> const Surface& {
|
||||||
auto& cube = texture_cube_cache[config];
|
auto [it, new_surface] = texture_cube_cache.try_emplace(config);
|
||||||
cube->is_texture_cube = true;
|
if (new_surface) {
|
||||||
|
SurfaceParams cube_params = {
|
||||||
|
.addr = config.px,
|
||||||
|
.width = config.width,
|
||||||
|
.height = config.width,
|
||||||
|
.stride = config.width,
|
||||||
|
.texture_type = TextureType::CubeMap,
|
||||||
|
.pixel_format = PixelFormatFromTextureFormat(config.format),
|
||||||
|
.type = SurfaceType::Texture
|
||||||
|
};
|
||||||
|
|
||||||
struct Face {
|
it->second = CreateSurface(cube_params);
|
||||||
Face(std::shared_ptr<Watcher>& watcher, PAddr address)
|
}
|
||||||
: watcher(watcher), address(address) {}
|
|
||||||
std::shared_ptr<Watcher>& watcher;
|
|
||||||
PAddr address;
|
|
||||||
};
|
|
||||||
|
|
||||||
const std::array<Face, 6> faces{{
|
Surface& cube = it->second;
|
||||||
{cube->level_watchers[0], config.px},
|
|
||||||
{cube->level_watchers[1], config.nx},
|
// Update surface watchers
|
||||||
{cube->level_watchers[2], config.py},
|
auto& watchers = cube->level_watchers;
|
||||||
{cube->level_watchers[3], config.ny},
|
const std::array addresses = {config.px, config.nx, config.py,
|
||||||
{cube->level_watchers[4], config.pz},
|
config.ny, config.pz, config.nz};
|
||||||
{cube->level_watchers[5], config.nz},
|
|
||||||
}};
|
for (std::size_t i = 0; i < addresses.size(); i++) {
|
||||||
|
auto& watcher = watchers[i];
|
||||||
|
if (!watcher || !watcher->Get()) {
|
||||||
|
Pica::Texture::TextureInfo info = {
|
||||||
|
.physical_address = addresses[i],
|
||||||
|
.width = config.width,
|
||||||
|
.height = config.width,
|
||||||
|
.format = config.format,
|
||||||
|
};
|
||||||
|
|
||||||
for (const Face& face : faces) {
|
|
||||||
if (!face.watcher || !face.watcher->Get()) {
|
|
||||||
Pica::Texture::TextureInfo info;
|
|
||||||
info.physical_address = face.address;
|
|
||||||
info.height = info.width = config.width;
|
|
||||||
info.format = config.format;
|
|
||||||
info.SetDefaultStride();
|
info.SetDefaultStride();
|
||||||
auto surface = GetTextureSurface(info);
|
auto surface = GetTextureSurface(info);
|
||||||
if (surface) {
|
if (surface) {
|
||||||
face.watcher = surface->CreateWatcher();
|
watcher = surface->CreateWatcher();
|
||||||
} else {
|
} 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
|
* Can occur when texture address is invalid. We mark the watcher with nullptr
|
||||||
// usually leftover setup in the texture unit and games are not supposed to draw
|
* in this case and the content of the face wouldn't get updated. These are
|
||||||
// using them.
|
* usually leftover setup in the texture unit and games are not supposed to draw
|
||||||
face.watcher = nullptr;
|
* using them.
|
||||||
|
*/
|
||||||
|
watcher = nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cube->texture.handle == 0) {
|
// Validate the face surfaces
|
||||||
for (const Face& face : faces) {
|
const u32 scaled_size = cube->GetScaledWidth();
|
||||||
if (face.watcher) {
|
for (std::size_t i = 0; i < addresses.size(); i++) {
|
||||||
auto surface = face.watcher->Get();
|
const auto& watcher = watchers[i];
|
||||||
cube->res_scale = std::max(cube->res_scale, surface->res_scale);
|
if (watcher && !watcher->IsValid()) {
|
||||||
}
|
auto face = watcher->Get();
|
||||||
}
|
if (!face->invalid_regions.empty()) {
|
||||||
|
ValidateSurface(face, face->addr, face->size);
|
||||||
const u32 width = cube->res_scale * config.width;
|
|
||||||
cube->texture = runtime.AllocateCubeMap(width, PixelFormatFromTextureFormat(config.format));
|
|
||||||
}
|
|
||||||
|
|
||||||
const u32 scaled_size = cube->res_scale * config.width;
|
|
||||||
for (std::size_t i = 0; i < faces.size(); i++) {
|
|
||||||
const Face& face = faces[i];
|
|
||||||
if (face.watcher && !face.watcher->IsValid()) {
|
|
||||||
auto surface = face.watcher->Get();
|
|
||||||
if (!surface->invalid_regions.empty()) {
|
|
||||||
ValidateSurface(surface, surface->addr, surface->size);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const TextureBlit texture_blit = {
|
const TextureBlit texture_blit = {
|
||||||
@ -636,12 +634,12 @@ auto RasterizerCache<T>::GetTextureCube(const TextureCubeConfig& config) -> cons
|
|||||||
.dst_level = 0,
|
.dst_level = 0,
|
||||||
.src_layer = 0,
|
.src_layer = 0,
|
||||||
.dst_layer = static_cast<u32>(i),
|
.dst_layer = static_cast<u32>(i),
|
||||||
.src_rect = surface->GetScaledRect(),
|
.src_rect = face->GetScaledRect(),
|
||||||
.dst_rect = Rect2D{0, scaled_size, scaled_size, 0}
|
.dst_rect = Rect2D{0, scaled_size, scaled_size, 0}
|
||||||
};
|
};
|
||||||
|
|
||||||
runtime.BlitTextures(*surface, *cube, texture_blit);
|
runtime.BlitTextures(*face, *cube, texture_blit);
|
||||||
face.watcher->Validate();
|
watcher->Validate();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1233,10 +1231,6 @@ auto RasterizerCache<T>::CreateSurface(SurfaceParams& params) -> Surface {
|
|||||||
Surface surface = std::make_shared<typename T::Surface>(params, runtime);
|
Surface surface = std::make_shared<typename T::Surface>(params, runtime);
|
||||||
surface->invalid_regions.insert(surface->GetInterval());
|
surface->invalid_regions.insert(surface->GetInterval());
|
||||||
|
|
||||||
// Allocate surface texture
|
|
||||||
surface->texture =
|
|
||||||
runtime.Allocate2D(surface->GetScaledWidth(), surface->GetScaledHeight(), params.pixel_format);
|
|
||||||
|
|
||||||
return surface;
|
return surface;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
#include "common/alignment.h"
|
#include "common/alignment.h"
|
||||||
#include "common/assert.h"
|
#include "common/assert.h"
|
||||||
#include "video_core/rasterizer_cache/surface_params.h"
|
#include "video_core/rasterizer_cache/surface_params.h"
|
||||||
|
#include "video_core/rasterizer_cache/utils.h"
|
||||||
|
|
||||||
namespace VideoCore {
|
namespace VideoCore {
|
||||||
|
|
||||||
@ -80,7 +81,6 @@ public:
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
bool registered = false;
|
bool registered = false;
|
||||||
bool is_texture_cube = false;
|
|
||||||
SurfaceRegions invalid_regions;
|
SurfaceRegions invalid_regions;
|
||||||
std::array<std::shared_ptr<Watcher>, 7> level_watchers;
|
std::array<std::shared_ptr<Watcher>, 7> level_watchers;
|
||||||
u32 max_level = 0;
|
u32 max_level = 0;
|
||||||
|
@ -15,6 +15,11 @@ namespace VideoCore {
|
|||||||
|
|
||||||
using SurfaceInterval = boost::icl::right_open_interval<PAddr>;
|
using SurfaceInterval = boost::icl::right_open_interval<PAddr>;
|
||||||
|
|
||||||
|
enum class TextureType {
|
||||||
|
Texture2D = 0,
|
||||||
|
CubeMap = 1
|
||||||
|
};
|
||||||
|
|
||||||
class SurfaceParams {
|
class SurfaceParams {
|
||||||
public:
|
public:
|
||||||
/// Surface match traits
|
/// Surface match traits
|
||||||
@ -89,6 +94,7 @@ public:
|
|||||||
u16 res_scale = 1;
|
u16 res_scale = 1;
|
||||||
|
|
||||||
bool is_tiled = false;
|
bool is_tiled = false;
|
||||||
|
TextureType texture_type = TextureType::Texture2D;
|
||||||
PixelFormat pixel_format = PixelFormat::Invalid;
|
PixelFormat pixel_format = PixelFormat::Invalid;
|
||||||
SurfaceType type = SurfaceType::Invalid;
|
SurfaceType type = SurfaceType::Invalid;
|
||||||
};
|
};
|
||||||
|
@ -3,7 +3,6 @@
|
|||||||
// Refer to the license.txt file included.
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <functional>
|
|
||||||
#include <span>
|
#include <span>
|
||||||
#include "common/hash.h"
|
#include "common/hash.h"
|
||||||
#include "video_core/rasterizer_cache/pixel_format.h"
|
#include "video_core/rasterizer_cache/pixel_format.h"
|
||||||
@ -15,6 +14,8 @@ struct HostTextureTag {
|
|||||||
PixelFormat format{};
|
PixelFormat format{};
|
||||||
u32 width = 0;
|
u32 width = 0;
|
||||||
u32 height = 0;
|
u32 height = 0;
|
||||||
|
u32 levels = 1;
|
||||||
|
u32 layers = 1;
|
||||||
|
|
||||||
auto operator<=>(const HostTextureTag&) const noexcept = default;
|
auto operator<=>(const HostTextureTag&) const noexcept = default;
|
||||||
|
|
||||||
@ -58,7 +59,7 @@ void SwizzleTexture(const SurfaceParams& params, u32 start_offset,
|
|||||||
void UnswizzleTexture(const SurfaceParams& params, u32 start_offset,
|
void UnswizzleTexture(const SurfaceParams& params, u32 start_offset,
|
||||||
std::span<std::byte> source_tiled, std::span<std::byte> dest_linear);
|
std::span<std::byte> source_tiled, std::span<std::byte> dest_linear);
|
||||||
|
|
||||||
} // namespace OpenGL
|
} // namespace VideoCore
|
||||||
|
|
||||||
namespace std {
|
namespace std {
|
||||||
template <>
|
template <>
|
||||||
|
@ -727,8 +727,8 @@ bool RasterizerOpenGL::Draw(bool accelerate, bool is_indexed) {
|
|||||||
// Making a copy to sample from eliminates this issue and seems to be fairly cheap.
|
// Making a copy to sample from eliminates this issue and seems to be fairly cheap.
|
||||||
OGLTexture temp_tex;
|
OGLTexture temp_tex;
|
||||||
if (need_duplicate_texture) {
|
if (need_duplicate_texture) {
|
||||||
temp_tex = runtime.Allocate2D(color_surface->GetScaledWidth(), color_surface->GetScaledHeight(),
|
temp_tex = runtime.Allocate(color_surface->GetScaledWidth(), color_surface->GetScaledHeight(),
|
||||||
color_surface->pixel_format);
|
color_surface->pixel_format, color_surface->texture_type);
|
||||||
|
|
||||||
temp_tex.CopyFrom(color_surface->texture, GL_TEXTURE_2D, color_surface->max_level + 1,
|
temp_tex.CopyFrom(color_surface->texture, GL_TEXTURE_2D, color_surface->max_level + 1,
|
||||||
color_surface->GetScaledWidth(), color_surface->GetScaledHeight());
|
color_surface->GetScaledWidth(), color_surface->GetScaledHeight());
|
||||||
|
@ -52,10 +52,8 @@ void OGLTexture::Release() {
|
|||||||
handle = 0;
|
handle = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void OGLTexture::Allocate(GLenum _target, GLsizei levels, GLenum internalformat, GLsizei width,
|
void OGLTexture::Allocate(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width,
|
||||||
GLsizei height, GLsizei depth) {
|
GLsizei height, GLsizei depth) {
|
||||||
target = _target;
|
|
||||||
|
|
||||||
GLuint old_tex = OpenGLState::GetCurState().texture_units[0].texture_2d;
|
GLuint old_tex = OpenGLState::GetCurState().texture_units[0].texture_2d;
|
||||||
glActiveTexture(GL_TEXTURE0);
|
glActiveTexture(GL_TEXTURE0);
|
||||||
glBindTexture(target, handle);
|
glBindTexture(target, handle);
|
||||||
|
@ -65,7 +65,6 @@ public:
|
|||||||
GLsizei height);
|
GLsizei height);
|
||||||
|
|
||||||
GLuint handle = 0;
|
GLuint handle = 0;
|
||||||
GLenum target = GL_TEXTURE_2D;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class OGLSampler : private NonCopyable {
|
class OGLSampler : private NonCopyable {
|
||||||
|
@ -124,33 +124,45 @@ const FormatTuple& TextureRuntime::GetFormatTuple(VideoCore::PixelFormat pixel_f
|
|||||||
return DEFAULT_TUPLE;
|
return DEFAULT_TUPLE;
|
||||||
}
|
}
|
||||||
|
|
||||||
OGLTexture TextureRuntime::Allocate2D(u32 width, u32 height, VideoCore::PixelFormat format) {
|
OGLTexture TextureRuntime::Allocate(u32 width, u32 height, VideoCore::PixelFormat format,
|
||||||
const auto& tuple = GetFormatTuple(format);
|
VideoCore::TextureType type) {
|
||||||
auto recycled_tex = texture_recycler.find({format, width, height});
|
|
||||||
if (recycled_tex != texture_recycler.end()) {
|
const u32 layers = type == VideoCore::TextureType::CubeMap ? 6 : 1;
|
||||||
OGLTexture texture = std::move(recycled_tex->second);
|
const GLenum target =
|
||||||
texture_recycler.erase(recycled_tex);
|
type == VideoCore::TextureType::CubeMap ? GL_TEXTURE_CUBE_MAP : GL_TEXTURE_2D;
|
||||||
|
const VideoCore::HostTextureTag key = {
|
||||||
|
.format = format,
|
||||||
|
.width = width,
|
||||||
|
.height = height,
|
||||||
|
.layers = layers
|
||||||
|
};
|
||||||
|
|
||||||
|
// Attempt to recycle an unused texture
|
||||||
|
if (auto it = texture_recycler.find(key); it != texture_recycler.end()) {
|
||||||
|
OGLTexture texture = std::move(it->second);
|
||||||
|
texture_recycler.erase(it);
|
||||||
return texture;
|
return texture;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Allocate the 2D texture
|
|
||||||
OGLTexture texture{};
|
|
||||||
texture.Create();
|
|
||||||
texture.Allocate(GL_TEXTURE_2D, std::bit_width(std::max(width, height)),
|
|
||||||
tuple.internal_format, width, height);
|
|
||||||
|
|
||||||
return texture;
|
|
||||||
}
|
|
||||||
|
|
||||||
OGLTexture TextureRuntime::AllocateCubeMap(u32 width, VideoCore::PixelFormat format) {
|
|
||||||
const auto& tuple = GetFormatTuple(format);
|
const auto& tuple = GetFormatTuple(format);
|
||||||
|
const OpenGLState& state = OpenGLState::GetCurState();
|
||||||
|
GLuint old_tex = state.texture_units[0].texture_2d;
|
||||||
|
|
||||||
// Allocate the cube texture
|
// Allocate new texture
|
||||||
OGLTexture texture{};
|
OGLTexture texture{};
|
||||||
texture.Create();
|
texture.Create();
|
||||||
texture.Allocate(GL_TEXTURE_CUBE_MAP, std::bit_width(width),
|
|
||||||
tuple.internal_format, width, width);
|
|
||||||
|
|
||||||
|
glActiveTexture(GL_TEXTURE0);
|
||||||
|
glBindTexture(target, texture.handle);
|
||||||
|
|
||||||
|
glTexStorage2D(target, std::bit_width(std::max(width, height)),
|
||||||
|
tuple.internal_format, width, height);
|
||||||
|
|
||||||
|
glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||||
|
glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||||
|
glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||||
|
|
||||||
|
glBindTexture(target, old_tex);
|
||||||
return texture;
|
return texture;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -229,11 +241,11 @@ bool TextureRuntime::BlitTextures(Surface& source, Surface& dest, const VideoCor
|
|||||||
state.draw.draw_framebuffer = draw_fbo.handle;
|
state.draw.draw_framebuffer = draw_fbo.handle;
|
||||||
state.Apply();
|
state.Apply();
|
||||||
|
|
||||||
const GLenum src_textarget = source.is_texture_cube ?
|
const GLenum src_textarget = source.texture_type == VideoCore::TextureType::CubeMap ?
|
||||||
GL_TEXTURE_CUBE_MAP_POSITIVE_X + blit.src_layer : GL_TEXTURE_2D;
|
GL_TEXTURE_CUBE_MAP_POSITIVE_X + blit.src_layer : GL_TEXTURE_2D;
|
||||||
BindFramebuffer(GL_READ_FRAMEBUFFER, blit.src_level, src_textarget, source.type, source.texture);
|
BindFramebuffer(GL_READ_FRAMEBUFFER, blit.src_level, src_textarget, source.type, source.texture);
|
||||||
|
|
||||||
const GLenum dst_textarget = dest.is_texture_cube ?
|
const GLenum dst_textarget = dest.texture_type == VideoCore::TextureType::CubeMap ?
|
||||||
GL_TEXTURE_CUBE_MAP_POSITIVE_X + blit.dst_layer : GL_TEXTURE_2D;
|
GL_TEXTURE_CUBE_MAP_POSITIVE_X + blit.dst_layer : GL_TEXTURE_2D;
|
||||||
BindFramebuffer(GL_DRAW_FRAMEBUFFER, blit.dst_level, dst_textarget, dest.type, dest.texture);
|
BindFramebuffer(GL_DRAW_FRAMEBUFFER, blit.dst_level, dst_textarget, dest.type, dest.texture);
|
||||||
|
|
||||||
@ -287,7 +299,7 @@ void TextureRuntime::BindFramebuffer(GLenum target, GLint level, GLenum textarge
|
|||||||
|
|
||||||
Surface::Surface(VideoCore::SurfaceParams& params, TextureRuntime& runtime)
|
Surface::Surface(VideoCore::SurfaceParams& params, TextureRuntime& runtime)
|
||||||
: VideoCore::SurfaceBase<Surface>{params}, runtime{runtime}, driver{runtime.GetDriver()} {
|
: VideoCore::SurfaceBase<Surface>{params}, runtime{runtime}, driver{runtime.GetDriver()} {
|
||||||
|
texture = runtime.Allocate(GetScaledWidth(), GetScaledHeight(), params.pixel_format, texture_type);
|
||||||
}
|
}
|
||||||
|
|
||||||
MICROPROFILE_DEFINE(RasterizerCache_TextureUL, "RasterizerCache", "Texture Upload", MP_RGB(128, 192, 64));
|
MICROPROFILE_DEFINE(RasterizerCache_TextureUL, "RasterizerCache", "Texture Upload", MP_RGB(128, 192, 64));
|
||||||
@ -361,7 +373,8 @@ void Surface::ScaledDownload(const VideoCore::BufferTextureCopy& download) {
|
|||||||
const u32 rect_height = download.texture_rect.GetHeight();
|
const u32 rect_height = download.texture_rect.GetHeight();
|
||||||
|
|
||||||
// Allocate an unscaled texture that fits the download rectangle to use as a blit destination
|
// Allocate an unscaled texture that fits the download rectangle to use as a blit destination
|
||||||
OGLTexture unscaled_tex = runtime.Allocate2D(rect_width, rect_height, pixel_format);
|
OGLTexture unscaled_tex = runtime.Allocate(rect_width, rect_height, pixel_format,
|
||||||
|
VideoCore::TextureType::Texture2D);
|
||||||
runtime.BindFramebuffer(GL_DRAW_FRAMEBUFFER, 0, GL_TEXTURE_2D, type, unscaled_tex);
|
runtime.BindFramebuffer(GL_DRAW_FRAMEBUFFER, 0, GL_TEXTURE_2D, type, unscaled_tex);
|
||||||
runtime.BindFramebuffer(GL_READ_FRAMEBUFFER, download.texture_level, GL_TEXTURE_2D, type, texture);
|
runtime.BindFramebuffer(GL_READ_FRAMEBUFFER, download.texture_level, GL_TEXTURE_2D, type, texture);
|
||||||
|
|
||||||
@ -389,7 +402,8 @@ void Surface::ScaledUpload(const VideoCore::BufferTextureCopy& upload) {
|
|||||||
const u32 rect_width = upload.texture_rect.GetWidth();
|
const u32 rect_width = upload.texture_rect.GetWidth();
|
||||||
const u32 rect_height = upload.texture_rect.GetHeight();
|
const u32 rect_height = upload.texture_rect.GetHeight();
|
||||||
|
|
||||||
OGLTexture unscaled_tex = runtime.Allocate2D(rect_width, rect_height, pixel_format);
|
OGLTexture unscaled_tex = runtime.Allocate(rect_width, rect_height, pixel_format,
|
||||||
|
VideoCore::TextureType::Texture2D);
|
||||||
glActiveTexture(GL_TEXTURE0);
|
glActiveTexture(GL_TEXTURE0);
|
||||||
glBindTexture(GL_TEXTURE_2D, unscaled_tex.handle);
|
glBindTexture(GL_TEXTURE_2D, unscaled_tex.handle);
|
||||||
|
|
||||||
|
@ -70,11 +70,9 @@ public:
|
|||||||
/// Returns the OpenGL format tuple associated with the provided pixel format
|
/// Returns the OpenGL format tuple associated with the provided pixel format
|
||||||
const FormatTuple& GetFormatTuple(VideoCore::PixelFormat pixel_format);
|
const FormatTuple& GetFormatTuple(VideoCore::PixelFormat pixel_format);
|
||||||
|
|
||||||
/// Allocates a 2D OpenGL texture with the specified dimentions and format
|
/// Allocates an OpenGL texture with the specified dimentions and format
|
||||||
OGLTexture Allocate2D(u32 width, u32 height, VideoCore::PixelFormat format);
|
OGLTexture Allocate(u32 width, u32 height, VideoCore::PixelFormat format,
|
||||||
|
VideoCore::TextureType type);
|
||||||
/// Allocates an OpenGL cube map texture with the specified dimentions and format
|
|
||||||
OGLTexture AllocateCubeMap(u32 width, VideoCore::PixelFormat format);
|
|
||||||
|
|
||||||
/// Fills the rectangle of the texture with the clear value provided
|
/// Fills the rectangle of the texture with the clear value provided
|
||||||
bool ClearTexture(Surface& surface, const VideoCore::TextureClear& clear,
|
bool ClearTexture(Surface& surface, const VideoCore::TextureClear& clear,
|
||||||
|
Reference in New Issue
Block a user