mirror of
https://github.com/doitsujin/dxvk.git
synced 2025-02-20 10:54:16 +01:00
[dxvk] Added proper support for block-compressed image formats
This commit is contained in:
parent
cd4f21a0c3
commit
c0f5b46f81
@ -421,6 +421,56 @@ namespace dxvk {
|
||||
return;
|
||||
}
|
||||
|
||||
// Upload data through a staging buffer. Special care needs to
|
||||
// be taken when dealing with compressed image formats: Rather
|
||||
// than copying pixels, we'll be copying blocks of pixels.
|
||||
const DxvkFormatInfo* formatInfo
|
||||
= imageFormatInfo(image->info().format);
|
||||
|
||||
VkExtent3D elementCount = imageExtent;
|
||||
elementCount.depth *= subresources.layerCount;
|
||||
|
||||
elementCount.width /= formatInfo->blockSize.width;
|
||||
elementCount.height /= formatInfo->blockSize.height;
|
||||
elementCount.depth /= formatInfo->blockSize.depth;
|
||||
|
||||
VkDeviceSize bytesPerRow = elementCount.width * formatInfo->elementSize;
|
||||
VkDeviceSize bytesPerLayer = elementCount.height * bytesPerRow;
|
||||
VkDeviceSize bytesTotal = elementCount.depth * bytesPerLayer;
|
||||
|
||||
// Allocate staging buffer memory for the image data. The
|
||||
// pixels or blocks will be tightly packed within the buffer.
|
||||
DxvkStagingBufferSlice slice = m_cmd->stagedAlloc(bytesTotal);
|
||||
|
||||
auto dstData = reinterpret_cast<char*>(slice.mapPtr);
|
||||
auto srcData = reinterpret_cast<const char*>(data);
|
||||
|
||||
// If the application provides tightly packed data as well,
|
||||
// we can minimize the number of memcpy calls in order to
|
||||
// improve performance.
|
||||
bool useDirectCopy = true;
|
||||
|
||||
useDirectCopy &= (pitchPerLayer == bytesPerLayer) || (elementCount.depth == 1);
|
||||
useDirectCopy &= (pitchPerRow == bytesPerRow) || (elementCount.height == 1);
|
||||
|
||||
if (useDirectCopy) {
|
||||
std::memcpy(dstData, srcData, bytesTotal);
|
||||
} else {
|
||||
for (uint32_t i = 0; i < elementCount.depth; i++) {
|
||||
for (uint32_t j = 0; j < elementCount.height; j++) {
|
||||
std::memcpy(dstData, srcData, bytesPerRow);
|
||||
|
||||
dstData += bytesPerRow;
|
||||
srcData += pitchPerRow;
|
||||
}
|
||||
|
||||
dstData += bytesPerLayer;
|
||||
srcData += pitchPerLayer;
|
||||
}
|
||||
}
|
||||
|
||||
// Prepare the image layout. If the given extent covers
|
||||
// the entire image, we may discard its previous contents.
|
||||
VkImageSubresourceRange subresourceRange;
|
||||
subresourceRange.aspectMask = subresources.aspectMask;
|
||||
subresourceRange.baseMipLevel = subresources.mipLevel;
|
||||
@ -440,39 +490,9 @@ namespace dxvk {
|
||||
VK_ACCESS_TRANSFER_WRITE_BIT);
|
||||
m_barriers.recordCommands(m_cmd);
|
||||
|
||||
// TODO support block formats properly
|
||||
const DxvkFormatInfo* formatInfo
|
||||
= imageFormatInfo(image->info().format);
|
||||
|
||||
const VkDeviceSize layerCount = imageExtent.depth * subresources.layerCount;
|
||||
VkDeviceSize bytesPerRow = imageExtent.width * formatInfo->elementSize;
|
||||
VkDeviceSize bytesPerLayer = imageExtent.height * bytesPerRow;
|
||||
VkDeviceSize bytesTotal = layerCount * bytesPerLayer;
|
||||
|
||||
auto slice = m_cmd->stagedAlloc(bytesTotal);
|
||||
auto dstData = reinterpret_cast<char*>(slice.mapPtr);
|
||||
auto srcData = reinterpret_cast<const char*>(data);
|
||||
|
||||
bool useDirectCopy = true;
|
||||
useDirectCopy &= (pitchPerLayer == bytesPerLayer) || layerCount == 1;
|
||||
useDirectCopy &= (pitchPerRow == bytesPerRow) || imageExtent.height == 1;
|
||||
|
||||
if (useDirectCopy) {
|
||||
std::memcpy(dstData, srcData, bytesTotal);
|
||||
} else {
|
||||
for (uint32_t i = 0; i < layerCount; i++) {
|
||||
for (uint32_t j = 0; j < imageExtent.height; j++) {
|
||||
std::memcpy(dstData, srcData, bytesPerRow);
|
||||
|
||||
dstData += bytesPerRow;
|
||||
srcData += pitchPerRow;
|
||||
}
|
||||
|
||||
dstData += bytesPerLayer;
|
||||
srcData += pitchPerLayer;
|
||||
}
|
||||
}
|
||||
|
||||
// Copy contents of the staging buffer into the image.
|
||||
// Since our source data is tightly packed, we do not
|
||||
// need to specify any strides.
|
||||
VkBufferImageCopy region;
|
||||
region.bufferOffset = slice.offset;
|
||||
region.bufferRowLength = 0;
|
||||
@ -485,6 +505,7 @@ namespace dxvk {
|
||||
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
||||
region, slice);
|
||||
|
||||
// Transition image back into its optimal layout
|
||||
m_barriers.accessImage(
|
||||
image, subresourceRange,
|
||||
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
||||
|
@ -4,7 +4,7 @@ namespace dxvk {
|
||||
|
||||
const std::array<DxvkFormatInfo, 147> g_formatInfos = {{
|
||||
// VK_FORMAT_UNDEFINED
|
||||
{ 0, 0 },
|
||||
{ },
|
||||
|
||||
// VK_FORMAT_R4G4_UNORM_PACK8
|
||||
{ 1, VK_IMAGE_ASPECT_COLOR_BIT },
|
||||
@ -397,52 +397,84 @@ namespace dxvk {
|
||||
{ 0, VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT },
|
||||
|
||||
// VK_FORMAT_BC1_RGB_UNORM_BLOCK
|
||||
{ 0, VK_IMAGE_ASPECT_COLOR_BIT },
|
||||
{ 8, VK_IMAGE_ASPECT_COLOR_BIT,
|
||||
DxvkFormatFlag::BlockCompressed,
|
||||
VkExtent3D { 4, 4, 1 } },
|
||||
|
||||
// VK_FORMAT_BC1_RGB_SRGB_BLOCK
|
||||
{ 0, VK_IMAGE_ASPECT_COLOR_BIT },
|
||||
{ 8, VK_IMAGE_ASPECT_COLOR_BIT,
|
||||
DxvkFormatFlag::BlockCompressed,
|
||||
VkExtent3D { 4, 4, 1 } },
|
||||
|
||||
// VK_FORMAT_BC1_RGBA_UNORM_BLOCK
|
||||
{ 0, VK_IMAGE_ASPECT_COLOR_BIT },
|
||||
{ 8, VK_IMAGE_ASPECT_COLOR_BIT,
|
||||
DxvkFormatFlag::BlockCompressed,
|
||||
VkExtent3D { 4, 4, 1 } },
|
||||
|
||||
// VK_FORMAT_BC1_RGBA_SRGB_BLOCK
|
||||
{ 0, VK_IMAGE_ASPECT_COLOR_BIT },
|
||||
{ 8, VK_IMAGE_ASPECT_COLOR_BIT,
|
||||
DxvkFormatFlag::BlockCompressed,
|
||||
VkExtent3D { 4, 4, 1 } },
|
||||
|
||||
// VK_FORMAT_BC2_UNORM_BLOCK
|
||||
{ 0, VK_IMAGE_ASPECT_COLOR_BIT },
|
||||
{ 16, VK_IMAGE_ASPECT_COLOR_BIT,
|
||||
DxvkFormatFlag::BlockCompressed,
|
||||
VkExtent3D { 4, 4, 1 } },
|
||||
|
||||
// VK_FORMAT_BC2_SRGB_BLOCK
|
||||
{ 0, VK_IMAGE_ASPECT_COLOR_BIT },
|
||||
{ 16, VK_IMAGE_ASPECT_COLOR_BIT,
|
||||
DxvkFormatFlag::BlockCompressed,
|
||||
VkExtent3D { 4, 4, 1 } },
|
||||
|
||||
// VK_FORMAT_BC3_UNORM_BLOCK
|
||||
{ 0, VK_IMAGE_ASPECT_COLOR_BIT },
|
||||
{ 16, VK_IMAGE_ASPECT_COLOR_BIT,
|
||||
DxvkFormatFlag::BlockCompressed,
|
||||
VkExtent3D { 4, 4, 1 } },
|
||||
|
||||
// VK_FORMAT_BC3_SRGB_BLOCK
|
||||
{ 0, VK_IMAGE_ASPECT_COLOR_BIT },
|
||||
{ 16, VK_IMAGE_ASPECT_COLOR_BIT,
|
||||
DxvkFormatFlag::BlockCompressed,
|
||||
VkExtent3D { 4, 4, 1 } },
|
||||
|
||||
// VK_FORMAT_BC4_UNORM_BLOCK
|
||||
{ 0, VK_IMAGE_ASPECT_COLOR_BIT },
|
||||
{ 8, VK_IMAGE_ASPECT_COLOR_BIT,
|
||||
DxvkFormatFlag::BlockCompressed,
|
||||
VkExtent3D { 4, 4, 1 } },
|
||||
|
||||
// VK_FORMAT_BC4_SNORM_BLOCK
|
||||
{ 0, VK_IMAGE_ASPECT_COLOR_BIT },
|
||||
{ 8, VK_IMAGE_ASPECT_COLOR_BIT,
|
||||
DxvkFormatFlag::BlockCompressed,
|
||||
VkExtent3D { 4, 4, 1 } },
|
||||
|
||||
// VK_FORMAT_BC5_UNORM_BLOCK
|
||||
{ 0, VK_IMAGE_ASPECT_COLOR_BIT },
|
||||
{ 16, VK_IMAGE_ASPECT_COLOR_BIT,
|
||||
DxvkFormatFlag::BlockCompressed,
|
||||
VkExtent3D { 4, 4, 1 } },
|
||||
|
||||
// VK_FORMAT_BC5_SNORM_BLOCK
|
||||
{ 0, VK_IMAGE_ASPECT_COLOR_BIT },
|
||||
{ 16, VK_IMAGE_ASPECT_COLOR_BIT,
|
||||
DxvkFormatFlag::BlockCompressed,
|
||||
VkExtent3D { 4, 4, 1 } },
|
||||
|
||||
// VK_FORMAT_BC6H_UFLOAT_BLOCK
|
||||
{ 0, VK_IMAGE_ASPECT_COLOR_BIT },
|
||||
{ 16, VK_IMAGE_ASPECT_COLOR_BIT,
|
||||
DxvkFormatFlag::BlockCompressed,
|
||||
VkExtent3D { 4, 4, 1 } },
|
||||
|
||||
// VK_FORMAT_BC6H_SFLOAT_BLOCK
|
||||
{ 0, VK_IMAGE_ASPECT_COLOR_BIT },
|
||||
{ 16, VK_IMAGE_ASPECT_COLOR_BIT,
|
||||
DxvkFormatFlag::BlockCompressed,
|
||||
VkExtent3D { 4, 4, 1 } },
|
||||
|
||||
// VK_FORMAT_BC7_UNORM_BLOCK
|
||||
{ 0, VK_IMAGE_ASPECT_COLOR_BIT },
|
||||
{ 16, VK_IMAGE_ASPECT_COLOR_BIT,
|
||||
DxvkFormatFlag::BlockCompressed,
|
||||
VkExtent3D { 4, 4, 1 } },
|
||||
|
||||
// VK_FORMAT_BC7_SRGB_BLOCK
|
||||
{ 0, VK_IMAGE_ASPECT_COLOR_BIT },
|
||||
{ 16, VK_IMAGE_ASPECT_COLOR_BIT,
|
||||
DxvkFormatFlag::BlockCompressed,
|
||||
VkExtent3D { 4, 4, 1 } },
|
||||
}};
|
||||
|
||||
const DxvkFormatInfo* imageFormatInfo(VkFormat format) {
|
||||
|
@ -4,6 +4,12 @@
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
enum class DxvkFormatFlag {
|
||||
BlockCompressed,
|
||||
};
|
||||
|
||||
using DxvkFormatFlags = Flags<DxvkFormatFlag>;
|
||||
|
||||
/**
|
||||
* \brief Format info structure
|
||||
*
|
||||
@ -11,14 +17,23 @@ namespace dxvk {
|
||||
* about a Vulkan image format.
|
||||
*/
|
||||
struct DxvkFormatInfo {
|
||||
/// Size of an element in this format
|
||||
VkDeviceSize elementSize;
|
||||
/// Size of an element in this format. For compressed
|
||||
/// formats, this is the size of a block, in bytes.
|
||||
VkDeviceSize elementSize = 0;
|
||||
|
||||
/// Available image aspect flags
|
||||
VkImageAspectFlags aspectMask;
|
||||
VkImageAspectFlags aspectMask = 0;
|
||||
|
||||
/// Some other format info flags
|
||||
DxvkFormatFlags flags = 0;
|
||||
|
||||
/// Size, in pixels, of a compressed block. For
|
||||
/// non-block formats, all these values are 1.
|
||||
VkExtent3D blockSize = { 1, 1, 1 };
|
||||
};
|
||||
|
||||
|
||||
|
||||
const DxvkFormatInfo* imageFormatInfo(VkFormat format);
|
||||
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user