webgpu improvements
This commit is contained in:
parent
5a75571ffd
commit
8347467e1e
18 changed files with 1932 additions and 153 deletions
|
|
@ -113,17 +113,30 @@ export namespace Crafter {
|
|||
std::uint16_t width = 0;
|
||||
std::uint16_t height = 0;
|
||||
std::uint16_t layers = 0;
|
||||
std::uint8_t mipLevels = 1;
|
||||
|
||||
void Create(std::uint16_t w, std::uint16_t h, std::uint16_t layerCount) {
|
||||
width = w;
|
||||
height = h;
|
||||
layers = layerCount;
|
||||
handle = WebGPU::wgpuCreateImage2DArray(w, h, layerCount);
|
||||
// Create an array with `layerCount` × (w × h) layers, each carrying
|
||||
// `mipLevels` mip levels. Pass mipLevels=1 (default) for a single
|
||||
// base level — matching the original no-mip behaviour. Caller is
|
||||
// responsible for uploading each level via UpdateLayer (which
|
||||
// handles CPU mip-chain generation when mipLevels > 1).
|
||||
void Create(std::uint16_t w, std::uint16_t h, std::uint16_t layerCount,
|
||||
std::uint8_t mipLevelCount = 1) {
|
||||
width = w;
|
||||
height = h;
|
||||
layers = layerCount;
|
||||
mipLevels = mipLevelCount;
|
||||
handle = WebGPU::wgpuCreateImage2DArray(w, h, layerCount, mipLevelCount);
|
||||
}
|
||||
|
||||
// Decompress `tex` and upload to `layer`. The asset's dims must
|
||||
// match the array's (w × h) — resize beforehand on the host with
|
||||
// TextureAsset<RGBA8>::Resize() if they don't.
|
||||
// Decompress `tex`, generate a CPU box-filter mip chain (if
|
||||
// mipLevels > 1), and upload each level into `layer`. The asset's
|
||||
// base-level dims must match the array's (w × h) — resize
|
||||
// beforehand on the host with TextureAsset<RGBA8>::Resize() if
|
||||
// they don't. Pixel data is treated as raw bytes per channel for
|
||||
// the box filter — for non-color data (normal maps) this gives
|
||||
// approximate but adequate results; for sRGB-encoded color data
|
||||
// it's also approximate but visually fine for game textures.
|
||||
void UpdateLayer(std::uint16_t layer, const CompressedTextureAsset& tex) {
|
||||
if (tex.pixelStride != sizeof(PixelType)) {
|
||||
std::println(std::cerr,
|
||||
|
|
@ -142,11 +155,56 @@ export namespace Crafter {
|
|||
std::as_writable_bytes(std::span(pixels)),
|
||||
};
|
||||
Compression::DecompressCPU(tex.blob, outputs);
|
||||
|
||||
// Upload level 0.
|
||||
WebGPU::wgpuWriteImage2DLayer(
|
||||
handle, layer,
|
||||
handle, layer, /*level*/ 0,
|
||||
pixels.data(),
|
||||
static_cast<std::int32_t>(pixels.size() * sizeof(PixelType)),
|
||||
width, height);
|
||||
|
||||
// Generate + upload subsequent mip levels via a 2x2 box filter
|
||||
// on the previous level's bytes. Each channel is averaged
|
||||
// independently across 4 source texels.
|
||||
std::uint16_t srcW = width;
|
||||
std::uint16_t srcH = height;
|
||||
std::vector<PixelType> prev = std::move(pixels);
|
||||
for (std::uint8_t lvl = 1; lvl < mipLevels; ++lvl) {
|
||||
std::uint16_t dstW = std::max<std::uint16_t>(1, srcW >> 1);
|
||||
std::uint16_t dstH = std::max<std::uint16_t>(1, srcH >> 1);
|
||||
std::vector<PixelType> next(static_cast<std::size_t>(dstW) * dstH);
|
||||
constexpr std::size_t kChannels = sizeof(PixelType);
|
||||
auto srcBytes = reinterpret_cast<const std::uint8_t*>(prev.data());
|
||||
auto dstBytes = reinterpret_cast<std::uint8_t*>(next.data());
|
||||
for (std::uint16_t y = 0; y < dstH; ++y) {
|
||||
std::uint16_t sy0 = static_cast<std::uint16_t>(y * 2);
|
||||
std::uint16_t sy1 = static_cast<std::uint16_t>(std::min<std::int32_t>(sy0 + 1, srcH - 1));
|
||||
for (std::uint16_t x = 0; x < dstW; ++x) {
|
||||
std::uint16_t sx0 = static_cast<std::uint16_t>(x * 2);
|
||||
std::uint16_t sx1 = static_cast<std::uint16_t>(std::min<std::int32_t>(sx0 + 1, srcW - 1));
|
||||
std::size_t a = (static_cast<std::size_t>(sy0) * srcW + sx0) * kChannels;
|
||||
std::size_t b = (static_cast<std::size_t>(sy0) * srcW + sx1) * kChannels;
|
||||
std::size_t c = (static_cast<std::size_t>(sy1) * srcW + sx0) * kChannels;
|
||||
std::size_t d = (static_cast<std::size_t>(sy1) * srcW + sx1) * kChannels;
|
||||
std::size_t out = (static_cast<std::size_t>(y) * dstW + x) * kChannels;
|
||||
for (std::size_t ch = 0; ch < kChannels; ++ch) {
|
||||
std::uint32_t sum = static_cast<std::uint32_t>(srcBytes[a + ch])
|
||||
+ static_cast<std::uint32_t>(srcBytes[b + ch])
|
||||
+ static_cast<std::uint32_t>(srcBytes[c + ch])
|
||||
+ static_cast<std::uint32_t>(srcBytes[d + ch]);
|
||||
dstBytes[out + ch] = static_cast<std::uint8_t>((sum + 2u) >> 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
WebGPU::wgpuWriteImage2DLayer(
|
||||
handle, layer, /*level*/ lvl,
|
||||
next.data(),
|
||||
static_cast<std::int32_t>(next.size() * sizeof(PixelType)),
|
||||
dstW, dstH);
|
||||
prev = std::move(next);
|
||||
srcW = dstW;
|
||||
srcH = dstH;
|
||||
}
|
||||
}
|
||||
|
||||
ImageSlot AllocateSlot(DescriptorHeapWebGPU& heap) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue