crossxtex/DirectXTex/DirectXTexCompressGPU.cpp

421 lines
12 KiB
C++
Raw Normal View History

2016-08-22 18:26:36 +00:00
//-------------------------------------------------------------------------------------
// DirectXTexCompressGPU.cpp
//
// DirectX Texture Library - DirectCompute-based texture compression
//
// Copyright (c) Microsoft Corporation. All rights reserved.
2018-02-24 06:24:46 +00:00
// Licensed under the MIT License.
2016-08-22 18:26:36 +00:00
//
// http://go.microsoft.com/fwlink/?LinkId=248926
//-------------------------------------------------------------------------------------
2018-06-13 01:07:34 +00:00
#include "DirectXTexp.h"
2016-08-22 18:26:36 +00:00
#include "BCDirectCompute.h"
2016-08-22 18:26:36 +00:00
2016-09-09 02:09:46 +00:00
using namespace DirectX;
2016-08-22 18:26:36 +00:00
2016-09-09 02:09:46 +00:00
namespace
2016-08-22 18:26:36 +00:00
{
2016-09-09 02:09:46 +00:00
inline DWORD GetSRGBFlags(_In_ DWORD compress)
2016-08-22 18:26:36 +00:00
{
2017-07-12 07:56:51 +00:00
static_assert(static_cast<int>(TEX_COMPRESS_SRGB_IN) == static_cast<int>(TEX_FILTER_SRGB_IN), "TEX_COMPRESS_SRGB* should match TEX_FILTER_SRGB*");
static_assert(static_cast<int>(TEX_COMPRESS_SRGB_OUT) == static_cast<int>(TEX_FILTER_SRGB_OUT), "TEX_COMPRESS_SRGB* should match TEX_FILTER_SRGB*");
static_assert(static_cast<int>(TEX_COMPRESS_SRGB) == static_cast<int>(TEX_FILTER_SRGB), "TEX_COMPRESS_SRGB* should match TEX_FILTER_SRGB*");
2016-09-09 02:09:46 +00:00
return (compress & TEX_COMPRESS_SRGB);
2016-08-22 18:26:36 +00:00
}
2016-09-09 02:09:46 +00:00
//-------------------------------------------------------------------------------------
// Converts to R8G8B8A8_UNORM or R8G8B8A8_UNORM_SRGB doing any conversion logic needed
//-------------------------------------------------------------------------------------
HRESULT ConvertToRGBA32(
const Image& srcImage,
ScratchImage& image,
bool srgb,
DWORD filter)
2016-08-22 18:26:36 +00:00
{
2016-09-09 02:09:46 +00:00
if (!srcImage.pixels)
return E_POINTER;
2016-08-22 18:26:36 +00:00
2016-09-09 02:09:46 +00:00
DXGI_FORMAT format = srgb ? DXGI_FORMAT_R8G8B8A8_UNORM_SRGB : DXGI_FORMAT_R8G8B8A8_UNORM;
HRESULT hr = image.Initialize2D(format, srcImage.width, srcImage.height, 1, 1);
if (FAILED(hr))
return hr;
const Image *img = image.GetImage(0, 0, 0);
if (!img)
2016-08-22 18:26:36 +00:00
{
image.Release();
2016-09-09 02:09:46 +00:00
return E_POINTER;
2016-08-22 18:26:36 +00:00
}
2016-09-09 02:09:46 +00:00
uint8_t* pDest = img->pixels;
if (!pDest)
2016-08-22 18:26:36 +00:00
{
image.Release();
2016-09-09 02:09:46 +00:00
return E_POINTER;
2016-08-22 18:26:36 +00:00
}
2018-03-29 19:00:16 +00:00
ScopedAlignedArrayXMVECTOR scanline(static_cast<XMVECTOR*>(_aligned_malloc((sizeof(XMVECTOR) * srcImage.width), 16)));
2016-09-09 02:09:46 +00:00
if (!scanline)
{
image.Release();
return E_OUTOFMEMORY;
}
2016-08-22 18:26:36 +00:00
2016-09-09 02:09:46 +00:00
const uint8_t *pSrc = srcImage.pixels;
for (size_t h = 0; h < srcImage.height; ++h)
{
if (!_LoadScanline(scanline.get(), srcImage.width, pSrc, srcImage.rowPitch, srcImage.format))
{
image.Release();
return E_FAIL;
}
2016-08-22 18:26:36 +00:00
2016-09-09 02:09:46 +00:00
_ConvertScanline(scanline.get(), srcImage.width, format, srcImage.format, filter);
2016-08-22 18:26:36 +00:00
2016-09-09 02:09:46 +00:00
if (!_StoreScanline(pDest, img->rowPitch, format, scanline.get(), srcImage.width))
{
image.Release();
return E_FAIL;
}
2016-08-22 18:26:36 +00:00
2016-09-09 02:09:46 +00:00
pSrc += srcImage.rowPitch;
pDest += img->rowPitch;
}
2016-08-22 18:26:36 +00:00
2016-09-09 02:09:46 +00:00
return S_OK;
2016-08-22 18:26:36 +00:00
}
2016-09-09 02:09:46 +00:00
//-------------------------------------------------------------------------------------
// Converts to DXGI_FORMAT_R32G32B32A32_FLOAT doing any conversion logic needed
//-------------------------------------------------------------------------------------
HRESULT ConvertToRGBAF32(
const Image& srcImage,
ScratchImage& image,
DWORD filter)
2016-08-22 18:26:36 +00:00
{
2016-09-09 02:09:46 +00:00
if (!srcImage.pixels)
return E_POINTER;
HRESULT hr = image.Initialize2D(DXGI_FORMAT_R32G32B32A32_FLOAT, srcImage.width, srcImage.height, 1, 1);
if (FAILED(hr))
return hr;
const Image *img = image.GetImage(0, 0, 0);
if (!img)
2016-08-22 18:26:36 +00:00
{
image.Release();
2016-09-09 02:09:46 +00:00
return E_POINTER;
2016-08-22 18:26:36 +00:00
}
2016-09-09 02:09:46 +00:00
uint8_t* pDest = img->pixels;
if (!pDest)
{
image.Release();
return E_POINTER;
}
2016-08-22 18:26:36 +00:00
2016-09-09 02:09:46 +00:00
const uint8_t *pSrc = srcImage.pixels;
for (size_t h = 0; h < srcImage.height; ++h)
{
if (!_LoadScanline(reinterpret_cast<XMVECTOR*>(pDest), srcImage.width, pSrc, srcImage.rowPitch, srcImage.format))
{
image.Release();
return E_FAIL;
}
2016-08-22 18:26:36 +00:00
2016-09-09 02:09:46 +00:00
_ConvertScanline(reinterpret_cast<XMVECTOR*>(pDest), srcImage.width, DXGI_FORMAT_R32G32B32A32_FLOAT, srcImage.format, filter);
2016-08-22 18:26:36 +00:00
2016-09-09 02:09:46 +00:00
pSrc += srcImage.rowPitch;
pDest += img->rowPitch;
}
2016-08-22 18:26:36 +00:00
2016-09-09 02:09:46 +00:00
return S_OK;
}
2016-08-22 18:26:36 +00:00
2016-09-09 02:09:46 +00:00
//-------------------------------------------------------------------------------------
// Compress using GPU, converting to the proper input format for the shader if needed
//-------------------------------------------------------------------------------------
inline HRESULT GPUCompress(
_In_ GPUCompressBC* gpubc,
const Image& srcImage,
const Image& destImage,
DWORD compress)
2016-08-22 18:26:36 +00:00
{
2016-09-09 02:09:46 +00:00
if (!gpubc)
return E_POINTER;
2016-08-22 18:26:36 +00:00
2016-09-09 02:09:46 +00:00
assert(srcImage.pixels && destImage.pixels);
2016-08-22 18:26:36 +00:00
2016-09-09 02:09:46 +00:00
DXGI_FORMAT format = gpubc->GetSourceFormat();
if (srcImage.format == format)
{
// Input is already in our required source format
return gpubc->Compress(srcImage, destImage);
}
else
2016-08-22 18:26:36 +00:00
{
2016-09-09 02:09:46 +00:00
// Convert format and then use as the source image
ScratchImage image;
2018-03-29 19:00:16 +00:00
HRESULT hr = E_UNEXPECTED;
2016-08-22 18:26:36 +00:00
2016-09-09 02:09:46 +00:00
DWORD srgb = GetSRGBFlags(compress);
2016-08-22 18:26:36 +00:00
2016-09-09 02:09:46 +00:00
switch (format)
{
case DXGI_FORMAT_R8G8B8A8_UNORM:
hr = ConvertToRGBA32(srcImage, image, false, srgb);
break;
2016-08-22 18:26:36 +00:00
2016-09-09 02:09:46 +00:00
case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB:
hr = ConvertToRGBA32(srcImage, image, true, srgb);
break;
2016-08-22 18:26:36 +00:00
2016-09-09 02:09:46 +00:00
case DXGI_FORMAT_R32G32B32A32_FLOAT:
hr = ConvertToRGBAF32(srcImage, image, srgb);
break;
2016-08-22 18:26:36 +00:00
2016-09-09 02:09:46 +00:00
default:
break;
}
2016-08-22 18:26:36 +00:00
2016-09-09 02:09:46 +00:00
if (FAILED(hr))
return hr;
2016-08-22 18:26:36 +00:00
2016-09-09 02:09:46 +00:00
const Image *img = image.GetImage(0, 0, 0);
if (!img)
return E_POINTER;
return gpubc->Compress(*img, destImage);
}
}
};
2016-08-22 18:26:36 +00:00
//=====================================================================================
// Entry-points
//=====================================================================================
//-------------------------------------------------------------------------------------
// Compression
//-------------------------------------------------------------------------------------
_Use_decl_annotations_
2016-09-09 02:09:46 +00:00
HRESULT DirectX::Compress(
ID3D11Device* pDevice,
const Image& srcImage,
DXGI_FORMAT format,
DWORD compress,
float alphaWeight,
ScratchImage& image)
2016-08-22 18:26:36 +00:00
{
2016-09-09 02:09:46 +00:00
if (!pDevice || IsCompressed(srcImage.format) || !IsCompressed(format))
2016-08-22 18:26:36 +00:00
return E_INVALIDARG;
2016-09-09 02:09:46 +00:00
if (IsTypeless(format)
|| IsTypeless(srcImage.format) || IsPlanar(srcImage.format) || IsPalettized(srcImage.format))
return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED);
2016-08-22 18:26:36 +00:00
// Setup GPU compressor
2016-09-09 02:09:46 +00:00
std::unique_ptr<GPUCompressBC> gpubc(new (std::nothrow) GPUCompressBC);
if (!gpubc)
2016-08-22 18:26:36 +00:00
return E_OUTOFMEMORY;
2016-09-09 02:09:46 +00:00
HRESULT hr = gpubc->Initialize(pDevice);
if (FAILED(hr))
2016-08-22 18:26:36 +00:00
return hr;
hr = gpubc->Prepare(srcImage.width, srcImage.height, compress, format, alphaWeight);
2016-09-09 02:09:46 +00:00
if (FAILED(hr))
2016-08-22 18:26:36 +00:00
return hr;
// Create workspace for result
2016-09-09 02:09:46 +00:00
hr = image.Initialize2D(format, srcImage.width, srcImage.height, 1, 1);
if (FAILED(hr))
2016-08-22 18:26:36 +00:00
return hr;
2016-09-09 02:09:46 +00:00
const Image *img = image.GetImage(0, 0, 0);
if (!img)
2016-08-22 18:26:36 +00:00
{
image.Release();
return E_POINTER;
}
2016-09-09 02:09:46 +00:00
hr = GPUCompress(gpubc.get(), srcImage, *img, compress);
if (FAILED(hr))
2016-08-22 18:26:36 +00:00
image.Release();
return hr;
}
_Use_decl_annotations_
2016-09-09 02:09:46 +00:00
HRESULT DirectX::Compress(
ID3D11Device* pDevice,
const Image* srcImages,
size_t nimages,
const TexMetadata& metadata,
DXGI_FORMAT format,
DWORD compress,
float alphaWeight,
ScratchImage& cImages)
2016-08-22 18:26:36 +00:00
{
2016-09-09 02:09:46 +00:00
if (!pDevice || !srcImages || !nimages)
2016-08-22 18:26:36 +00:00
return E_INVALIDARG;
2016-09-09 02:09:46 +00:00
if (IsCompressed(metadata.format) || !IsCompressed(format))
2016-08-22 18:26:36 +00:00
return E_INVALIDARG;
2016-09-09 02:09:46 +00:00
if (IsTypeless(format)
|| IsTypeless(metadata.format) || IsPlanar(metadata.format) || IsPalettized(metadata.format))
return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED);
2016-08-22 18:26:36 +00:00
cImages.Release();
// Setup GPU compressor
2016-09-09 02:09:46 +00:00
std::unique_ptr<GPUCompressBC> gpubc(new (std::nothrow) GPUCompressBC);
if (!gpubc)
2016-08-22 18:26:36 +00:00
return E_OUTOFMEMORY;
2016-09-09 02:09:46 +00:00
HRESULT hr = gpubc->Initialize(pDevice);
if (FAILED(hr))
2016-08-22 18:26:36 +00:00
return hr;
// Create workspace for result
TexMetadata mdata2 = metadata;
mdata2.format = format;
2016-09-09 02:09:46 +00:00
hr = cImages.Initialize(mdata2);
if (FAILED(hr))
2016-08-22 18:26:36 +00:00
return hr;
2016-09-09 02:09:46 +00:00
if (nimages != cImages.GetImageCount())
2016-08-22 18:26:36 +00:00
{
cImages.Release();
return E_FAIL;
}
const Image* dest = cImages.GetImages();
2016-09-09 02:09:46 +00:00
if (!dest)
2016-08-22 18:26:36 +00:00
{
cImages.Release();
return E_POINTER;
}
// Process images (ordered by size)
2016-09-09 02:09:46 +00:00
switch (metadata.dimension)
2016-08-22 18:26:36 +00:00
{
case TEX_DIMENSION_TEXTURE1D:
case TEX_DIMENSION_TEXTURE2D:
2016-09-09 02:09:46 +00:00
{
size_t w = metadata.width;
size_t h = metadata.height;
for (size_t level = 0; level < metadata.mipLevels; ++level)
2016-08-22 18:26:36 +00:00
{
hr = gpubc->Prepare(w, h, compress, format, alphaWeight);
2016-09-09 02:09:46 +00:00
if (FAILED(hr))
{
cImages.Release();
return hr;
}
2016-08-22 18:26:36 +00:00
2016-09-09 02:09:46 +00:00
for (size_t item = 0; item < metadata.arraySize; ++item)
2016-08-22 18:26:36 +00:00
{
2016-09-09 02:09:46 +00:00
size_t index = metadata.ComputeIndex(level, item, 0);
if (index >= nimages)
2016-08-22 18:26:36 +00:00
{
cImages.Release();
2016-09-09 02:09:46 +00:00
return E_FAIL;
2016-08-22 18:26:36 +00:00
}
2016-09-09 02:09:46 +00:00
assert(dest[index].format == format);
const Image& src = srcImages[index];
if (src.width != dest[index].width || src.height != dest[index].height)
2016-08-22 18:26:36 +00:00
{
2016-09-09 02:09:46 +00:00
cImages.Release();
return E_FAIL;
2016-08-22 18:26:36 +00:00
}
2016-09-09 02:09:46 +00:00
hr = GPUCompress(gpubc.get(), src, dest[index], compress);
if (FAILED(hr))
{
cImages.Release();
return hr;
}
2016-08-22 18:26:36 +00:00
}
2016-09-09 02:09:46 +00:00
if (h > 1)
h >>= 1;
if (w > 1)
w >>= 1;
2016-08-22 18:26:36 +00:00
}
2016-09-09 02:09:46 +00:00
}
break;
2016-08-22 18:26:36 +00:00
case TEX_DIMENSION_TEXTURE3D:
2016-09-09 02:09:46 +00:00
{
size_t w = metadata.width;
size_t h = metadata.height;
size_t d = metadata.depth;
for (size_t level = 0; level < metadata.mipLevels; ++level)
2016-08-22 18:26:36 +00:00
{
hr = gpubc->Prepare(w, h, compress, format, alphaWeight);
2016-09-09 02:09:46 +00:00
if (FAILED(hr))
{
cImages.Release();
return hr;
}
2016-08-22 18:26:36 +00:00
2016-09-09 02:09:46 +00:00
for (size_t slice = 0; slice < d; ++slice)
2016-08-22 18:26:36 +00:00
{
2016-09-09 02:09:46 +00:00
size_t index = metadata.ComputeIndex(level, 0, slice);
if (index >= nimages)
2016-08-22 18:26:36 +00:00
{
cImages.Release();
2016-09-09 02:09:46 +00:00
return E_FAIL;
2016-08-22 18:26:36 +00:00
}
2016-09-09 02:09:46 +00:00
assert(dest[index].format == format);
const Image& src = srcImages[index];
if (src.width != dest[index].width || src.height != dest[index].height)
2016-08-22 18:26:36 +00:00
{
2016-09-09 02:09:46 +00:00
cImages.Release();
return E_FAIL;
2016-08-22 18:26:36 +00:00
}
2016-09-09 02:09:46 +00:00
hr = GPUCompress(gpubc.get(), src, dest[index], compress);
if (FAILED(hr))
{
cImages.Release();
return hr;
}
}
2016-08-22 18:26:36 +00:00
2016-09-09 02:09:46 +00:00
if (h > 1)
h >>= 1;
2016-08-22 18:26:36 +00:00
2016-09-09 02:09:46 +00:00
if (w > 1)
w >>= 1;
if (d > 1)
d >>= 1;
2016-08-22 18:26:36 +00:00
}
2016-09-09 02:09:46 +00:00
}
break;
2016-08-22 18:26:36 +00:00
default:
2016-09-09 02:09:46 +00:00
return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED);
2016-08-22 18:26:36 +00:00
}
return S_OK;
}