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

View File

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

View File

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

View File

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

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. // 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());

View File

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

View File

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

View File

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

View File

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