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:
emufan4568
2022-09-13 21:38:21 +03:00
committed by GPUCode
parent d809687aeb
commit 887ef51f04
9 changed files with 102 additions and 92 deletions

View File

@ -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;
}

View File

@ -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;

View File

@ -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;
};

View File

@ -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 <>

View File

@ -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());

View File

@ -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);

View File

@ -65,7 +65,6 @@ public:
GLsizei height);
GLuint handle = 0;
GLenum target = GL_TEXTURE_2D;
};
class OGLSampler : private NonCopyable {

View File

@ -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);

View File

@ -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,