Skip to content

Commit

Permalink
GPUDevice: Support compressed textures
Browse files Browse the repository at this point in the history
  • Loading branch information
stenzek committed Nov 24, 2024
1 parent 24dfd30 commit 7eb1d4e
Show file tree
Hide file tree
Showing 18 changed files with 841 additions and 196 deletions.
7 changes: 7 additions & 0 deletions src/util/d3d11_device.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,13 @@ void D3D11Device::SetFeatures(FeatureMask disabled_features)
(SUCCEEDED(m_device->CheckFeatureSupport(D3D11_FEATURE_D3D11_OPTIONS2, &data, sizeof(data))) &&
data.ROVsSupported);
}

m_features.dxt_textures =
(!(disabled_features & FEATURE_MASK_COMPRESSED_TEXTURES) &&
(SupportsTextureFormat(GPUTexture::Format::BC1) && SupportsTextureFormat(GPUTexture::Format::BC2) &&
SupportsTextureFormat(GPUTexture::Format::BC3)));
m_features.bptc_textures =
(!(disabled_features & FEATURE_MASK_COMPRESSED_TEXTURES) && SupportsTextureFormat(GPUTexture::Format::BC7));
}

D3D11SwapChain::D3D11SwapChain(const WindowInfo& wi, GPUVSyncMode vsync_mode, bool allow_present_throttle,
Expand Down
27 changes: 18 additions & 9 deletions src/util/d3d11_texture.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -147,23 +147,24 @@ bool D3D11Texture::Update(u32 x, u32 y, u32 width, u32 height, const void* data,
if (HasFlag(Flags::AllowMap))
{
void* map;
u32 map_stride;
if (!Map(&map, &map_stride, x, y, width, height, layer, level))
u32 map_pitch;
if (!Map(&map, &map_pitch, x, y, width, height, layer, level))
return false;

StringUtil::StrideMemCpy(map, map_stride, data, pitch, GetPixelSize() * width, height);
CopyTextureDataForUpload(width, height, m_format, map, map_pitch, data, pitch);
Unmap();
return true;
}

const CD3D11_BOX box(static_cast<LONG>(x), static_cast<LONG>(y), 0, static_cast<LONG>(x + width),
static_cast<LONG>(y + height), 1);
const u32 bs = GetBlockSize();
const D3D11_BOX box = {Common::AlignDownPow2(x, bs), Common::AlignDownPow2(y, bs), 0U,
Common::AlignUpPow2(x + width, bs), Common::AlignUpPow2(y + height, bs), 1U};
const u32 srnum = D3D11CalcSubresource(level, layer, m_levels);

ID3D11DeviceContext1* context = D3D11Device::GetD3DContext();
CommitClear(context);

GPUDevice::GetStatistics().buffer_streamed += height * pitch;
GPUDevice::GetStatistics().buffer_streamed += CalcUploadSize(height, pitch);
GPUDevice::GetStatistics().num_uploads++;

context->UpdateSubresource(m_texture.Get(), srnum, &box, data, pitch, 0);
Expand Down Expand Up @@ -194,10 +195,18 @@ bool D3D11Texture::Map(void** map, u32* map_stride, u32 x, u32 y, u32 width, u32
return false;
}

GPUDevice::GetStatistics().buffer_streamed += height * sr.RowPitch;
GPUDevice::GetStatistics().buffer_streamed += CalcUploadSize(height, sr.RowPitch);
GPUDevice::GetStatistics().num_uploads++;

*map = static_cast<u8*>(sr.pData) + (y * sr.RowPitch) + (x * GetPixelSize());
if (IsCompressedFormat(m_format))
{
*map = static_cast<u8*>(sr.pData) + ((y / GetBlockSize()) * sr.RowPitch) +
((x / GetBlockSize()) * GetPixelSize());
}
else
{
*map = static_cast<u8*>(sr.pData) + (y * sr.RowPitch) + (x * GetPixelSize());
}
*map_stride = sr.RowPitch;
m_mapped_subresource = srnum;
m_state = GPUTexture::State::Dirty;
Expand Down Expand Up @@ -294,7 +303,7 @@ std::unique_ptr<D3D11Texture> D3D11Texture::Create(ID3D11Device* device, u32 wid

if (initial_data)
{
GPUDevice::GetStatistics().buffer_streamed += height * initial_data_stride;
GPUDevice::GetStatistics().buffer_streamed += CalcUploadSize(format, height, initial_data_stride);
GPUDevice::GetStatistics().num_uploads++;
}

Expand Down
7 changes: 7 additions & 0 deletions src/util/d3d12_device.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1366,6 +1366,13 @@ void D3D12Device::SetFeatures(D3D_FEATURE_LEVEL feature_level, FeatureMask disab
SUCCEEDED(m_device->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS, &options, sizeof(options))) &&
options.ROVsSupported;
}

m_features.dxt_textures =
(!(disabled_features & FEATURE_MASK_COMPRESSED_TEXTURES) &&
(SupportsTextureFormat(GPUTexture::Format::BC1) && SupportsTextureFormat(GPUTexture::Format::BC2) &&
SupportsTextureFormat(GPUTexture::Format::BC3)));
m_features.bptc_textures =
(!(disabled_features & FEATURE_MASK_COMPRESSED_TEXTURES) && SupportsTextureFormat(GPUTexture::Format::BC7));
}

void D3D12Device::CopyTextureRegion(GPUTexture* dst, u32 dst_x, u32 dst_y, u32 dst_layer, u32 dst_level,
Expand Down
42 changes: 21 additions & 21 deletions src/util/d3d12_texture.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -340,24 +340,24 @@ ID3D12GraphicsCommandList4* D3D12Texture::GetCommandBufferForUpdate()
return dev.GetInitCommandList();
}

void D3D12Texture::CopyTextureDataForUpload(void* dst, const void* src, u32 width, u32 height, u32 pitch,
u32 upload_pitch) const
{
StringUtil::StrideMemCpy(dst, upload_pitch, src, pitch, GetPixelSize() * width, height);
}

ID3D12Resource* D3D12Texture::AllocateUploadStagingBuffer(const void* data, u32 pitch, u32 upload_pitch, u32 width,
u32 height) const
u32 height, u32 buffer_size) const
{
const u32 size = upload_pitch * height;
ComPtr<ID3D12Resource> resource;
ComPtr<D3D12MA::Allocation> allocation;

const D3D12MA::ALLOCATION_DESC allocation_desc = {D3D12MA::ALLOCATION_FLAG_NONE, D3D12_HEAP_TYPE_UPLOAD,
D3D12_HEAP_FLAG_NONE, nullptr, nullptr};
const D3D12_RESOURCE_DESC resource_desc = {
D3D12_RESOURCE_DIMENSION_BUFFER, 0, size, 1, 1, 1, DXGI_FORMAT_UNKNOWN, {1, 0}, D3D12_TEXTURE_LAYOUT_ROW_MAJOR,
D3D12_RESOURCE_FLAG_NONE};
const D3D12_RESOURCE_DESC resource_desc = {D3D12_RESOURCE_DIMENSION_BUFFER,
0,
buffer_size,
1,
1,
1,
DXGI_FORMAT_UNKNOWN,
{1, 0},
D3D12_TEXTURE_LAYOUT_ROW_MAJOR,
D3D12_RESOURCE_FLAG_NONE};
HRESULT hr = D3D12Device::GetInstance().GetAllocator()->CreateResource(
&allocation_desc, &resource_desc, D3D12_RESOURCE_STATE_GENERIC_READ, nullptr, allocation.GetAddressOf(),
IID_PPV_ARGS(resource.GetAddressOf()));
Expand All @@ -375,9 +375,9 @@ ID3D12Resource* D3D12Texture::AllocateUploadStagingBuffer(const void* data, u32
return nullptr;
}

CopyTextureDataForUpload(map_ptr, data, width, height, pitch, upload_pitch);
CopyTextureDataForUpload(width, height, m_format, map_ptr, upload_pitch, data, pitch);

const D3D12_RANGE write_range = {0, size};
const D3D12_RANGE write_range = {0, buffer_size};
resource->Unmap(0, &write_range);

// Immediately queue it for freeing after the command buffer finishes, since it's only needed for the copy.
Expand All @@ -395,8 +395,8 @@ bool D3D12Texture::Update(u32 x, u32 y, u32 width, u32 height, const void* data,
D3D12Device& dev = D3D12Device::GetInstance();
D3D12StreamBuffer& sbuffer = dev.GetTextureUploadBuffer();

const u32 upload_pitch = Common::AlignUpPow2<u32>(pitch, D3D12_TEXTURE_DATA_PITCH_ALIGNMENT);
const u32 required_size = height * upload_pitch;
const u32 upload_pitch = Common::AlignUpPow2<u32>(CalcUploadPitch(width), D3D12_TEXTURE_DATA_PITCH_ALIGNMENT);
const u32 required_size = CalcUploadSize(height, upload_pitch);

D3D12_TEXTURE_COPY_LOCATION srcloc;
srcloc.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT;
Expand All @@ -410,7 +410,7 @@ bool D3D12Texture::Update(u32 x, u32 y, u32 width, u32 height, const void* data,
// Otherwise allocation will either fail, or require lots of cmdbuffer submissions.
if (required_size > (sbuffer.GetSize() / 2))
{
srcloc.pResource = AllocateUploadStagingBuffer(data, pitch, upload_pitch, width, height);
srcloc.pResource = AllocateUploadStagingBuffer(data, pitch, upload_pitch, width, height, required_size);
if (!srcloc.pResource)
return false;

Expand All @@ -431,7 +431,7 @@ bool D3D12Texture::Update(u32 x, u32 y, u32 width, u32 height, const void* data,

srcloc.pResource = sbuffer.GetBuffer();
srcloc.PlacedFootprint.Offset = sbuffer.GetCurrentOffset();
CopyTextureDataForUpload(sbuffer.GetCurrentHostPointer(), data, width, height, pitch, upload_pitch);
CopyTextureDataForUpload(width, height, m_format, sbuffer.GetCurrentHostPointer(), upload_pitch, data, pitch);
sbuffer.CommitMemory(required_size);
}

Expand Down Expand Up @@ -482,8 +482,8 @@ bool D3D12Texture::Map(void** map, u32* map_stride, u32 x, u32 y, u32 width, u32
CommitClear(GetCommandBufferForUpdate());

// see note in Update() for the reason why.
const u32 aligned_pitch = Common::AlignUpPow2(width * GetPixelSize(), D3D12_TEXTURE_DATA_PITCH_ALIGNMENT);
const u32 req_size = height * aligned_pitch;
const u32 aligned_pitch = Common::AlignUpPow2(CalcUploadPitch(m_width), D3D12_TEXTURE_DATA_PITCH_ALIGNMENT);
const u32 req_size = CalcUploadSize(m_height, aligned_pitch);
D3D12StreamBuffer& buffer = dev.GetTextureUploadBuffer();
if (req_size >= (buffer.GetSize() / 2))
return false;
Expand Down Expand Up @@ -512,8 +512,8 @@ void D3D12Texture::Unmap()
{
D3D12Device& dev = D3D12Device::GetInstance();
D3D12StreamBuffer& sb = dev.GetTextureUploadBuffer();
const u32 aligned_pitch = Common::AlignUpPow2(m_map_width * GetPixelSize(), D3D12_TEXTURE_DATA_PITCH_ALIGNMENT);
const u32 req_size = m_map_height * aligned_pitch;
const u32 aligned_pitch = Common::AlignUpPow2(CalcUploadPitch(m_width), D3D12_TEXTURE_DATA_PITCH_ALIGNMENT);
const u32 req_size = CalcUploadSize(m_map_height, aligned_pitch);
const u32 offset = sb.GetCurrentOffset();
sb.CommitMemory(req_size);

Expand Down
3 changes: 1 addition & 2 deletions src/util/d3d12_texture.h
Original file line number Diff line number Diff line change
Expand Up @@ -80,8 +80,7 @@ class D3D12Texture final : public GPUTexture

ID3D12GraphicsCommandList4* GetCommandBufferForUpdate();
ID3D12Resource* AllocateUploadStagingBuffer(const void* data, u32 pitch, u32 upload_pitch, u32 width,
u32 height) const;
void CopyTextureDataForUpload(void* dst, const void* src, u32 width, u32 height, u32 pitch, u32 upload_pitch) const;
u32 height, u32 buffer_size) const;
void ActuallyCommitClear(ID3D12GraphicsCommandList* cmdlist);

ComPtr<ID3D12Resource> m_resource;
Expand Down
4 changes: 4 additions & 0 deletions src/util/d3d_common.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -650,6 +650,10 @@ static constexpr std::array<D3DCommon::DXGIFormatMapping, static_cast<int>(GPUTe
{DXGI_FORMAT_R16G16B16A16_FLOAT, DXGI_FORMAT_R16G16B16A16_FLOAT, DXGI_FORMAT_R16G16B16A16_FLOAT, DXGI_FORMAT_UNKNOWN }, // RGBA16F
{DXGI_FORMAT_R32G32B32A32_FLOAT, DXGI_FORMAT_R32G32B32A32_FLOAT, DXGI_FORMAT_R32G32B32A32_FLOAT, DXGI_FORMAT_UNKNOWN }, // RGBA32F
{DXGI_FORMAT_R10G10B10A2_UNORM, DXGI_FORMAT_R10G10B10A2_UNORM, DXGI_FORMAT_R10G10B10A2_UNORM, DXGI_FORMAT_UNKNOWN }, // RGB10A2
{DXGI_FORMAT_BC1_UNORM, DXGI_FORMAT_BC1_UNORM, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN }, // BC1
{DXGI_FORMAT_BC2_UNORM, DXGI_FORMAT_BC2_UNORM, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN }, // BC2
{DXGI_FORMAT_BC3_UNORM, DXGI_FORMAT_BC3_UNORM, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN }, // BC3
{DXGI_FORMAT_BC7_UNORM, DXGI_FORMAT_BC7_UNORM, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN }, // BC7
// clang-format on
}};

Expand Down
16 changes: 15 additions & 1 deletion src/util/gpu_device.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1057,8 +1057,22 @@ std::unique_ptr<GPUTexture> GPUDevice::FetchAndUploadTextureImage(const Image& i
{
const Image* image_to_upload = &image;
GPUTexture::Format gpu_format = GPUTexture::GetTextureFormatForImageFormat(image.GetFormat());
bool gpu_format_supported;

// avoid device query for compressed formats that we've already pretested
if (gpu_format >= GPUTexture::Format::BC1 && gpu_format <= GPUTexture::Format::BC3)
gpu_format_supported = m_features.dxt_textures;
else if (gpu_format == GPUTexture::Format::BC7)
gpu_format_supported = m_features.bptc_textures;
else if (gpu_format == GPUTexture::Format::RGBA8) // always supported
gpu_format_supported = true;
else if (gpu_format != GPUTexture::Format::Unknown)
gpu_format_supported = SupportsTextureFormat(gpu_format);
else
gpu_format_supported = false;

std::optional<Image> converted_image;
if (!SupportsTextureFormat(gpu_format))
if (!gpu_format_supported)
{
converted_image = image.ConvertToRGBA8(error);
if (!converted_image.has_value())
Expand Down
3 changes: 3 additions & 0 deletions src/util/gpu_device.h
Original file line number Diff line number Diff line change
Expand Up @@ -515,6 +515,7 @@ class GPUDevice
FEATURE_MASK_TEXTURE_COPY_TO_SELF = (1 << 6),
FEATURE_MASK_MEMORY_IMPORT = (1 << 7),
FEATURE_MASK_RASTER_ORDER_VIEWS = (1 << 8),
FEATURE_MASK_COMPRESSED_TEXTURES = (1 << 9),
};

enum class DrawBarrier : u32
Expand Down Expand Up @@ -553,6 +554,8 @@ class GPUDevice
bool pipeline_cache : 1;
bool prefer_unused_textures : 1;
bool raster_order_views : 1;
bool dxt_textures : 1;
bool bptc_textures : 1;
};

struct Statistics
Expand Down
Loading

0 comments on commit 7eb1d4e

Please sign in to comment.