Compare commits

...
Author SHA1 Message Date
refractionpcsx2 13eca59847 GS/HW: Allow filling of mip levels from targets in DX12/VK 2026-02-05 16:14:40 +00:00
17 changed files with 133 additions and 52 deletions
+7
View File
@@ -706,6 +706,13 @@ void GSDevice::PurgePool()
m_pool_memory_usage = 0;
}
GSTexture* GSDevice::CreateMipRenderTarget(int w, int h, int mipmap_levels, GSTexture::Format format, bool clear, bool prefer_reuse /* = false */)
{
pxAssert(mipmap_levels != 0 && (mipmap_levels < 0 || mipmap_levels <= GetMipmapLevelsForSize(w, h)));
const int levels = mipmap_levels < 0 ? GetMipmapLevelsForSize(w, h) : mipmap_levels;
return FetchSurface(GSTexture::Type::RenderTarget, w, h, levels, format, clear, !prefer_reuse);
}
GSTexture* GSDevice::CreateRenderTarget(int w, int h, GSTexture::Format format, bool clear, bool prefer_reuse)
{
return FetchSurface(GSTexture::Type::RenderTarget, w, h, 1, format, clear, !prefer_reuse);
+1
View File
@@ -1060,6 +1060,7 @@ public:
virtual void PopDebugGroup() = 0;
virtual void InsertDebugMessage(DebugMessageCategory category, const char* fmt, ...) = 0;
GSTexture* CreateMipRenderTarget(int w, int h, int mipmap_levels, GSTexture::Format format, bool clear = true, bool prefer_reuse = false);
GSTexture* CreateRenderTarget(int w, int h, GSTexture::Format format, bool clear = true, bool prefer_reuse = true);
GSTexture* CreateDepthStencil(int w, int h, GSTexture::Format format, bool clear = true, bool prefer_reuse = true);
GSTexture* CreateTexture(int w, int h, int mipmap_levels, GSTexture::Format format, bool prefer_reuse = false);
+2 -2
View File
@@ -158,13 +158,13 @@ u32 GSTexture::CalcUploadSize(Format format, u32 height, u32 pitch)
return pitch * ((static_cast<u32>(height) + (block_size - 1)) / block_size);
}
void GSTexture::GenerateMipmapsIfNeeded()
void GSTexture::GenerateMipmapsIfNeeded(GSTexture* target_list[], GSVector2i offsets_list[])
{
if (!m_needs_mipmaps_generated || m_mipmap_levels <= 1 || IsCompressedFormat())
return;
m_needs_mipmaps_generated = false;
GenerateMipmap();
GenerateMipmap(target_list, offsets_list);
}
GSDownloadTexture::GSDownloadTexture(u32 width, u32 height, GSTexture::Format format)
+3 -2
View File
@@ -59,6 +59,7 @@ public:
};
protected:
GSVector2i m_size{};
int m_mipmap_levels = 0;
Type m_type = Type::Invalid;
@@ -82,7 +83,7 @@ public:
virtual bool Update(const GSVector4i& r, const void* data, int pitch, int layer = 0) = 0;
virtual bool Map(GSMap& m, const GSVector4i* r = nullptr, int layer = 0) = 0;
virtual void Unmap() = 0;
virtual void GenerateMipmap() = 0;
virtual void GenerateMipmap(GSTexture* target_list[], GSVector2i offset_list[]) = 0;
#ifdef PCSX2_DEVBUILD
virtual void SetDebugName(std::string_view name) = 0;
@@ -153,7 +154,7 @@ public:
m_clear_value.depth = depth;
}
void GenerateMipmapsIfNeeded();
void GenerateMipmapsIfNeeded(GSTexture* target_list[], GSVector2i offsets_list[]);
void ClearMipmapGenerationFlag() { m_needs_mipmaps_generated = false; }
// Typical size of a RGBA texture
+1 -1
View File
@@ -84,7 +84,7 @@ void GSTexture11::Unmap()
pxFailRel("Should not be called.");
}
void GSTexture11::GenerateMipmap()
void GSTexture11::GenerateMipmap(GSTexture* target_list[], GSVector2i offsets_list[])
{
GSDevice11::GetInstance()->GetD3DContext()->GenerateMips(operator ID3D11ShaderResourceView*());
}
+1 -1
View File
@@ -31,7 +31,7 @@ public:
bool Update(const GSVector4i& r, const void* data, int pitch, int layer = 0) override;
bool Map(GSMap& m, const GSVector4i* r = NULL, int layer = 0) override;
void Unmap() override;
void GenerateMipmap() override;
void GenerateMipmap(GSTexture* target_list[], GSVector2i offsets_list[]) override;
#ifdef PCSX2_DEVBUILD
void SetDebugName(std::string_view name) override;
+27 -20
View File
@@ -1595,7 +1595,8 @@ void GSDevice12::CopyRect(GSTexture* sTex, GSTexture* dTex, const GSVector4i& r,
dstloc.SubresourceIndex = 0;
// DX12 requires ProgrammableSamplePositions tier 1 to support partial depth copies, otherwise fallback to full depth copies.
const bool full_rt_copy = src_dst_rect_match && ((sTex12->IsDepthStencil() && !m_programmable_sample_positions) || (destX == 0 && destY == 0 && r.eq(src_rect)));
// We only want to copy mip level 0, so check resource mip levels
const bool full_rt_copy = src_dst_rect_match && ((sTex12->IsDepthStencil() && !m_programmable_sample_positions) || (destX == 0 && destY == 0 && r.eq(src_rect))) && (sTex12->GetMipmapLevels() == 1 && dTex12->GetMipmapLevels() == 1);
if (full_rt_copy)
{
GetCommandList().list4->CopyResource(dTex12->GetResource(), sTex12->GetResource());
@@ -3525,7 +3526,7 @@ void GSDevice12::UnbindTexture(GSTexture12* tex)
}
void GSDevice12::RenderTextureMipmap(
GSTexture12* texture, u32 dst_level, u32 dst_width, u32 dst_height, u32 src_level, u32 src_width, u32 src_height)
GSTexture12* src_texture, GSTexture12* dst_texture, u32 dst_level, u32 dst_width, u32 dst_height, u32 src_level, u32 src_width, u32 src_height, GSVector2i offsets)
{
EndRenderPass();
@@ -3540,16 +3541,17 @@ void GSDevice12::RenderTextureMipmap(
ExecuteCommandList(false);
// Setup views. This will be a partial view for the SRV.
D3D12_RENDER_TARGET_VIEW_DESC rtv_desc = {texture->GetDXGIFormat(), D3D12_RTV_DIMENSION_TEXTURE2D};
D3D12_RENDER_TARGET_VIEW_DESC rtv_desc = {dst_texture->GetDXGIFormat(), D3D12_RTV_DIMENSION_TEXTURE2D};
rtv_desc.Texture2D = {dst_level, 0u};
m_device.get()->CreateRenderTargetView(texture->GetResource(), &rtv_desc, rtv_handle);
m_device.get()->CreateRenderTargetView(dst_texture->GetResource(), &rtv_desc, rtv_handle);
D3D12_SHADER_RESOURCE_VIEW_DESC srv_desc = {
texture->GetDXGIFormat(), D3D12_SRV_DIMENSION_TEXTURE2D, D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING};
src_texture->GetDXGIFormat(), D3D12_SRV_DIMENSION_TEXTURE2D, D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING};
srv_desc.Texture2D = {src_level, 1u, 0u, 0.0f};
m_device.get()->CreateShaderResourceView(texture->GetResource(), &srv_desc, srv_handle);
m_device.get()->CreateShaderResourceView(src_texture->GetResource(), &srv_desc, srv_handle);
// We need to set the descriptors up manually, because we're not going through GSTexture.
m_dirty_flags |= DIRTY_FLAG_TEXTURES_DESCRIPTOR_TABLE;
if (!GetTextureGroupDescriptors(&m_utility_texture_gpu, &srv_handle, 1))
ExecuteCommandList(false);
if (m_utility_sampler_cpu != m_linear_sampler_cpu)
@@ -3561,12 +3563,12 @@ void GSDevice12::RenderTextureMipmap(
// *now* we don't have to worry about running out of anything.
const D3D12CommandList& cmdlist = GetCommandList();
if (texture->GetResourceState() != GSTexture12::ResourceState::PixelShaderResource)
texture->TransitionSubresourceToState(
cmdlist, src_level, texture->GetResourceState(), GSTexture12::ResourceState::PixelShaderResource);
if (texture->GetResourceState() != GSTexture12::ResourceState::RenderTarget)
texture->TransitionSubresourceToState(
cmdlist, dst_level, texture->GetResourceState(), GSTexture12::ResourceState::RenderTarget);
if (src_texture->GetResourceState() != GSTexture12::ResourceState::PixelShaderResource)
src_texture->TransitionSubresourceToState(
cmdlist, src_level, src_texture->GetResourceState(), GSTexture12::ResourceState::PixelShaderResource);
if (dst_texture->GetResourceState() != GSTexture12::ResourceState::RenderTarget)
dst_texture->TransitionSubresourceToState(
cmdlist, dst_level, dst_texture->GetResourceState(), GSTexture12::ResourceState::RenderTarget);
// We set the state directly here.
constexpr u32 MODIFIED_STATE = DIRTY_FLAG_VIEWPORT | DIRTY_FLAG_SCISSOR | DIRTY_FLAG_RENDER_TARGET;
@@ -3574,7 +3576,7 @@ void GSDevice12::RenderTextureMipmap(
// Using a render pass is probably a bit overkill.
const D3D12_DISCARD_REGION discard_region = {0u, nullptr, dst_level, 1u};
cmdlist.list4->DiscardResource(texture->GetResource(), &discard_region);
cmdlist.list4->DiscardResource(dst_texture->GetResource(), &discard_region);
cmdlist.list4->OMSetRenderTargets(1, &rtv_handle.cpu_handle, FALSE, nullptr);
const D3D12_VIEWPORT vp = {0.0f, 0.0f, static_cast<float>(dst_width), static_cast<float>(dst_height), 0.0f, 1.0f};
@@ -3585,16 +3587,21 @@ void GSDevice12::RenderTextureMipmap(
SetUtilityRootSignature();
SetPipeline(m_convert[static_cast<int>(ShaderConvert::COPY)].get());
DrawStretchRect(GSVector4(0.0f, 0.0f, 1.0f, 1.0f),
const int src_tex_width = std::max<int>(src_texture->GetWidth() >> src_level, 1);
const int src_tex_height = std::max<int>(src_texture->GetHeight() >> src_level, 1);
GSVector4 src_level_size = GSVector4(src_tex_width, src_tex_height, src_tex_width, src_tex_height);
GSVector4 src_bounds = GSVector4(static_cast<float>(offsets.x), static_cast<float>(offsets.y), static_cast<float>(offsets.x + src_width), static_cast<float>(offsets.y + src_height)) /
src_level_size;
DrawStretchRect(src_bounds,
GSVector4(0.0f, 0.0f, static_cast<float>(dst_width), static_cast<float>(dst_height)),
GSVector2i(dst_width, dst_height));
if (texture->GetResourceState() != GSTexture12::ResourceState::PixelShaderResource)
texture->TransitionSubresourceToState(
cmdlist, src_level, GSTexture12::ResourceState::PixelShaderResource, texture->GetResourceState());
if (texture->GetResourceState() != GSTexture12::ResourceState::RenderTarget)
texture->TransitionSubresourceToState(
cmdlist, dst_level, GSTexture12::ResourceState::RenderTarget, texture->GetResourceState());
if (src_texture->GetResourceState() != GSTexture12::ResourceState::PixelShaderResource)
src_texture->TransitionSubresourceToState(
cmdlist, src_level, GSTexture12::ResourceState::PixelShaderResource, src_texture->GetResourceState());
if (dst_texture->GetResourceState() != GSTexture12::ResourceState::RenderTarget)
dst_texture->TransitionSubresourceToState(
cmdlist, dst_level, GSTexture12::ResourceState::RenderTarget, dst_texture->GetResourceState());
// Must destroy after current cmdlist.
DeferDescriptorDestruction(m_descriptor_heap_manager, &srv_handle);
+2 -2
View File
@@ -524,8 +524,8 @@ public:
// Assumes that the previous level has been transitioned to PS resource,
// and the current level has been transitioned to RT.
void RenderTextureMipmap(GSTexture12* texture, u32 dst_level, u32 dst_width, u32 dst_height, u32 src_level,
u32 src_width, u32 src_height);
void RenderTextureMipmap(GSTexture12* src_texture, GSTexture12* dst_texture, u32 dst_level, u32 dst_width, u32 dst_height, u32 src_level,
u32 src_width, u32 src_height, GSVector2i offsets);
// Ends a render pass if we're currently in one.
// When Bind() is next called, the pass will be restarted.
+9 -3
View File
@@ -771,20 +771,26 @@ void GSTexture12::Unmap()
m_needs_mipmaps_generated |= (m_map_level == 0);
}
void GSTexture12::GenerateMipmap()
void GSTexture12::GenerateMipmap(GSTexture* target_list[], GSVector2i offsets_list[])
{
pxAssert(!IsCompressedFormat(m_format));
for (int dst_level = 1; dst_level < m_mipmap_levels; dst_level++)
{
const int src_level = dst_level - 1;
const bool has_target_layer = target_list && target_list[dst_level] != nullptr;
int src_level = has_target_layer ? dst_level : (dst_level - 1);
const int src_width = std::max<int>(m_size.x >> src_level, 1);
const int src_height = std::max<int>(m_size.y >> src_level, 1);
const int dst_width = std::max<int>(m_size.x >> dst_level, 1);
const int dst_height = std::max<int>(m_size.y >> dst_level, 1);
GSVector2i offset = has_target_layer ? offsets_list[dst_level] : GSVector2i(0, 0);
src_level = has_target_layer ? 0 : src_level;
GSTexture12* src_image = has_target_layer ? static_cast<GSTexture12*>(target_list[dst_level]) : this;
GSDevice12::GetInstance()->RenderTextureMipmap(
this, dst_level, dst_width, dst_height, src_level, src_width, src_height);
src_image, this, dst_level, dst_width, dst_height, src_level, src_width, src_height, offset);
}
SetUseFenceCounter(GSDevice12::GetInstance()->GetCurrentFenceValue());
+1 -1
View File
@@ -61,7 +61,7 @@ public:
bool Update(const GSVector4i& r, const void* data, int pitch, int layer = 0) override;
bool Map(GSMap& m, const GSVector4i* r = NULL, int layer = 0) override;
void Unmap() override;
void GenerateMipmap() override;
void GenerateMipmap(GSTexture* target_list[], GSVector2i offsets_list[]) override;
#ifdef PCSX2_DEVBUILD
void SetDebugName(std::string_view name) override;
+50 -6
View File
@@ -4170,10 +4170,23 @@ void GSRendererHW::Draw()
// Backup original coverage.
const GSVector4i coverage = tmm.coverage;
GSTexture* target_levels[6] = {nullptr};
GSVector2i target_offsets[6] = {};
for (int layer = m_lod.x + 1; layer <= m_lod.y; layer++)
GSVector2i layer_levels(m_lod.x + 1, m_lod.y);
if (src->m_target)
{
const GIFRegTEX0 MIP_TEX0(GetTex0Layer(layer));
target_levels[0] = src->m_texture;
layer_levels.x = 1;
layer_levels.y = m_context->TEX1.MXL;
}
bool has_target_mips = true;
for (int layer = layer_levels.x; layer <= layer_levels.y; layer++)
{
GIFRegTEX0 MIP_TEX0(GetTex0Layer(layer));
MIP_CLAMP.MINU >>= 1;
MIP_CLAMP.MINV >>= 1;
@@ -4185,7 +4198,37 @@ void GSRendererHW::Draw()
tmm = GetTextureMinMax(MIP_TEX0, MIP_CLAMP, m_vt.IsLinear(), true);
src->UpdateLayer(MIP_TEX0, tmm.coverage, layer - m_lod.x);
if (!src->m_target)
{
src->UpdateLayer(MIP_TEX0, tmm.coverage, layer - m_lod.x);
has_target_mips = false;
}
else
{
const GSVector4i tgt_rect = GSVector4i(0, 0, tmm.coverage.z, tmm.coverage.w);
GSTextureCache::Target* tgt = g_texture_cache->FindOverlappingTarget(MIP_TEX0.TBP0, GSLocalMemory::GetEndBlockAddress(MIP_TEX0.TBP0, MIP_TEX0.TBW, MIP_TEX0.PSM, tgt_rect));
if (tgt != nullptr)
{
tgt->Update();
target_levels[layer] = tgt->m_texture;
if (tgt->m_TEX0.TBP0 != MIP_TEX0.TBP0)
{
GSVector4i offset = GSVector4i::zero();
g_texture_cache->TranslateAlignedRectByPage(tgt, MIP_TEX0.TBP0, MIP_TEX0.PSM, MIP_TEX0.TBW, tgt_rect, false);
target_offsets[layer] = GSVector2i(offset.x * tgt->GetScale(), offset.y * tgt->GetScale());
}
}
else
has_target_mips = false;
}
}
if (src->m_target && !src->m_target_direct && m_lod.y > m_lod.x && has_target_mips)
{
src->m_texture->GenerateMipmapsIfNeeded(target_levels, target_offsets);
src->m_target_mips = true;
}
// we don't need to generate mipmaps since they were provided
@@ -6507,12 +6550,13 @@ __ri void GSRendererHW::EmulateTextureSampler(const GSTextureCache::Target* rt,
const bool need_mipmap = IsMipMapDraw();
const bool shader_emulated_sampler = tex->m_palette || (tex->m_target && !m_conf.ps.shuffle && cpsm.fmt != 0) ||
complex_wms_wmt || psm.depth || target_region;
const bool can_trilinear = !tex->m_palette && !tex->m_target && !m_conf.ps.shuffle;
const bool mips_available = tex->m_target_mips || !tex->m_target;
const bool can_trilinear = !tex->m_palette && mips_available && !m_conf.ps.shuffle;
const bool trilinear_manual = need_mipmap && GSConfig.HWMipmap;
bool bilinear = m_vt.IsLinear();
int trilinear = 0;
bool trilinear_auto = false; // Generate mipmaps if needed (basic).
bool trilinear_auto = true; // Generate mipmaps if needed (basic).
switch (GSConfig.TriFilter)
{
case TriFiltering::Forced:
@@ -6806,7 +6850,7 @@ __ri void GSRendererHW::EmulateTextureSampler(const GSTextureCache::Target* rt,
}
else if (trilinear_auto)
{
tex->m_texture->GenerateMipmapsIfNeeded();
tex->m_texture->GenerateMipmapsIfNeeded(nullptr, nullptr);
m_conf.ps.automatic_lod = 1;
}
+15 -5
View File
@@ -6220,6 +6220,8 @@ GSTextureCache::Source* GSTextureCache::CreateSource(const GIFRegTEX0& TEX0, con
// Create a cleared RT if we somehow end up with an empty source rect (because the RT isn't large enough).
const bool source_rect_empty = sRect.rempty();
const bool use_texture = (shader == ShaderConvert::COPY && !source_rect_empty);
const bool needs_lod_levels = use_texture && (lod != nullptr) && lod->y > 0;
const int lod_level = (lod != nullptr) ? (lod->y + 1) : 1;
GSVector4i region_rect = GSVector4i(0, 0, tw, th);
// Assuming everything matches up, instead of copying the target, we can just sample it directly.
@@ -6227,7 +6229,7 @@ GSTextureCache::Source* GSTextureCache::CreateSource(const GIFRegTEX0& TEX0, con
// TODO: We still need to copy if the TBW is mismatched. Except when TBW <= 1 (Jak 2).
const GSVector2i dst_texture_size = dst->m_texture->GetSize();
if (use_texture && // not reinterpreting the RT
!force_target_copy)
!force_target_copy && !needs_lod_levels)
{
// sample the target directly
src->m_texture = dst->m_texture;
@@ -6262,7 +6264,7 @@ GSTextureCache::Source* GSTextureCache::CreateSource(const GIFRegTEX0& TEX0, con
// 'src' is the new texture cache entry (hence the output)
GSTexture* sTex = dst->m_texture;
GSTexture* dTex = use_texture ?
g_gs_device->CreateTexture(new_size.x, new_size.y, 1, GSTexture::Format::Color, PreferReusedLabelledTexture()) :
g_gs_device->CreateTexture(new_size.x, new_size.y, lod_level, GSTexture::Format::Color, PreferReusedLabelledTexture()) :
g_gs_device->CreateRenderTarget(new_size.x, new_size.y, GSTexture::Format::Color, source_rect_empty || destX != 0 || destY != 0, PreferReusedLabelledTexture());
if (!dTex) [[unlikely]]
{
@@ -6280,9 +6282,17 @@ GSTextureCache::Source* GSTextureCache::CreateSource(const GIFRegTEX0& TEX0, con
{
if (dst->m_rt_alpha_scale)
{
const GSVector4 sRectF = GSVector4(sRect) / GSVector4(1, 1, sTex->GetWidth(), sTex->GetHeight());
g_gs_device->StretchRect(
sTex, sRectF, dTex, GSVector4(destX, destY, sRect.width(), sRect.height()), ShaderConvert::RTA_DECORRECTION, false);
if (!use_texture)
{
const GSVector4 sRectF = GSVector4(sRect) / GSVector4(1, 1, sTex->GetWidth(), sTex->GetHeight());
g_gs_device->StretchRect(
sTex, sRectF, dTex, GSVector4(destX, destY, sRect.width(), sRect.height()), ShaderConvert::RTA_DECORRECTION, false);
}
else
{
dst->UnscaleRTAlpha();
g_gs_device->CopyRect(sTex, dTex, sRect, destX, destY);
}
}
else
g_gs_device->CopyRect(sTex, dTex, sRect, destX, destY);
+3 -2
View File
@@ -309,6 +309,7 @@ public:
u8 m_complete_layers = 0;
bool m_target = false;
bool m_target_direct = false;
bool m_target_mips = false;
bool m_repeating = false;
bool m_valid_alpha_minmax = false;
std::pair<u8, u8> m_alpha_minmax = {0u, 255u};
@@ -455,8 +456,6 @@ protected:
std::unique_ptr<GSDownloadTexture> m_uint16_download_texture;
std::unique_ptr<GSDownloadTexture> m_uint32_download_texture;
Source* CreateSource(const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA, const GIFRegCLAMP& CLAMP, Target* t, int x_offset, int y_offset, const GSVector2i* lod, const GSVector4i* src_range, GSTexture* gpu_clut, SourceRegion region, bool force_temporary = false);
bool PreloadTarget(GIFRegTEX0 TEX0, const GSVector2i& size, const GSVector2i& valid_size, bool is_frame,
bool preload, bool preserve_target, const GSVector4i draw_rect, Target* dst, GSTextureCache::Source* src = nullptr);
@@ -508,6 +507,8 @@ public:
GSTexture* LookupPaletteSource(u32 CBP, u32 CPSM, u32 CBW, GSVector2i& offset, float* scale, const GSVector2i& size);
std::shared_ptr<Palette> LookupPaletteObject(const u32* clut, u16 pal, bool need_gs_texture);
Source* CreateSource(const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA, const GIFRegCLAMP& CLAMP, Target* t, int x_offset, int y_offset, const GSVector2i* lod, const GSVector4i* src_range, GSTexture* gpu_clut, SourceRegion region, bool force_temporary = false);
Source* LookupSource(const bool is_color, const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA, const GIFRegCLAMP& CLAMP, const GSVector4i& r, const GSVector2i* lod, const bool possible_shuffle, const bool linear, const GIFRegFRAME& frame, bool req_color = true, bool req_alpha = true);
Source* LookupDepthSource(const bool is_depth, const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA, const GIFRegCLAMP& CLAMP, const GSVector4i& r, const bool possible_shuffle, const bool linear, const GIFRegFRAME& frame, bool req_color = true, bool req_alpha = true, bool palette = false);
+1 -1
View File
@@ -311,7 +311,7 @@ void GSTextureOGL::Unmap()
}
}
void GSTextureOGL::GenerateMipmap()
void GSTextureOGL::GenerateMipmap(GSTexture* target_list[], GSVector2i offsets_list[])
{
pxAssert(m_mipmap_levels > 1);
GSDeviceOGL::GetInstance()->CommitClear(this, true);
+1 -1
View File
@@ -39,7 +39,7 @@ public:
bool Update(const GSVector4i& r, const void* data, int pitch, int layer = 0) override;
bool Map(GSMap& m, const GSVector4i* r = NULL, int layer = 0) override;
void Unmap() override;
void GenerateMipmap() override;
void GenerateMipmap(GSTexture* target_list[], GSVector2i offsets_list[]) override;
#ifdef PCSX2_DEVBUILD
void SetDebugName(std::string_view name) override;
+8 -4
View File
@@ -461,7 +461,7 @@ void GSTextureVK::Unmap()
m_needs_mipmaps_generated |= (m_map_level == 0);
}
void GSTextureVK::GenerateMipmap()
void GSTextureVK::GenerateMipmap(GSTexture* target_list[], GSVector2i offsets_list[])
{
const VkCommandBuffer cmdbuf = GetCommandBufferForUpdate();
@@ -470,7 +470,8 @@ void GSTextureVK::GenerateMipmap()
for (int dst_level = 1; dst_level < m_mipmap_levels; dst_level++)
{
const int src_level = dst_level - 1;
const bool has_target_layer = target_list && target_list[dst_level] != nullptr;
int src_level = has_target_layer ? dst_level : (dst_level - 1);
const int src_width = std::max<int>(m_size.x >> src_level, 1);
const int src_height = std::max<int>(m_size.y >> src_level, 1);
const int dst_width = std::max<int>(m_size.x >> dst_level, 1);
@@ -479,14 +480,17 @@ void GSTextureVK::GenerateMipmap()
TransitionSubresourcesToLayout(cmdbuf, src_level, 1, m_layout, Layout::TransferSrc);
TransitionSubresourcesToLayout(cmdbuf, dst_level, 1, m_layout, Layout::TransferDst);
GSVector2i offset = has_target_layer ? offsets_list[dst_level] : GSVector2i(0, 0);
src_level = has_target_layer ? 0 : src_level;
const VkImageBlit blit = {
{VK_IMAGE_ASPECT_COLOR_BIT, static_cast<u32>(src_level), 0u, 1u}, // srcSubresource
{{0, 0, 0}, {src_width, src_height, 1}}, // srcOffsets
{{offset.x, offset.y, 0}, {offset.x + src_width, offset.y + src_height, 1}}, // srcOffsets
{VK_IMAGE_ASPECT_COLOR_BIT, static_cast<u32>(dst_level), 0u, 1u}, // dstSubresource
{{0, 0, 0}, {dst_width, dst_height, 1}} // dstOffsets
};
vkCmdBlitImage(cmdbuf, m_image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, m_image,
VkImage src_image = has_target_layer ? static_cast<GSTextureVK*>(target_list[dst_level])->m_image : m_image;
vkCmdBlitImage(cmdbuf, src_image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, m_image,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &blit, VK_FILTER_LINEAR);
TransitionSubresourcesToLayout(cmdbuf, src_level, 1, Layout::TransferSrc, m_layout);
+1 -1
View File
@@ -51,7 +51,7 @@ public:
bool Update(const GSVector4i& r, const void* data, int pitch, int layer = 0) override;
bool Map(GSMap& m, const GSVector4i* r = NULL, int layer = 0) override;
void Unmap() override;
void GenerateMipmap() override;
void GenerateMipmap(GSTexture* target_list[], GSVector2i offsets_list[]) override;
#ifdef PCSX2_DEVBUILD
void SetDebugName(std::string_view name) override;