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>
|
||||
auto RasterizerCache<T>::GetTextureCube(const TextureCubeConfig& config) -> const Surface& {
|
||||
auto& cube = texture_cube_cache[config];
|
||||
cube->is_texture_cube = true;
|
||||
auto [it, new_surface] = texture_cube_cache.try_emplace(config);
|
||||
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 {
|
||||
Face(std::shared_ptr<Watcher>& watcher, PAddr address)
|
||||
: watcher(watcher), address(address) {}
|
||||
std::shared_ptr<Watcher>& watcher;
|
||||
PAddr address;
|
||||
};
|
||||
it->second = CreateSurface(cube_params);
|
||||
}
|
||||
|
||||
const std::array<Face, 6> faces{{
|
||||
{cube->level_watchers[0], config.px},
|
||||
{cube->level_watchers[1], config.nx},
|
||||
{cube->level_watchers[2], config.py},
|
||||
{cube->level_watchers[3], config.ny},
|
||||
{cube->level_watchers[4], config.pz},
|
||||
{cube->level_watchers[5], config.nz},
|
||||
}};
|
||||
Surface& cube = it->second;
|
||||
|
||||
// Update surface watchers
|
||||
auto& watchers = cube->level_watchers;
|
||||
const std::array addresses = {config.px, config.nx, config.py,
|
||||
config.ny, config.pz, 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();
|
||||
auto surface = GetTextureSurface(info);
|
||||
if (surface) {
|
||||
face.watcher = surface->CreateWatcher();
|
||||
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;
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
watcher = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
// Validate the face surfaces
|
||||
const u32 scaled_size = cube->GetScaledWidth();
|
||||
for (std::size_t i = 0; i < addresses.size(); i++) {
|
||||
const auto& watcher = watchers[i];
|
||||
if (watcher && !watcher->IsValid()) {
|
||||
auto face = watcher->Get();
|
||||
if (!face->invalid_regions.empty()) {
|
||||
ValidateSurface(face, face->addr, face->size);
|
||||
}
|
||||
|
||||
const TextureBlit texture_blit = {
|
||||
@ -636,12 +634,12 @@ auto RasterizerCache<T>::GetTextureCube(const TextureCubeConfig& config) -> cons
|
||||
.dst_level = 0,
|
||||
.src_layer = 0,
|
||||
.dst_layer = static_cast<u32>(i),
|
||||
.src_rect = surface->GetScaledRect(),
|
||||
.src_rect = face->GetScaledRect(),
|
||||
.dst_rect = Rect2D{0, scaled_size, scaled_size, 0}
|
||||
};
|
||||
|
||||
runtime.BlitTextures(*surface, *cube, texture_blit);
|
||||
face.watcher->Validate();
|
||||
runtime.BlitTextures(*face, *cube, texture_blit);
|
||||
watcher->Validate();
|
||||
}
|
||||
}
|
||||
|
||||
@ -1233,10 +1231,6 @@ auto RasterizerCache<T>::CreateSurface(SurfaceParams& params) -> Surface {
|
||||
Surface surface = std::make_shared<typename T::Surface>(params, runtime);
|
||||
surface->invalid_regions.insert(surface->GetInterval());
|
||||
|
||||
// Allocate surface texture
|
||||
surface->texture =
|
||||
runtime.Allocate2D(surface->GetScaledWidth(), surface->GetScaledHeight(), params.pixel_format);
|
||||
|
||||
return surface;
|
||||
}
|
||||
|
||||
|
@ -7,6 +7,7 @@
|
||||
#include "common/alignment.h"
|
||||
#include "common/assert.h"
|
||||
#include "video_core/rasterizer_cache/surface_params.h"
|
||||
#include "video_core/rasterizer_cache/utils.h"
|
||||
|
||||
namespace VideoCore {
|
||||
|
||||
@ -80,7 +81,6 @@ public:
|
||||
|
||||
public:
|
||||
bool registered = false;
|
||||
bool is_texture_cube = false;
|
||||
SurfaceRegions invalid_regions;
|
||||
std::array<std::shared_ptr<Watcher>, 7> level_watchers;
|
||||
u32 max_level = 0;
|
||||
|
@ -15,6 +15,11 @@ namespace VideoCore {
|
||||
|
||||
using SurfaceInterval = boost::icl::right_open_interval<PAddr>;
|
||||
|
||||
enum class TextureType {
|
||||
Texture2D = 0,
|
||||
CubeMap = 1
|
||||
};
|
||||
|
||||
class SurfaceParams {
|
||||
public:
|
||||
/// Surface match traits
|
||||
@ -89,6 +94,7 @@ public:
|
||||
u16 res_scale = 1;
|
||||
|
||||
bool is_tiled = false;
|
||||
TextureType texture_type = TextureType::Texture2D;
|
||||
PixelFormat pixel_format = PixelFormat::Invalid;
|
||||
SurfaceType type = SurfaceType::Invalid;
|
||||
};
|
||||
|
@ -3,7 +3,6 @@
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
#include <functional>
|
||||
#include <span>
|
||||
#include "common/hash.h"
|
||||
#include "video_core/rasterizer_cache/pixel_format.h"
|
||||
@ -15,6 +14,8 @@ struct HostTextureTag {
|
||||
PixelFormat format{};
|
||||
u32 width = 0;
|
||||
u32 height = 0;
|
||||
u32 levels = 1;
|
||||
u32 layers = 1;
|
||||
|
||||
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,
|
||||
std::span<std::byte> source_tiled, std::span<std::byte> dest_linear);
|
||||
|
||||
} // namespace OpenGL
|
||||
} // namespace VideoCore
|
||||
|
||||
namespace std {
|
||||
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.
|
||||
OGLTexture temp_tex;
|
||||
if (need_duplicate_texture) {
|
||||
temp_tex = runtime.Allocate2D(color_surface->GetScaledWidth(), color_surface->GetScaledHeight(),
|
||||
color_surface->pixel_format);
|
||||
temp_tex = runtime.Allocate(color_surface->GetScaledWidth(), color_surface->GetScaledHeight(),
|
||||
color_surface->pixel_format, color_surface->texture_type);
|
||||
|
||||
temp_tex.CopyFrom(color_surface->texture, GL_TEXTURE_2D, color_surface->max_level + 1,
|
||||
color_surface->GetScaledWidth(), color_surface->GetScaledHeight());
|
||||
|
@ -52,10 +52,8 @@ void OGLTexture::Release() {
|
||||
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) {
|
||||
target = _target;
|
||||
|
||||
GLuint old_tex = OpenGLState::GetCurState().texture_units[0].texture_2d;
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
glBindTexture(target, handle);
|
||||
|
@ -65,7 +65,6 @@ public:
|
||||
GLsizei height);
|
||||
|
||||
GLuint handle = 0;
|
||||
GLenum target = GL_TEXTURE_2D;
|
||||
};
|
||||
|
||||
class OGLSampler : private NonCopyable {
|
||||
|
@ -124,33 +124,45 @@ const FormatTuple& TextureRuntime::GetFormatTuple(VideoCore::PixelFormat pixel_f
|
||||
return DEFAULT_TUPLE;
|
||||
}
|
||||
|
||||
OGLTexture TextureRuntime::Allocate2D(u32 width, u32 height, VideoCore::PixelFormat format) {
|
||||
const auto& tuple = GetFormatTuple(format);
|
||||
auto recycled_tex = texture_recycler.find({format, width, height});
|
||||
if (recycled_tex != texture_recycler.end()) {
|
||||
OGLTexture texture = std::move(recycled_tex->second);
|
||||
texture_recycler.erase(recycled_tex);
|
||||
OGLTexture TextureRuntime::Allocate(u32 width, u32 height, VideoCore::PixelFormat format,
|
||||
VideoCore::TextureType type) {
|
||||
|
||||
const u32 layers = type == VideoCore::TextureType::CubeMap ? 6 : 1;
|
||||
const GLenum target =
|
||||
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;
|
||||
}
|
||||
|
||||
// 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 OpenGLState& state = OpenGLState::GetCurState();
|
||||
GLuint old_tex = state.texture_units[0].texture_2d;
|
||||
|
||||
// Allocate the cube texture
|
||||
// Allocate new texture
|
||||
OGLTexture texture{};
|
||||
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;
|
||||
}
|
||||
|
||||
@ -229,11 +241,11 @@ bool TextureRuntime::BlitTextures(Surface& source, Surface& dest, const VideoCor
|
||||
state.draw.draw_framebuffer = draw_fbo.handle;
|
||||
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;
|
||||
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;
|
||||
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)
|
||||
: 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));
|
||||
@ -361,7 +373,8 @@ void Surface::ScaledDownload(const VideoCore::BufferTextureCopy& download) {
|
||||
const u32 rect_height = download.texture_rect.GetHeight();
|
||||
|
||||
// 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_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_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);
|
||||
glBindTexture(GL_TEXTURE_2D, unscaled_tex.handle);
|
||||
|
||||
|
@ -70,11 +70,9 @@ public:
|
||||
/// Returns the OpenGL format tuple associated with the provided pixel format
|
||||
const FormatTuple& GetFormatTuple(VideoCore::PixelFormat pixel_format);
|
||||
|
||||
/// Allocates a 2D OpenGL texture with the specified dimentions and format
|
||||
OGLTexture Allocate2D(u32 width, u32 height, VideoCore::PixelFormat format);
|
||||
|
||||
/// Allocates an OpenGL cube map texture with the specified dimentions and format
|
||||
OGLTexture AllocateCubeMap(u32 width, VideoCore::PixelFormat format);
|
||||
/// Allocates an OpenGL texture with the specified dimentions and format
|
||||
OGLTexture Allocate(u32 width, u32 height, VideoCore::PixelFormat format,
|
||||
VideoCore::TextureType type);
|
||||
|
||||
/// Fills the rectangle of the texture with the clear value provided
|
||||
bool ClearTexture(Surface& surface, const VideoCore::TextureClear& clear,
|
||||
|
Reference in New Issue
Block a user