rasterizer_cache: Cleanup texture clears
This commit is contained in:
@ -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>
|
||||
|
@ -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));
|
||||
|
@ -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;
|
||||
|
@ -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{};
|
||||
|
@ -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!");
|
||||
|
@ -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);
|
||||
|
@ -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) {
|
||||
|
@ -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 {
|
||||
|
Reference in New Issue
Block a user