From aae41e425b7b208bf8da58bf9162accad3872be6 Mon Sep 17 00:00:00 2001 From: Chuck Walbourn Date: Wed, 28 Feb 2024 11:21:43 -0800 Subject: [PATCH] Xbox auxiliary optimization for tiling (#459) --- Auxiliary/DirectXTexXboxDetile.cpp | 400 +++-------------------------- Auxiliary/DirectXTexXboxTile.cpp | 396 +++------------------------- DirectXTex/DirectXTex.h | 6 +- DirectXTex/DirectXTexUtil.cpp | 67 ++++- 4 files changed, 134 insertions(+), 735 deletions(-) diff --git a/Auxiliary/DirectXTexXboxDetile.cpp b/Auxiliary/DirectXTexXboxDetile.cpp index 06fd914..d8ab45f 100644 --- a/Auxiliary/DirectXTexXboxDetile.cpp +++ b/Auxiliary/DirectXTexXboxDetile.cpp @@ -72,127 +72,6 @@ namespace return S_OK; } - //---------------------------------------------------------------------------------- - inline HRESULT DetileByElement2D( - const XboxImage& xbox, - uint32_t level, - _In_ XGTextureAddressComputer* computer, - const XG_RESOURCE_LAYOUT& layout, - _In_reads_(nimages) const Image* const * result, - size_t nimages, - size_t bpp, - size_t w, - size_t h, - bool packed) - { - const uint8_t* sptr = xbox.GetPointer(); - const uint8_t* endPtr = sptr + layout.SizeBytes; - - for (uint32_t item = 0; item < nimages; ++item) - { - const Image* img = result[item]; - if (!img || !img->pixels) - return E_POINTER; - - assert(img->width == result[0]->width); - assert(img->height == result[0]->height); - assert(img->rowPitch == result[0]->rowPitch); - assert(img->format == result[0]->format); - - uint8_t* dptr = img->pixels; - - for (uint32_t y = 0; y < h; ++y) - { - uint8_t* tptr = dptr; - - for (size_t x = 0; x < w; ++x) - { - #if defined(_GAMING_XBOX_SCARLETT) || defined(_USE_SCARLETT) - const UINT64 element = (packed) ? (x >> 1) : x; - const size_t offset = computer->GetTexelElementOffsetBytes(0, level, element, y, item, 0, nullptr); - #else - const size_t offset = computer->GetTexelElementOffsetBytes(0, level, x, y, item, 0); - #endif - if (offset == size_t(-1)) - return E_FAIL; - - const uint8_t* src = sptr + offset; - - if ((src + bpp) > endPtr) - return E_FAIL; - - memcpy(tptr, src, bpp); - tptr += bpp; - - if (packed) - ++x; - } - - dptr += img->rowPitch; - } - } - - return S_OK; - } - - //---------------------------------------------------------------------------------- - inline HRESULT DetileByElement3D( - const XboxImage& xbox, - uint32_t level, - uint32_t slices, - _In_ XGTextureAddressComputer* computer, - const XG_RESOURCE_LAYOUT& layout, - const Image& result, - size_t bpp, - size_t w, - size_t h, - bool packed) - { - const uint8_t* sptr = xbox.GetPointer(); - const uint8_t* endPtr = sptr + layout.SizeBytes; - - uint8_t* dptr = result.pixels; - - for (uint32_t z = 0; z < slices; ++z) - { - uint8_t* rptr = dptr; - - for (uint32_t y = 0; y < h; ++y) - { - uint8_t* tptr = rptr; - - for (size_t x = 0; x < w; ++x) - { - #if defined(_GAMING_XBOX_SCARLETT) || defined(_USE_SCARLETT) - const UINT64 element = (packed) ? (x >> 1) : x; - const size_t offset = computer->GetTexelElementOffsetBytes(0, level, element, y, z, 0, nullptr); - #else - const size_t offset = computer->GetTexelElementOffsetBytes(0, level, x, y, z, 0); - #endif - if (offset == size_t(-1)) - return E_FAIL; - - const uint8_t* src = sptr + offset; - - if ((src + bpp) > endPtr) - return E_FAIL; - - memcpy(tptr, src, bpp); - tptr += bpp; - - if (packed) - ++x; - } - - rptr += result.rowPitch; - } - - dptr += result.slicePitch; - } - - return S_OK; - } - //------------------------------------------------------------------------------------- // 1D Tiling //------------------------------------------------------------------------------------- @@ -331,125 +210,33 @@ namespace assert(layout.Planes == 1); - const DXGI_FORMAT format = result[0]->format; + uint8_t* baseAddr = xbox.GetPointer(); + const auto& metadata = xbox.GetMetadata(); - assert(format == xbox.GetMetadata().format); - - bool byelement = IsTypeless(format); - #if defined(_GAMING_XBOX_SCARLETT) || defined(_USE_SCARLETT) - if (nimages > 1) - byelement = true; - #endif - - if (IsCompressed(format)) + for (uint32_t item = 0; item < nimages; ++item) { - //--- BC formats use per-block copy ------------------------------------------- - const size_t nbw = std::max(1, (result[0]->width + 3) / 4); - const size_t nbh = std::max(1, (result[0]->height + 3) / 4); + const Image* img = result[item]; + if (!img || !img->pixels) + return E_POINTER; - const size_t bpb = (format == DXGI_FORMAT_BC1_TYPELESS - || format == DXGI_FORMAT_BC1_UNORM - || format == DXGI_FORMAT_BC1_UNORM_SRGB - || format == DXGI_FORMAT_BC4_TYPELESS - || format == DXGI_FORMAT_BC4_UNORM - || format == DXGI_FORMAT_BC4_SNORM) ? 8 : 16; + assert(img->width == result[0]->width); + assert(img->height == result[0]->height); + assert(img->rowPitch == result[0]->rowPitch); + assert(img->format == result[0]->format); - assert(nbw == layout.Plane[0].MipLayout[level].WidthElements); - assert(nbh == layout.Plane[0].MipLayout[level].HeightElements); - assert(bpb == layout.Plane[0].BytesPerElement); - - return DetileByElement2D(xbox, level, computer, layout, result, nimages, bpb, nbw, nbh, false); - } - else if (IsPacked(format)) - { - const size_t bpp = (BitsPerPixel(format) + 7) / 8; - - // XG (XboxOne) incorrectly returns 2 instead of 4 here for layout.Plane[0].BytesPerElement - - const size_t w = result[0]->width; - const size_t h = result[0]->height; - assert(((w + 1) / 2) == layout.Plane[0].MipLayout[level].WidthElements); - assert(h == layout.Plane[0].MipLayout[level].HeightElements); - - return DetileByElement2D(xbox, level, computer, layout, result, nimages, bpp, w, h, true); - } - else if (byelement) - { - //--- Typeless is done with per-element copy ---------------------------------- - const size_t bpp = (BitsPerPixel(format) + 7) / 8; - assert(bpp == layout.Plane[0].BytesPerElement); - - const size_t w = result[0]->width; - const size_t h = result[0]->height; - - assert(w == layout.Plane[0].MipLayout[level].WidthElements); - assert(h == layout.Plane[0].MipLayout[level].HeightElements); - - return DetileByElement2D(xbox, level, computer, layout, result, nimages, bpp, w, h, false); - } - else - { - //--- Standard format handling ------------------------------------------------ - auto& mip = layout.Plane[0].MipLayout[level]; - - const UINT32 tiledPixels = mip.PaddedWidthElements * mip.PaddedHeightElements * mip.PaddedDepthOrArraySize; - - auto scanline = make_AlignedArrayXMVECTOR(tiledPixels + result[0]->width); - - XMVECTOR* target = scanline.get(); - XMVECTOR* tiled = target + result[0]->width; - - #ifdef _DEBUG - memset(target, 0xCD, sizeof(XMVECTOR) * result[0]->width); - memset(tiled, 0xDD, sizeof(XMVECTOR) * tiledPixels); - #endif - - // Load tiled texture - if ((xbox.GetSize() - mip.OffsetBytes) < mip.SizeBytes) - return E_FAIL; - - if (!LoadScanline(tiled, tiledPixels, xbox.GetPointer() + mip.OffsetBytes, mip.SizeBytes, xbox.GetMetadata().format)) - return E_FAIL; - - // Perform detiling - for (uint32_t item = 0; item < nimages; ++item) + HRESULT hr = computer->CopyFromSubresource( + img->pixels, + 0u, + metadata.CalculateSubresource(level, item), + #if defined(_GAMING_XBOX_SCARLETT) || defined(_USE_SCARLETT) + 0u, + #endif + baseAddr, + static_cast(img->rowPitch), + 0u); + if (FAILED(hr)) { - const Image* img = result[item]; - if (!img || !img->pixels) - return E_POINTER; - - assert(img->width == result[0]->width); - assert(img->height == result[0]->height); - assert(img->rowPitch == result[0]->rowPitch); - assert(img->format == result[0]->format); - - auto dptr = reinterpret_cast(img->pixels); - for (uint32_t y = 0; y < img->height; ++y) - { - for (size_t x = 0; x < img->width; ++x) - { - #if defined(_GAMING_XBOX_SCARLETT) || defined(_USE_SCARLETT) - size_t offset = computer->GetTexelElementOffsetBytes(0, level, x, y, item, 0, nullptr); - #else - size_t offset = computer->GetTexelElementOffsetBytes(0, level, x, y, item, 0); - #endif - if (offset == size_t(-1)) - return E_FAIL; - - assert(offset >= mip.OffsetBytes); - assert(offset < mip.OffsetBytes + mip.SizeBytes); - - offset = (offset - mip.OffsetBytes) / layout.Plane[0].BytesPerElement; - assert(offset < tiledPixels); - - target[x] = tiled[offset]; - } - - if (!StoreScanline(dptr, img->rowPitch, img->format, target, img->width)) - return E_FAIL; - - dptr += img->rowPitch; - } + return hr; } } @@ -463,7 +250,6 @@ namespace HRESULT Detile3D( const XboxImage& xbox, uint32_t level, - uint32_t slices, _In_ XGTextureAddressComputer* computer, const XG_RESOURCE_LAYOUT& layout, const Image& result) @@ -475,137 +261,19 @@ namespace assert(layout.Planes == 1); - #if defined(_GAMING_XBOX_SCARLETT) || defined(_USE_SCARLETT) - const bool byelement = true; - #else - const bool byelement = IsTypeless(result.format); - #endif + uint8_t* baseAddr = xbox.GetPointer(); + const auto& metadata = xbox.GetMetadata(); - if (IsCompressed(result.format)) - { - //--- BC formats use per-block copy ------------------------------------------- - const size_t nbw = std::max(1, (result.width + 3) / 4); - const size_t nbh = std::max(1, (result.height + 3) / 4); - - const size_t bpb = (result.format == DXGI_FORMAT_BC1_TYPELESS - || result.format == DXGI_FORMAT_BC1_UNORM - || result.format == DXGI_FORMAT_BC1_UNORM_SRGB - || result.format == DXGI_FORMAT_BC4_TYPELESS - || result.format == DXGI_FORMAT_BC4_UNORM - || result.format == DXGI_FORMAT_BC4_SNORM) ? 8 : 16; - - assert(nbw == layout.Plane[0].MipLayout[level].WidthElements); - assert(nbh == layout.Plane[0].MipLayout[level].HeightElements); - assert(bpb == layout.Plane[0].BytesPerElement); - - return DetileByElement3D(xbox, level, slices, computer, layout, result, bpb, nbw, nbh, false); - } - else if (IsPacked(result.format)) - { - const size_t bpp = (BitsPerPixel(result.format) + 7) / 8; - - // XG (XboxOne) incorrectly returns 2 instead of 4 here for layout.Plane[0].BytesPerElement - - assert(((result.width + 1) / 2) == layout.Plane[0].MipLayout[level].WidthElements); - assert(result.height == layout.Plane[0].MipLayout[level].HeightElements); - - return DetileByElement3D(xbox, level, slices, computer, layout, result, bpp, result.width, result.height, true); - } - else if (byelement) - { - //--- Typeless is done with per-element copy ---------------------------------- - const size_t bpp = (BitsPerPixel(result.format) + 7) / 8; - assert(bpp == layout.Plane[0].BytesPerElement); - - assert(result.width == layout.Plane[0].MipLayout[level].WidthElements); - assert(result.height == layout.Plane[0].MipLayout[level].HeightElements); - - return DetileByElement3D(xbox, level, slices, computer, layout, result, bpp, result.width, result.height, false); - } - else - { - //--- Standard format handling ------------------------------------------------ - auto& mip = layout.Plane[0].MipLayout[level]; - - const UINT32 tiledPixels = mip.PaddedWidthElements * mip.PaddedHeightElements * mip.PaddedDepthOrArraySize; - assert(tiledPixels >= (result.width * result.height * slices)); - - auto scanline = make_AlignedArrayXMVECTOR(tiledPixels + result.width); - - XMVECTOR* target = scanline.get(); - XMVECTOR* tiled = target + result.width; - - #ifdef _DEBUG - memset(target, 0xCD, sizeof(XMVECTOR) * result.width); - memset(tiled, 0xDD, sizeof(XMVECTOR) * tiledPixels); + return computer->CopyFromSubresource( + result.pixels, + 0u, + metadata.CalculateSubresource(level, 0), + #if defined(_GAMING_XBOX_SCARLETT) || defined(_USE_SCARLETT) + 0u, #endif - - // Load tiled texture - if ((xbox.GetSize() - mip.OffsetBytes) < mip.SizeBytes) - return E_FAIL; - - const uint8_t* sptr = xbox.GetPointer() + mip.OffsetBytes; - const uint8_t* endPtr = sptr + mip.SizeBytes; - XMVECTOR* tptr = tiled; - for (uint32_t z = 0; z < mip.PaddedDepthOrArraySize; ++z) - { - const uint8_t* rptr = sptr; - XMVECTOR* uptr = tptr; - - for (uint32_t y = 0; y < mip.PaddedHeightElements; ++y) - { - if ((rptr + mip.PitchBytes) > endPtr) - return E_FAIL; - - if (!LoadScanline(uptr, mip.PitchPixels, rptr, mip.PitchBytes, xbox.GetMetadata().format)) - return E_FAIL; - - rptr += mip.PitchBytes; - uptr += mip.PaddedWidthElements; - } - - sptr += mip.Slice2DSizeBytes; - tptr += size_t(mip.PaddedHeightElements) * size_t(mip.PaddedWidthElements); - } - - // Perform detiling - uint8_t* dptr = reinterpret_cast(result.pixels); - for (uint32_t z = 0; z < slices; ++z) - { - uint8_t* rptr = dptr; - - for (uint32_t y = 0; y < result.height; ++y) - { - for (size_t x = 0; x < result.width; ++x) - { - #if defined(_GAMING_XBOX_SCARLETT) || defined(_USE_SCARLETT) - size_t offset = computer->GetTexelElementOffsetBytes(0, level, x, y, z, 0, nullptr); - #else - size_t offset = computer->GetTexelElementOffsetBytes(0, level, x, y, z, 0); - #endif - if (offset == size_t(-1)) - return E_FAIL; - - assert(offset >= mip.OffsetBytes); - assert(offset < mip.OffsetBytes + mip.SizeBytes); - - offset = (offset - mip.OffsetBytes) / layout.Plane[0].BytesPerElement; - assert(offset < tiledPixels); - - target[x] = tiled[offset]; - } - - if (!StoreScanline(rptr, result.rowPitch, result.format, target, result.width)) - return E_FAIL; - - rptr += result.rowPitch; - } - - dptr += result.slicePitch; - } - } - - return S_OK; + baseAddr, + static_cast(result.rowPitch), + static_cast(result.slicePitch)); } } @@ -854,7 +522,7 @@ HRESULT Xbox::Detile( } // Relies on the fact that slices are contiguous - hr = Detile3D(xbox, level, d, computer.Get(), layout, image.GetImages()[index]); + hr = Detile3D(xbox, level, computer.Get(), layout, image.GetImages()[index]); if (FAILED(hr)) { image.Release(); diff --git a/Auxiliary/DirectXTexXboxTile.cpp b/Auxiliary/DirectXTexXboxTile.cpp index 99c452d..c860303 100644 --- a/Auxiliary/DirectXTexXboxTile.cpp +++ b/Auxiliary/DirectXTexXboxTile.cpp @@ -75,126 +75,6 @@ namespace return S_OK; } - //---------------------------------------------------------------------------------- - inline HRESULT TileByElement2D( - _In_reads_(nimages) const Image* const * images, - size_t nimages, - uint32_t level, - _In_ XGTextureAddressComputer* computer, - const XG_RESOURCE_LAYOUT& layout, - const XboxImage& xbox, - size_t bpp, - size_t w, - size_t h, - bool packed) - { - uint8_t* dptr = xbox.GetPointer(); - const uint8_t* endPtr = dptr + layout.SizeBytes; - - for (uint32_t item = 0; item < nimages; ++item) - { - const Image* img = images[item]; - - if (!img || !img->pixels) - return E_POINTER; - - assert(img->width == images[0]->width); - assert(img->height == images[0]->height); - assert(img->rowPitch == images[0]->rowPitch); - assert(img->format == images[0]->format); - - const uint8_t* sptr = img->pixels; - for (uint32_t y = 0; y < h; ++y) - { - const uint8_t* tptr = sptr; - - for (size_t x = 0; x < w; ++x) - { - #if defined(_GAMING_XBOX_SCARLETT) || defined(_USE_SCARLETT) - UINT64 element = (packed) ? (x >> 1) : x; - size_t offset = computer->GetTexelElementOffsetBytes(0, level, element, y, item, 0, nullptr); - #else - size_t offset = computer->GetTexelElementOffsetBytes(0, level, x, y, item, 0); - #endif - if (offset == size_t(-1)) - return E_FAIL; - - uint8_t* dest = dptr + offset; - - if ((dest + bpp) > endPtr) - return E_FAIL; - - memcpy(dest, tptr, bpp); - tptr += bpp; - - if (packed) - ++x; - } - - sptr += img->rowPitch; - } - } - - return S_OK; - } - - //---------------------------------------------------------------------------------- - inline HRESULT TileByElement3D( - const Image& image, - uint32_t level, - uint32_t slices, - _In_ XGTextureAddressComputer* computer, - const XG_RESOURCE_LAYOUT& layout, - const XboxImage& xbox, - size_t bpp, - size_t w, - size_t h, - bool packed) - { - uint8_t* dptr = xbox.GetPointer(); - const uint8_t* endPtr = dptr + layout.SizeBytes; - - const uint8_t* sptr = image.pixels; - for (uint32_t z = 0; z < slices; ++z) - { - const uint8_t* rptr = sptr; - - for (uint32_t y = 0; y < h; ++y) - { - const uint8_t* tptr = rptr; - - for (size_t x = 0; x < w; ++x) - { - #if defined(_GAMING_XBOX_SCARLETT) || defined(_USE_SCARLETT) - UINT64 element = (packed) ? (x >> 1) : x; - size_t offset = computer->GetTexelElementOffsetBytes(0, level, element, y, z, 0, nullptr); - #else - size_t offset = computer->GetTexelElementOffsetBytes(0, level, x, y, z, 0); - #endif - if (offset == size_t(-1)) - return E_FAIL; - - uint8_t* dest = dptr + offset; - - if ((dest + bpp) > endPtr) - return E_FAIL; - - memcpy(dest, tptr, bpp); - tptr += bpp; - - if (packed) - ++x; - } - - rptr += image.rowPitch; - } - - sptr += image.slicePitch; - } - - return S_OK; - } - //---------------------------------------------------------------------------------- #ifdef VERBOSE void DebugPrintDesc(const XG_TEXTURE1D_DESC& desc) @@ -414,126 +294,32 @@ namespace assert(layout.Planes == 1); - const DXGI_FORMAT format = images[0]->format; + uint8_t* baseAddr = xbox.GetPointer(); + const auto& metadata = xbox.GetMetadata(); - assert(format == xbox.GetMetadata().format); - - bool byelement = IsTypeless(format); - #if defined(_GAMING_XBOX_SCARLETT) || defined(_USE_SCARLETT) - if (nimages > 1) - byelement = true; - #endif - - if (IsCompressed(format)) + for (uint32_t item = 0; item < nimages; ++item) { - //--- BC formats use per-block copy ------------------------------------------- - const size_t nbw = std::max(1, (images[0]->width + 3) / 4); - const size_t nbh = std::max(1, (images[0]->height + 3) / 4); + const Image* img = images[item]; - const size_t bpb = (format == DXGI_FORMAT_BC1_TYPELESS - || format == DXGI_FORMAT_BC1_UNORM - || format == DXGI_FORMAT_BC1_UNORM_SRGB - || format == DXGI_FORMAT_BC4_TYPELESS - || format == DXGI_FORMAT_BC4_UNORM - || format == DXGI_FORMAT_BC4_SNORM) ? 8 : 16; + if (!img || !img->pixels) + return E_POINTER; - assert(nbw == layout.Plane[0].MipLayout[level].WidthElements); - assert(nbh == layout.Plane[0].MipLayout[level].HeightElements); - assert(bpb == layout.Plane[0].BytesPerElement); + assert(img->width == images[0]->width); + assert(img->height == images[0]->height); + assert(img->rowPitch == images[0]->rowPitch); + assert(img->format == images[0]->format); - return TileByElement2D(images, nimages, level, computer, layout, xbox, bpb, nbw, nbh, false); - } - else if (IsPacked(format)) - { - const size_t bpp = (BitsPerPixel(format) + 7) / 8; - - // XG (XboxOne) incorrectly returns 2 instead of 4 here for layout.Plane[0].BytesPerElement - - const size_t w = images[0]->width; - const size_t h = images[0]->height; - assert(((w + 1) / 2) == layout.Plane[0].MipLayout[level].WidthElements); - assert(h == layout.Plane[0].MipLayout[level].HeightElements); - - return TileByElement2D(images, nimages, level, computer, layout, xbox, bpp, w, h, true); - } - else if (byelement) - { - //--- Typeless is done with per-element copy ---------------------------------- - const size_t bpp = (BitsPerPixel(format) + 7) / 8; - assert(bpp == layout.Plane[0].BytesPerElement); - - const size_t w = images[0]->width; - const size_t h = images[0]->height; - - assert(w == layout.Plane[0].MipLayout[level].WidthElements); - assert(h == layout.Plane[0].MipLayout[level].HeightElements); - - return TileByElement2D(images, nimages, level, computer, layout, xbox, bpp, w, h, false); - } - else - { - //--- Standard format handling ------------------------------------------------ - auto& mip = layout.Plane[0].MipLayout[level]; - - const UINT32 tiledPixels = mip.PaddedWidthElements * mip.PaddedHeightElements * mip.PaddedDepthOrArraySize; - - auto scanline = make_AlignedArrayXMVECTOR(images[0]->width + tiledPixels); - - XMVECTOR* row = scanline.get(); - XMVECTOR* tiled = row + images[0]->width; - - #ifdef _DEBUG - memset(row, 0xCD, sizeof(XMVECTOR) * images[0]->width); - #endif - - memset(tiled, 0, sizeof(XMVECTOR) * tiledPixels); - - // Perform tiling - for (uint32_t item = 0; item < nimages; ++item) + HRESULT hr = computer->CopyIntoSubresource( + baseAddr, + 0u, + metadata.CalculateSubresource(level, item), + img->pixels, + static_cast(img->rowPitch), + 0u); + if (FAILED(hr)) { - const Image* img = images[item]; - - if (!img || !img->pixels) - return E_POINTER; - - assert(img->width == images[0]->width); - assert(img->height == images[0]->height); - assert(img->rowPitch == images[0]->rowPitch); - assert(img->format == images[0]->format); - - auto sptr = reinterpret_cast(img->pixels); - for (uint32_t y = 0; y < img->height; ++y) - { - if (!LoadScanline(row, img->width, sptr, img->rowPitch, img->format)) - return E_FAIL; - - sptr += img->rowPitch; - - for (size_t x = 0; x < img->width; ++x) - { - #if defined(_GAMING_XBOX_SCARLETT) || defined(_USE_SCARLETT) - size_t offset = computer->GetTexelElementOffsetBytes(0, level, x, y, item, 0, nullptr); - #else - size_t offset = computer->GetTexelElementOffsetBytes(0, level, x, y, item, 0); - #endif - if (offset == size_t(-1)) - return E_FAIL; - - assert(offset >= mip.OffsetBytes); - assert(offset < mip.OffsetBytes + mip.SizeBytes); - - offset = (offset - mip.OffsetBytes) / layout.Plane[0].BytesPerElement; - assert(offset < tiledPixels); - - tiled[offset] = row[x]; - } - } + return hr; } - - // Store tiled texture - assert(mip.OffsetBytes + mip.SizeBytes <= layout.SizeBytes); - if (!StoreScanline(xbox.GetPointer() + mip.OffsetBytes, mip.SizeBytes, xbox.GetMetadata().format, tiled, tiledPixels)) - return E_FAIL; } return S_OK; @@ -546,7 +332,6 @@ namespace HRESULT Tile3D( const Image& image, uint32_t level, - uint32_t slices, _In_ XGTextureAddressComputer* computer, const XG_RESOURCE_LAYOUT& layout, const XboxImage& xbox) @@ -554,141 +339,18 @@ namespace if (!image.pixels || !computer || !xbox.GetPointer()) return E_POINTER; - assert(slices > 0); - assert(layout.Planes == 1); - assert(image.format == xbox.GetMetadata().format); + uint8_t* baseAddr = xbox.GetPointer(); + const auto& metadata = xbox.GetMetadata(); - #if defined(_GAMING_XBOX_SCARLETT) || defined(_USE_SCARLETT) - const bool byelement = true; - #else - const bool byelement = IsTypeless(image.format); - #endif - - if (IsCompressed(image.format)) - { - //--- BC formats use per-block copy ------------------------------------------- - const size_t nbw = std::max(1, (image.width + 3) / 4); - const size_t nbh = std::max(1, (image.height + 3) / 4); - - const size_t bpb = (image.format == DXGI_FORMAT_BC1_TYPELESS - || image.format == DXGI_FORMAT_BC1_UNORM - || image.format == DXGI_FORMAT_BC1_UNORM_SRGB - || image.format == DXGI_FORMAT_BC4_TYPELESS - || image.format == DXGI_FORMAT_BC4_UNORM - || image.format == DXGI_FORMAT_BC4_SNORM) ? 8 : 16; - - assert(nbw == layout.Plane[0].MipLayout[level].WidthElements); - assert(nbh == layout.Plane[0].MipLayout[level].HeightElements); - assert(bpb == layout.Plane[0].BytesPerElement); - - return TileByElement3D(image, level, slices, computer, layout, xbox, bpb, nbw, nbh, false); - } - else if (IsPacked(image.format)) - { - const size_t bpp = (BitsPerPixel(image.format) + 7) / 8; - - // XG (XboxOne) incorrectly returns 2 instead of 4 here for layout.Plane[0].BytesPerElement - - assert(((image.width + 1) / 2) == layout.Plane[0].MipLayout[level].WidthElements); - assert(image.height == layout.Plane[0].MipLayout[level].HeightElements); - - return TileByElement3D(image, level, slices, computer, layout, xbox, bpp, image.width, image.height, true); - } - else if (byelement) - { - //--- Typeless is done with per-element copy ---------------------------------- - const size_t bpp = (BitsPerPixel(image.format) + 7) / 8; - assert(bpp == layout.Plane[0].BytesPerElement); - - assert(image.width == layout.Plane[0].MipLayout[level].WidthElements); - assert(image.height == layout.Plane[0].MipLayout[level].HeightElements); - - return TileByElement3D(image, level, slices, computer, layout, xbox, bpp, image.width, image.height, false); - } - else - { - //--- Standard format handling ------------------------------------------------ - auto& mip = layout.Plane[0].MipLayout[level]; - - const UINT32 tiledPixels = mip.PaddedWidthElements * mip.PaddedHeightElements * mip.PaddedDepthOrArraySize; - assert(tiledPixels >= (image.width * image.height * slices)); - - auto scanline = make_AlignedArrayXMVECTOR(image.width + tiledPixels); - - XMVECTOR* row = scanline.get(); - XMVECTOR* tiled = row + image.width; - - #ifdef _DEBUG - memset(row, 0xCD, sizeof(XMVECTOR) * image.width); - #endif - - memset(tiled, 0, sizeof(XMVECTOR) * tiledPixels); - - // Perform tiling - const uint8_t* sptr = reinterpret_cast(image.pixels); - for (uint32_t z = 0; z < slices; ++z) - { - const uint8_t* rptr = sptr; - - for (uint32_t y = 0; y < image.height; ++y) - { - if (!LoadScanline(row, image.width, rptr, image.rowPitch, image.format)) - return E_FAIL; - - rptr += image.rowPitch; - - for (size_t x = 0; x < image.width; ++x) - { - #if defined(_GAMING_XBOX_SCARLETT) || defined(_USE_SCARLETT) - size_t offset = computer->GetTexelElementOffsetBytes(0, level, x, y, z, 0, nullptr); - #else - size_t offset = computer->GetTexelElementOffsetBytes(0, level, x, y, z, 0); - #endif - if (offset == size_t(-1)) - return E_FAIL; - - assert(offset >= mip.OffsetBytes); - assert(offset < mip.OffsetBytes + mip.SizeBytes); - - offset = (offset - mip.OffsetBytes) / layout.Plane[0].BytesPerElement; - assert(offset < tiledPixels); - - tiled[offset] = row[x]; - } - } - - sptr += image.slicePitch; - } - - // Store tiled texture - uint8_t* dptr = xbox.GetPointer() + mip.OffsetBytes; - const uint8_t* endPtr = dptr + mip.SizeBytes; - const XMVECTOR* tptr = tiled; - for (uint32_t z = 0; z < mip.PaddedDepthOrArraySize; ++z) - { - uint8_t* rptr = dptr; - const XMVECTOR* uptr = tptr; - - for (uint32_t y = 0; y < mip.PaddedHeightElements; ++y) - { - if ((rptr + mip.PitchBytes) > endPtr) - return E_FAIL; - - if (!StoreScanline(rptr, mip.PitchBytes, xbox.GetMetadata().format, uptr, mip.PitchPixels)) - return E_FAIL; - - rptr += mip.PitchBytes; - uptr += mip.PaddedWidthElements; - } - - dptr += mip.Slice2DSizeBytes; - tptr += size_t(mip.PaddedHeightElements) * size_t(mip.PaddedWidthElements); - } - } - - return S_OK; + return computer->CopyIntoSubresource( + baseAddr, + 0u, + metadata.CalculateSubresource(level, 0), + image.pixels, + static_cast(image.rowPitch), + static_cast(image.slicePitch)); } } @@ -1055,7 +717,7 @@ HRESULT Xbox::Tile( } // Relies on the fact that slices are contiguous - hr = Tile3D(srcImages[index], level, d, computer.Get(), layout, xbox); + hr = Tile3D(srcImages[index], level, computer.Get(), layout, xbox); if (FAILED(hr)) { xbox.Release(); diff --git a/DirectXTex/DirectXTex.h b/DirectXTex/DirectXTex.h index 26329f3..eee44db 100644 --- a/DirectXTex/DirectXTex.h +++ b/DirectXTex/DirectXTex.h @@ -175,7 +175,7 @@ namespace DirectX DXGI_FORMAT format; TEX_DIMENSION dimension; - size_t __cdecl ComputeIndex(_In_ size_t mip, _In_ size_t item, _In_ size_t slice) const noexcept; + size_t __cdecl ComputeIndex(size_t mip, size_t item, size_t slice) const noexcept; // Returns size_t(-1) to indicate an out-of-range error bool __cdecl IsCubemap() const noexcept { return (miscFlags & TEX_MISC_TEXTURECUBE) != 0; } @@ -188,6 +188,10 @@ namespace DirectX bool __cdecl IsVolumemap() const noexcept { return (dimension == TEX_DIMENSION_TEXTURE3D); } // Helper for dimension + + uint32_t __cdecl CalculateSubresource(size_t mip, size_t item) const noexcept; + uint32_t __cdecl CalculateSubresource(size_t mip, size_t item, size_t plane) const noexcept; + // Returns size_t(-1) to indicate an out-of-range error }; struct DDSMetaData diff --git a/DirectXTex/DirectXTexUtil.cpp b/DirectXTex/DirectXTexUtil.cpp index 0136b04..9c6cfbc 100644 --- a/DirectXTex/DirectXTexUtil.cpp +++ b/DirectXTex/DirectXTexUtil.cpp @@ -1492,7 +1492,6 @@ DXGI_FORMAT DirectX::MakeTypelessFLOAT(DXGI_FORMAT fmt) noexcept // TexMetadata //===================================================================================== -_Use_decl_annotations_ size_t TexMetadata::ComputeIndex(size_t mip, size_t item, size_t slice) const noexcept { if (mip >= mipLevels) @@ -1541,6 +1540,72 @@ size_t TexMetadata::ComputeIndex(size_t mip, size_t item, size_t slice) const no } } +// Equivalent to D3D11CacluateSubresource +uint32_t TexMetadata::CalculateSubresource(size_t mip, size_t item) const noexcept +{ + uint32_t result = uint32_t(-1); + + if (mip < mipLevels) + { + switch (dimension) + { + case TEX_DIMENSION_TEXTURE1D: + case TEX_DIMENSION_TEXTURE2D: + if (item < arraySize) + { + return static_cast(mip + item*mipLevels); + } + break; + + case TEX_DIMENSION_TEXTURE3D: + // No support for arrays of volumes + if (item == 0) + { + result = static_cast(mip); + } + break; + + default: + break; + } + } + + return result; +} + +// Equivalent to D3D12CacluateSubresource +uint32_t TexMetadata::CalculateSubresource(size_t mip, size_t item, size_t plane) const noexcept +{ + uint32_t result = uint32_t(-1); + + if (mip < mipLevels) + { + switch (dimension) + { + case TEX_DIMENSION_TEXTURE1D: + case TEX_DIMENSION_TEXTURE2D: + if (item < arraySize) + { + return static_cast(mip + item*mipLevels + plane*mipLevels*arraySize); + } + break; + + case TEX_DIMENSION_TEXTURE3D: + // No support for arrays of volumes + if (item == 0) + { + result = static_cast(mip + plane*mipLevels); + } + break; + + default: + break; + } + } + + return result; +} + //===================================================================================== // Blob - Bitmap image container