rasterizer_cache: Cleanup texture clears

This commit is contained in:
GPUCode
2023-02-14 21:07:25 +02:00
parent 44c187d705
commit 087bcd8f97
8 changed files with 92 additions and 56 deletions

View File

@ -374,43 +374,30 @@ void RasterizerCache<T>::CopySurface(const Surface& src_surface, const Surface&
SurfaceInterval copy_interval) {
MICROPROFILE_SCOPE(RasterizerCache_CopySurface);
const SurfaceParams subrect_params = dst_surface->FromInterval(copy_interval);
const PAddr copy_addr = copy_interval.lower();
const auto subrect_params = dst_surface->FromInterval(copy_interval);
const Rect2D dst_rect = dst_surface->GetScaledSubRect(subrect_params);
ASSERT(subrect_params.GetInterval() == copy_interval && src_surface != dst_surface);
if (src_surface->type == SurfaceType::Fill) {
// FillSurface needs a 4 bytes buffer
const u32 fill_offset =
(boost::icl::first(copy_interval) - src_surface->addr) % src_surface->fill_size;
std::array<u8, 4> fill_buffer;
u32 fill_buff_pos = fill_offset;
for (std::size_t i = 0; i < fill_buffer.size(); i++) {
fill_buffer[i] = src_surface->fill_data[fill_buff_pos++ % src_surface->fill_size];
}
const ClearValue clear_value =
MakeClearValue(dst_surface->type, dst_surface->pixel_format, fill_buffer.data());
const TextureClear clear_rect = {
.texture_level = 0, .texture_rect = dst_surface->GetScaledSubRect(subrect_params)};
runtime.ClearTexture(*dst_surface, clear_rect, clear_value);
return;
}
if (src_surface->CanSubRect(subrect_params)) {
const TextureBlit texture_blit = {
.src_level = 0,
.dst_level = 0,
.src_layer = 0,
.dst_layer = 0,
.src_rect = src_surface->GetScaledSubRect(subrect_params),
.dst_rect = dst_surface->GetScaledSubRect(subrect_params),
const TextureClear texture_clear = {
.texture_level = 0,
.texture_rect = dst_rect,
.value = src_surface->MakeClearValue(copy_addr, dst_surface->pixel_format),
};
runtime.BlitTextures(*src_surface, *dst_surface, texture_blit);
runtime.ClearTexture(*dst_surface, texture_clear);
return;
}
UNREACHABLE();
const TextureBlit texture_blit = {
.src_level = 0,
.dst_level = 0,
.src_layer = 0,
.dst_layer = 0,
.src_rect = src_surface->GetScaledSubRect(subrect_params),
.dst_rect = dst_rect,
};
runtime.BlitTextures(*src_surface, *dst_surface, texture_blit);
}
template <class T>

View File

@ -5,6 +5,7 @@
#include "common/alignment.h"
#include "common/assert.h"
#include "video_core/rasterizer_cache/surface_base.h"
#include "video_core/texture/texture_decode.h"
namespace VideoCore {
@ -98,6 +99,58 @@ SurfaceInterval SurfaceBase::GetCopyableInterval(const SurfaceParams& params) co
return result;
}
ClearValue SurfaceBase::MakeClearValue(PAddr copy_addr, PixelFormat dst_format) {
const SurfaceType dst_type = GetFormatType(dst_format);
const std::array fill_buffer = MakeFillBuffer(copy_addr);
ClearValue result{};
switch (dst_type) {
case SurfaceType::Color:
case SurfaceType::Texture:
case SurfaceType::Fill: {
Pica::Texture::TextureInfo tex_info{};
tex_info.format = static_cast<Pica::TexturingRegs::TextureFormat>(dst_format);
const auto color = Pica::Texture::LookupTexture(fill_buffer.data(), 0, 0, tex_info);
result.color = color / 255.f;
break;
}
case SurfaceType::Depth: {
u32 depth_uint = 0;
if (dst_format == PixelFormat::D16) {
std::memcpy(&depth_uint, fill_buffer.data(), 2);
result.depth = depth_uint / 65535.0f; // 2^16 - 1
} else if (dst_format == PixelFormat::D24) {
std::memcpy(&depth_uint, fill_buffer.data(), 3);
result.depth = depth_uint / 16777215.0f; // 2^24 - 1
}
break;
}
case SurfaceType::DepthStencil: {
u32 clear_value_uint;
std::memcpy(&clear_value_uint, fill_buffer.data(), sizeof(u32));
result.depth = (clear_value_uint & 0xFFFFFF) / 16777215.0f; // 2^24 - 1
result.stencil = (clear_value_uint >> 24);
break;
}
default:
UNREACHABLE_MSG("Invalid surface type!");
}
return result;
}
std::array<u8, 4> SurfaceBase::MakeFillBuffer(PAddr copy_addr) {
const PAddr fill_offset = (copy_addr - addr) % fill_size;
std::array<u8, 4> fill_buffer;
u32 fill_buff_pos = fill_offset;
for (std::size_t i = 0; i < fill_buffer.size(); i++) {
fill_buffer[i] = fill_data[fill_buff_pos++ % fill_size];
}
return fill_buffer;
}
std::shared_ptr<Watcher> SurfaceBase::CreateWatcher() {
auto weak_ptr = weak_from_this();
auto watcher = std::make_shared<Watcher>(std::move(weak_ptr));

View File

@ -63,6 +63,9 @@ public:
/// Returns the region of the biggest valid rectange within interval
SurfaceInterval GetCopyableInterval(const SurfaceParams& params) const;
/// Returns the clear value used to validate another surface from this fill surface
ClearValue MakeClearValue(PAddr copy_addr, PixelFormat dst_format);
/// Creates a surface watcher linked to this surface
std::shared_ptr<Watcher> CreateWatcher();
@ -83,6 +86,10 @@ public:
return *invalid_regions.equal_range(interval).first == interval;
}
private:
/// Returns the fill buffer value starting from copy_addr
std::array<u8, 4> MakeFillBuffer(PAddr copy_addr);
public:
bool registered = false;
bool picked = false;

View File

@ -48,6 +48,7 @@ union ClearValue {
struct TextureClear {
u32 texture_level;
Rect2D texture_rect;
ClearValue value;
};
struct TextureCopy {
@ -76,12 +77,6 @@ struct BufferTextureCopy {
u32 texture_level;
};
struct BufferCopy {
u32 src_offset;
u32 dst_offset;
u32 size;
};
struct HostTextureTag {
PixelFormat format{};
TextureType type{};

View File

@ -158,8 +158,7 @@ OGLTexture TextureRuntime::Allocate(u32 width, u32 height, u32 levels,
return texture;
}
bool TextureRuntime::ClearTexture(Surface& surface, const VideoCore::TextureClear& clear,
VideoCore::ClearValue value) {
bool TextureRuntime::ClearTexture(Surface& surface, const VideoCore::TextureClear& clear) {
OpenGLState prev_state = OpenGLState::GetCurState();
SCOPE_EXIT({ prev_state.Apply(); });
@ -189,7 +188,7 @@ bool TextureRuntime::ClearTexture(Surface& surface, const VideoCore::TextureClea
state.color_mask.alpha_enabled = true;
state.Apply();
glClearBufferfv(GL_COLOR, 0, value.color.AsArray());
glClearBufferfv(GL_COLOR, 0, clear.value.color.AsArray());
break;
case VideoCore::SurfaceType::Depth:
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0);
@ -200,7 +199,7 @@ bool TextureRuntime::ClearTexture(Surface& surface, const VideoCore::TextureClea
state.depth.write_mask = GL_TRUE;
state.Apply();
glClearBufferfv(GL_DEPTH, 0, &value.depth);
glClearBufferfv(GL_DEPTH, 0, &clear.value.depth);
break;
case VideoCore::SurfaceType::DepthStencil:
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0);
@ -211,7 +210,7 @@ bool TextureRuntime::ClearTexture(Surface& surface, const VideoCore::TextureClea
state.stencil.write_mask = -1;
state.Apply();
glClearBufferfi(GL_DEPTH_STENCIL, 0, value.depth, value.stencil);
glClearBufferfi(GL_DEPTH_STENCIL, 0, clear.value.depth, clear.value.stencil);
break;
default:
UNREACHABLE_MSG("Invalid surface type!");

View File

@ -57,8 +57,7 @@ public:
VideoCore::TextureType type);
/// Fills the rectangle of the texture with the clear value provided
bool ClearTexture(Surface& surface, const VideoCore::TextureClear& clear,
VideoCore::ClearValue value);
bool ClearTexture(Surface& surface, const VideoCore::TextureClear& clear);
/// Copies a rectangle of src_tex to another rectange of dst_rect
bool CopyTextures(Surface& source, Surface& dest, const VideoCore::TextureCopy& copy);

View File

@ -306,8 +306,7 @@ void TextureRuntime::Recycle(const HostTextureTag tag, ImageAlloc&& alloc) {
texture_recycler.emplace(tag, std::move(alloc));
}
bool TextureRuntime::ClearTexture(Surface& surface, const VideoCore::TextureClear& clear,
VideoCore::ClearValue value) {
bool TextureRuntime::ClearTexture(Surface& surface, const VideoCore::TextureClear& clear) {
renderpass_cache.ExitRenderpass();
const RecordParams params = {
@ -318,7 +317,7 @@ bool TextureRuntime::ClearTexture(Surface& surface, const VideoCore::TextureClea
};
if (clear.texture_rect == surface.GetScaledRect()) {
scheduler.Record([params, clear, value](vk::CommandBuffer cmdbuf) {
scheduler.Record([params, clear](vk::CommandBuffer cmdbuf) {
const vk::ImageSubresourceRange range = {
.aspectMask = params.aspect,
.baseMipLevel = clear.texture_level,
@ -368,11 +367,11 @@ bool TextureRuntime::ClearTexture(Surface& surface, const VideoCore::TextureClea
static_cast<bool>(params.aspect & vk::ImageAspectFlagBits::eColor);
if (is_color) {
cmdbuf.clearColorImage(params.src_image, vk::ImageLayout::eTransferDstOptimal,
MakeClearColorValue(value.color), range);
MakeClearColorValue(clear.value.color), range);
} else {
cmdbuf.clearDepthStencilImage(params.src_image,
vk::ImageLayout::eTransferDstOptimal,
MakeClearDepthStencilValue(value), range);
MakeClearDepthStencilValue(clear.value), range);
}
cmdbuf.pipelineBarrier(vk::PipelineStageFlagBits::eTransfer, params.pipeline_flags,
@ -381,13 +380,12 @@ bool TextureRuntime::ClearTexture(Surface& surface, const VideoCore::TextureClea
return true;
}
ClearTextureWithRenderpass(surface, clear, value);
ClearTextureWithRenderpass(surface, clear);
return true;
}
void TextureRuntime::ClearTextureWithRenderpass(Surface& surface,
const VideoCore::TextureClear& clear,
VideoCore::ClearValue value) {
const VideoCore::TextureClear& clear) {
const bool is_color = surface.type != VideoCore::SurfaceType::Depth &&
surface.type != VideoCore::SurfaceType::DepthStencil;
@ -450,7 +448,7 @@ void TextureRuntime::ClearTextureWithRenderpass(Surface& surface,
};
renderpass_cache.EnterRenderpass(color_surface, depth_surface, render_area, true,
MakeClearValue(value));
MakeClearValue(clear.value));
renderpass_cache.ExitRenderpass();
scheduler.Record([params, access_flag, pipeline_flags](vk::CommandBuffer cmdbuf) {

View File

@ -114,8 +114,7 @@ public:
vk::ImageUsageFlags usage, vk::ImageAspectFlags aspect);
/// Fills the rectangle of the texture with the clear value provided
bool ClearTexture(Surface& surface, const VideoCore::TextureClear& clear,
VideoCore::ClearValue value);
bool ClearTexture(Surface& surface, const VideoCore::TextureClear& clear);
/// Copies a rectangle of src_tex to another rectange of dst_rect
bool CopyTextures(Surface& source, Surface& dest, const VideoCore::TextureCopy& copy);
@ -140,8 +139,7 @@ public:
private:
/// Clears a partial texture rect using a clear rectangle
void ClearTextureWithRenderpass(Surface& surface, const VideoCore::TextureClear& clear,
VideoCore::ClearValue value);
void ClearTextureWithRenderpass(Surface& surface, const VideoCore::TextureClear& clear);
/// Returns the current Vulkan instance
const Instance& GetInstance() const {