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) {
|
SurfaceInterval copy_interval) {
|
||||||
MICROPROFILE_SCOPE(RasterizerCache_CopySurface);
|
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);
|
ASSERT(subrect_params.GetInterval() == copy_interval && src_surface != dst_surface);
|
||||||
|
|
||||||
if (src_surface->type == SurfaceType::Fill) {
|
if (src_surface->type == SurfaceType::Fill) {
|
||||||
// FillSurface needs a 4 bytes buffer
|
const TextureClear texture_clear = {
|
||||||
const u32 fill_offset =
|
.texture_level = 0,
|
||||||
(boost::icl::first(copy_interval) - src_surface->addr) % src_surface->fill_size;
|
.texture_rect = dst_rect,
|
||||||
std::array<u8, 4> fill_buffer;
|
.value = src_surface->MakeClearValue(copy_addr, dst_surface->pixel_format),
|
||||||
|
|
||||||
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),
|
|
||||||
};
|
};
|
||||||
runtime.BlitTextures(*src_surface, *dst_surface, texture_blit);
|
runtime.ClearTexture(*dst_surface, texture_clear);
|
||||||
return;
|
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>
|
template <class T>
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
#include "common/alignment.h"
|
#include "common/alignment.h"
|
||||||
#include "common/assert.h"
|
#include "common/assert.h"
|
||||||
#include "video_core/rasterizer_cache/surface_base.h"
|
#include "video_core/rasterizer_cache/surface_base.h"
|
||||||
|
#include "video_core/texture/texture_decode.h"
|
||||||
|
|
||||||
namespace VideoCore {
|
namespace VideoCore {
|
||||||
|
|
||||||
@ -98,6 +99,58 @@ SurfaceInterval SurfaceBase::GetCopyableInterval(const SurfaceParams& params) co
|
|||||||
return result;
|
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() {
|
std::shared_ptr<Watcher> SurfaceBase::CreateWatcher() {
|
||||||
auto weak_ptr = weak_from_this();
|
auto weak_ptr = weak_from_this();
|
||||||
auto watcher = std::make_shared<Watcher>(std::move(weak_ptr));
|
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
|
/// Returns the region of the biggest valid rectange within interval
|
||||||
SurfaceInterval GetCopyableInterval(const SurfaceParams& params) const;
|
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
|
/// Creates a surface watcher linked to this surface
|
||||||
std::shared_ptr<Watcher> CreateWatcher();
|
std::shared_ptr<Watcher> CreateWatcher();
|
||||||
|
|
||||||
@ -83,6 +86,10 @@ public:
|
|||||||
return *invalid_regions.equal_range(interval).first == interval;
|
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:
|
public:
|
||||||
bool registered = false;
|
bool registered = false;
|
||||||
bool picked = false;
|
bool picked = false;
|
||||||
|
@ -48,6 +48,7 @@ union ClearValue {
|
|||||||
struct TextureClear {
|
struct TextureClear {
|
||||||
u32 texture_level;
|
u32 texture_level;
|
||||||
Rect2D texture_rect;
|
Rect2D texture_rect;
|
||||||
|
ClearValue value;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct TextureCopy {
|
struct TextureCopy {
|
||||||
@ -76,12 +77,6 @@ struct BufferTextureCopy {
|
|||||||
u32 texture_level;
|
u32 texture_level;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct BufferCopy {
|
|
||||||
u32 src_offset;
|
|
||||||
u32 dst_offset;
|
|
||||||
u32 size;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct HostTextureTag {
|
struct HostTextureTag {
|
||||||
PixelFormat format{};
|
PixelFormat format{};
|
||||||
TextureType type{};
|
TextureType type{};
|
||||||
|
@ -158,8 +158,7 @@ OGLTexture TextureRuntime::Allocate(u32 width, u32 height, u32 levels,
|
|||||||
return texture;
|
return texture;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TextureRuntime::ClearTexture(Surface& surface, const VideoCore::TextureClear& clear,
|
bool TextureRuntime::ClearTexture(Surface& surface, const VideoCore::TextureClear& clear) {
|
||||||
VideoCore::ClearValue value) {
|
|
||||||
OpenGLState prev_state = OpenGLState::GetCurState();
|
OpenGLState prev_state = OpenGLState::GetCurState();
|
||||||
SCOPE_EXIT({ prev_state.Apply(); });
|
SCOPE_EXIT({ prev_state.Apply(); });
|
||||||
|
|
||||||
@ -189,7 +188,7 @@ bool TextureRuntime::ClearTexture(Surface& surface, const VideoCore::TextureClea
|
|||||||
state.color_mask.alpha_enabled = true;
|
state.color_mask.alpha_enabled = true;
|
||||||
state.Apply();
|
state.Apply();
|
||||||
|
|
||||||
glClearBufferfv(GL_COLOR, 0, value.color.AsArray());
|
glClearBufferfv(GL_COLOR, 0, clear.value.color.AsArray());
|
||||||
break;
|
break;
|
||||||
case VideoCore::SurfaceType::Depth:
|
case VideoCore::SurfaceType::Depth:
|
||||||
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0);
|
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.depth.write_mask = GL_TRUE;
|
||||||
state.Apply();
|
state.Apply();
|
||||||
|
|
||||||
glClearBufferfv(GL_DEPTH, 0, &value.depth);
|
glClearBufferfv(GL_DEPTH, 0, &clear.value.depth);
|
||||||
break;
|
break;
|
||||||
case VideoCore::SurfaceType::DepthStencil:
|
case VideoCore::SurfaceType::DepthStencil:
|
||||||
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0);
|
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.stencil.write_mask = -1;
|
||||||
state.Apply();
|
state.Apply();
|
||||||
|
|
||||||
glClearBufferfi(GL_DEPTH_STENCIL, 0, value.depth, value.stencil);
|
glClearBufferfi(GL_DEPTH_STENCIL, 0, clear.value.depth, clear.value.stencil);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
UNREACHABLE_MSG("Invalid surface type!");
|
UNREACHABLE_MSG("Invalid surface type!");
|
||||||
|
@ -57,8 +57,7 @@ public:
|
|||||||
VideoCore::TextureType type);
|
VideoCore::TextureType type);
|
||||||
|
|
||||||
/// 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);
|
||||||
VideoCore::ClearValue value);
|
|
||||||
|
|
||||||
/// Copies a rectangle of src_tex to another rectange of dst_rect
|
/// Copies a rectangle of src_tex to another rectange of dst_rect
|
||||||
bool CopyTextures(Surface& source, Surface& dest, const VideoCore::TextureCopy& copy);
|
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));
|
texture_recycler.emplace(tag, std::move(alloc));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TextureRuntime::ClearTexture(Surface& surface, const VideoCore::TextureClear& clear,
|
bool TextureRuntime::ClearTexture(Surface& surface, const VideoCore::TextureClear& clear) {
|
||||||
VideoCore::ClearValue value) {
|
|
||||||
renderpass_cache.ExitRenderpass();
|
renderpass_cache.ExitRenderpass();
|
||||||
|
|
||||||
const RecordParams params = {
|
const RecordParams params = {
|
||||||
@ -318,7 +317,7 @@ bool TextureRuntime::ClearTexture(Surface& surface, const VideoCore::TextureClea
|
|||||||
};
|
};
|
||||||
|
|
||||||
if (clear.texture_rect == surface.GetScaledRect()) {
|
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 = {
|
const vk::ImageSubresourceRange range = {
|
||||||
.aspectMask = params.aspect,
|
.aspectMask = params.aspect,
|
||||||
.baseMipLevel = clear.texture_level,
|
.baseMipLevel = clear.texture_level,
|
||||||
@ -368,11 +367,11 @@ bool TextureRuntime::ClearTexture(Surface& surface, const VideoCore::TextureClea
|
|||||||
static_cast<bool>(params.aspect & vk::ImageAspectFlagBits::eColor);
|
static_cast<bool>(params.aspect & vk::ImageAspectFlagBits::eColor);
|
||||||
if (is_color) {
|
if (is_color) {
|
||||||
cmdbuf.clearColorImage(params.src_image, vk::ImageLayout::eTransferDstOptimal,
|
cmdbuf.clearColorImage(params.src_image, vk::ImageLayout::eTransferDstOptimal,
|
||||||
MakeClearColorValue(value.color), range);
|
MakeClearColorValue(clear.value.color), range);
|
||||||
} else {
|
} else {
|
||||||
cmdbuf.clearDepthStencilImage(params.src_image,
|
cmdbuf.clearDepthStencilImage(params.src_image,
|
||||||
vk::ImageLayout::eTransferDstOptimal,
|
vk::ImageLayout::eTransferDstOptimal,
|
||||||
MakeClearDepthStencilValue(value), range);
|
MakeClearDepthStencilValue(clear.value), range);
|
||||||
}
|
}
|
||||||
|
|
||||||
cmdbuf.pipelineBarrier(vk::PipelineStageFlagBits::eTransfer, params.pipeline_flags,
|
cmdbuf.pipelineBarrier(vk::PipelineStageFlagBits::eTransfer, params.pipeline_flags,
|
||||||
@ -381,13 +380,12 @@ bool TextureRuntime::ClearTexture(Surface& surface, const VideoCore::TextureClea
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
ClearTextureWithRenderpass(surface, clear, value);
|
ClearTextureWithRenderpass(surface, clear);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void TextureRuntime::ClearTextureWithRenderpass(Surface& surface,
|
void TextureRuntime::ClearTextureWithRenderpass(Surface& surface,
|
||||||
const VideoCore::TextureClear& clear,
|
const VideoCore::TextureClear& clear) {
|
||||||
VideoCore::ClearValue value) {
|
|
||||||
const bool is_color = surface.type != VideoCore::SurfaceType::Depth &&
|
const bool is_color = surface.type != VideoCore::SurfaceType::Depth &&
|
||||||
surface.type != VideoCore::SurfaceType::DepthStencil;
|
surface.type != VideoCore::SurfaceType::DepthStencil;
|
||||||
|
|
||||||
@ -450,7 +448,7 @@ void TextureRuntime::ClearTextureWithRenderpass(Surface& surface,
|
|||||||
};
|
};
|
||||||
|
|
||||||
renderpass_cache.EnterRenderpass(color_surface, depth_surface, render_area, true,
|
renderpass_cache.EnterRenderpass(color_surface, depth_surface, render_area, true,
|
||||||
MakeClearValue(value));
|
MakeClearValue(clear.value));
|
||||||
renderpass_cache.ExitRenderpass();
|
renderpass_cache.ExitRenderpass();
|
||||||
|
|
||||||
scheduler.Record([params, access_flag, pipeline_flags](vk::CommandBuffer cmdbuf) {
|
scheduler.Record([params, access_flag, pipeline_flags](vk::CommandBuffer cmdbuf) {
|
||||||
|
@ -114,8 +114,7 @@ public:
|
|||||||
vk::ImageUsageFlags usage, vk::ImageAspectFlags aspect);
|
vk::ImageUsageFlags usage, vk::ImageAspectFlags aspect);
|
||||||
|
|
||||||
/// 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);
|
||||||
VideoCore::ClearValue value);
|
|
||||||
|
|
||||||
/// Copies a rectangle of src_tex to another rectange of dst_rect
|
/// Copies a rectangle of src_tex to another rectange of dst_rect
|
||||||
bool CopyTextures(Surface& source, Surface& dest, const VideoCore::TextureCopy& copy);
|
bool CopyTextures(Surface& source, Surface& dest, const VideoCore::TextureCopy& copy);
|
||||||
@ -140,8 +139,7 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
/// Clears a partial texture rect using a clear rectangle
|
/// Clears a partial texture rect using a clear rectangle
|
||||||
void ClearTextureWithRenderpass(Surface& surface, const VideoCore::TextureClear& clear,
|
void ClearTextureWithRenderpass(Surface& surface, const VideoCore::TextureClear& clear);
|
||||||
VideoCore::ClearValue value);
|
|
||||||
|
|
||||||
/// Returns the current Vulkan instance
|
/// Returns the current Vulkan instance
|
||||||
const Instance& GetInstance() const {
|
const Instance& GetInstance() const {
|
||||||
|
Reference in New Issue
Block a user