diff --git a/features/Dynamic Cubemaps/Shaders/DynamicCubemaps/BC6HEncodeCS.hlsl b/features/Dynamic Cubemaps/Shaders/DynamicCubemaps/BC6HEncodeCS.hlsl new file mode 100644 index 0000000000..25d916293a --- /dev/null +++ b/features/Dynamic Cubemaps/Shaders/DynamicCubemaps/BC6HEncodeCS.hlsl @@ -0,0 +1,341 @@ +// BC6H real-time GPU encoder compute shader. +// Adapted from GPURealTimeBC6H by Krzysztof Narkowicz. +// Source: https://github.com/knarkowicz/GPURealTimeBC6H +// +// MIT License +// +// Copyright (c) 2015 Krzysztof Narkowicz +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// +// Modifications for Community Shaders: +// - Input changed from Texture2D to Texture2DArray to process all 6 cubemap faces in one dispatch +// - Output changed from RWTexture2D to RWTexture2DArray accordingly +// - cbuffer simplified to only fields needed for compression +// - QUALITY forced to 0 (fast P1-only mode) + +#pragma warning(disable: 3078) + +// Fast mode: P1 only (single endpoint pair, 4-bit indices). No P2. +#define QUALITY 0 +#define ENCODE_P2 0 + +#define INSET_COLOR_BBOX 1 +#define OPTIMIZE_ENDPOINTS 1 +#define LUMINANCE_WEIGHTS 1 + +static const float HALF_MAX = 65504.0f; +static const uint PATTERN_NUM = 32; + +Texture2DArray SrcTexture : register(t0); +RWTexture2DArray OutputTexture : register(u0); + +cbuffer BC6HEncodeCB : register(b0) +{ + uint2 TextureSizeInBlocks; + uint MipLevel; + uint pad; +}; + +float CalcMSLE(float3 a, float3 b) +{ + float3 delta = log2((b + 1.0f) / (a + 1.0f)); + float3 deltaSq = delta * delta; + +#if LUMINANCE_WEIGHTS + float3 luminanceWeights = float3(0.299f, 0.587f, 0.114f); + deltaSq *= luminanceWeights; +#endif + + return deltaSq.x + deltaSq.y + deltaSq.z; +} + +uint PatternFixupID(uint i) +{ + uint ret = 15; + ret = ((3441033216 >> i) & 0x1) ? 2 : ret; + ret = ((845414400 >> i) & 0x1) ? 8 : ret; + return ret; +} + +uint Pattern(uint p, uint i) +{ + uint p2 = p / 2; + uint p3 = p - p2 * 2; + + uint enc = 0; + enc = p2 == 0 ? 2290666700 : enc; + enc = p2 == 1 ? 3972591342 : enc; + enc = p2 == 2 ? 4276930688 : enc; + enc = p2 == 3 ? 3967876808 : enc; + enc = p2 == 4 ? 4293707776 : enc; + enc = p2 == 5 ? 3892379264 : enc; + enc = p2 == 6 ? 4278255592 : enc; + enc = p2 == 7 ? 4026597360 : enc; + enc = p2 == 8 ? 9369360 : enc; + enc = p2 == 9 ? 147747072 : enc; + enc = p2 == 10 ? 1930428556 : enc; + enc = p2 == 11 ? 2362323200 : enc; + enc = p2 == 12 ? 823134348 : enc; + enc = p2 == 13 ? 913073766 : enc; + enc = p2 == 14 ? 267393000 : enc; + enc = p2 == 15 ? 966553998 : enc; + + enc = p3 ? enc >> 16 : enc; + uint ret = (enc >> i) & 0x1; + return ret; +} + +float3 Quantize7(float3 x) +{ + return (f32tof16(x) * 128.0f) / (0x7bff + 1.0f); +} + +float3 Quantize9(float3 x) +{ + return (f32tof16(x) * 512.0f) / (0x7bff + 1.0f); +} + +float3 Quantize10(float3 x) +{ + return (f32tof16(x) * 1024.0f) / (0x7bff + 1.0f); +} + +float3 Unquantize7(float3 x) +{ + return (x * 65536.0f + 0x8000) / 128.0f; +} + +float3 Unquantize9(float3 x) +{ + return (x * 65536.0f + 0x8000) / 512.0f; +} + +float3 Unquantize10(float3 x) +{ + return (x * 65536.0f + 0x8000) / 1024.0f; +} + +float3 FinishUnquantize(float3 endpoint0Unq, float3 endpoint1Unq, float weight) +{ + float3 comp = (endpoint0Unq * (64.0f - weight) + endpoint1Unq * weight + 32.0f) * (31.0f / 4096.0f); + return f16tof32(uint3(comp)); +} + +void Swap(inout float3 a, inout float3 b) +{ + float3 tmp = a; + a = b; + b = tmp; +} + +void Swap(inout float a, inout float b) +{ + float tmp = a; + a = b; + b = tmp; +} + +uint ComputeIndex3(float texelPos, float endPoint0Pos, float endPoint1Pos) +{ + float r = (texelPos - endPoint0Pos) / (endPoint1Pos - endPoint0Pos); + return (uint)clamp(r * 6.98182f + 0.00909f + 0.5f, 0.0f, 7.0f); +} + +uint ComputeIndex4(float texelPos, float endPoint0Pos, float endPoint1Pos) +{ + float r = (texelPos - endPoint0Pos) / (endPoint1Pos - endPoint0Pos); + return (uint)clamp(r * 14.93333f + 0.03333f + 0.5f, 0.0f, 15.0f); +} + +void SignExtend(inout float3 v1, uint mask, uint signFlag) +{ + int3 v = (int3)v1; + v.x = (v.x & mask) | (v.x < 0 ? signFlag : 0); + v.y = (v.y & mask) | (v.y < 0 ? signFlag : 0); + v.z = (v.z & mask) | (v.z < 0 ? signFlag : 0); + v1 = v; +} + +void InsetColorBBoxP1(float3 texels[16], inout float3 blockMin, inout float3 blockMax) +{ + float3 refinedBlockMin = blockMax; + float3 refinedBlockMax = blockMin; + + for (uint i = 0; i < 16; ++i) { + refinedBlockMin = min(refinedBlockMin, texels[i] == blockMin ? refinedBlockMin : texels[i]); + refinedBlockMax = max(refinedBlockMax, texels[i] == blockMax ? refinedBlockMax : texels[i]); + } + + float3 logRefinedBlockMax = log2(refinedBlockMax + 1.0f); + float3 logRefinedBlockMin = log2(refinedBlockMin + 1.0f); + + float3 logBlockMax = log2(blockMax + 1.0f); + float3 logBlockMin = log2(blockMin + 1.0f); + float3 logBlockMaxExt = (logBlockMax - logBlockMin) * (1.0f / 32.0f); + + logBlockMin += min(logRefinedBlockMin - logBlockMin, logBlockMaxExt); + logBlockMax -= min(logBlockMax - logRefinedBlockMax, logBlockMaxExt); + + blockMin = exp2(logBlockMin) - 1.0f; + blockMax = exp2(logBlockMax) - 1.0f; +} + +void OptimizeEndpointsP1(float3 texels[16], inout float3 blockMin, inout float3 blockMax, in float3 blockMinNonInset, in float3 blockMaxNonInset) +{ + float3 blockDir = blockMax - blockMin; + blockDir = blockDir / (blockDir.x + blockDir.y + blockDir.z); + + float endPoint0Pos = f32tof16(dot(blockMin, blockDir)); + float endPoint1Pos = f32tof16(dot(blockMax, blockDir)); + + float3 alphaTexelSum = 0.0f; + float3 betaTexelSum = 0.0f; + float alphaBetaSum = 0.0f; + float alphaSqSum = 0.0f; + float betaSqSum = 0.0f; + + for (int i = 0; i < 16; i++) { + float texelPos = f32tof16(dot(texels[i], blockDir)); + uint texelIndex = ComputeIndex4(texelPos, endPoint0Pos, endPoint1Pos); + + float beta = saturate(texelIndex / 15.0f); + float alpha = 1.0f - beta; + + float3 texelF16 = f32tof16(texels[i].xyz); + alphaTexelSum += alpha * texelF16; + betaTexelSum += beta * texelF16; + + alphaBetaSum += alpha * beta; + alphaSqSum += alpha * alpha; + betaSqSum += beta * beta; + } + + float det = alphaSqSum * betaSqSum - alphaBetaSum * alphaBetaSum; + + if (abs(det) > 0.00001f) { + float detRcp = rcp(det); + blockMin = clamp(f16tof32(clamp(detRcp * (alphaTexelSum * betaSqSum - betaTexelSum * alphaBetaSum), 0.0f, HALF_MAX)), blockMinNonInset, blockMaxNonInset); + blockMax = clamp(f16tof32(clamp(detRcp * (betaTexelSum * alphaSqSum - alphaTexelSum * alphaBetaSum), 0.0f, HALF_MAX)), blockMinNonInset, blockMaxNonInset); + } +} + +void EncodeP1(inout uint4 block, inout float blockMSLE, float3 texels[16]) +{ + float3 blockMin = texels[0]; + float3 blockMax = texels[0]; + for (uint i = 1; i < 16; ++i) { + blockMin = min(blockMin, texels[i]); + blockMax = max(blockMax, texels[i]); + } + + float3 blockMinNonInset = blockMin; + float3 blockMaxNonInset = blockMax; +#if INSET_COLOR_BBOX + InsetColorBBoxP1(texels, blockMin, blockMax); +#endif + +#if OPTIMIZE_ENDPOINTS + OptimizeEndpointsP1(texels, blockMin, blockMax, blockMinNonInset, blockMaxNonInset); +#endif + + float3 blockDir = blockMax - blockMin; + blockDir = blockDir / (blockDir.x + blockDir.y + blockDir.z); + + float3 endpoint0 = Quantize10(blockMin); + float3 endpoint1 = Quantize10(blockMax); + float endPoint0Pos = f32tof16(dot(blockMin, blockDir)); + float endPoint1Pos = f32tof16(dot(blockMax, blockDir)); + + float fixupTexelPos = f32tof16(dot(texels[0], blockDir)); + uint fixupIndex = ComputeIndex4(fixupTexelPos, endPoint0Pos, endPoint1Pos); + if (fixupIndex > 7) { + Swap(endPoint0Pos, endPoint1Pos); + Swap(endpoint0, endpoint1); + } + + uint indices[16] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + for (uint i = 0; i < 16; ++i) { + float texelPos = f32tof16(dot(texels[i], blockDir)); + indices[i] = ComputeIndex4(texelPos, endPoint0Pos, endPoint1Pos); + } + + float3 endpoint0Unq = Unquantize10(endpoint0); + float3 endpoint1Unq = Unquantize10(endpoint1); + float msle = 0.0f; + for (uint i = 0; i < 16; ++i) { + float weight = floor((indices[i] * 64.0f) / 15.0f + 0.5f); + float3 texelUnc = FinishUnquantize(endpoint0Unq, endpoint1Unq, weight); + msle += CalcMSLE(texels[i], texelUnc); + } + + blockMSLE = msle; + block.x = 0x03; + + block.x |= (uint)endpoint0.x << 5; + block.x |= (uint)endpoint0.y << 15; + block.x |= (uint)endpoint0.z << 25; + block.y |= (uint)endpoint0.z >> 7; + block.y |= (uint)endpoint1.x << 3; + block.y |= (uint)endpoint1.y << 13; + block.y |= (uint)endpoint1.z << 23; + block.z |= (uint)endpoint1.z >> 9; + + block.z |= indices[0] << 1; + block.z |= indices[1] << 4; + block.z |= indices[2] << 8; + block.z |= indices[3] << 12; + block.z |= indices[4] << 16; + block.z |= indices[5] << 20; + block.z |= indices[6] << 24; + block.z |= indices[7] << 28; + block.w |= indices[8] << 0; + block.w |= indices[9] << 4; + block.w |= indices[10] << 8; + block.w |= indices[11] << 12; + block.w |= indices[12] << 16; + block.w |= indices[13] << 20; + block.w |= indices[14] << 24; + block.w |= indices[15] << 28; +} + +[numthreads(8, 8, 1)] void main( + uint3 dispatchThreadID : SV_DispatchThreadID) { + uint2 blockCoord = dispatchThreadID.xy; + uint faceIndex = dispatchThreadID.z; + + if (all(blockCoord < TextureSizeInBlocks)) { + int2 texelBase = int2(blockCoord) * 4; + + float3 texels[16]; + [unroll] for (int i = 0; i < 16; i++) + { + int tx = i % 4; + int ty = i / 4; + texels[i] = SrcTexture.Load(int4(texelBase.x + tx, texelBase.y + ty, int(faceIndex), int(MipLevel))).rgb; + } + + uint4 block = uint4(0, 0, 0, 0); + float blockMSLE = 0.0f; + + EncodeP1(block, blockMSLE, texels); + + OutputTexture[uint3(blockCoord, faceIndex)] = block; + } +} diff --git a/src/Features/DynamicCubemaps.cpp b/src/Features/DynamicCubemaps.cpp index 9adfe38078..a25ac330c3 100644 --- a/src/Features/DynamicCubemaps.cpp +++ b/src/Features/DynamicCubemaps.cpp @@ -243,6 +243,10 @@ void DynamicCubemaps::ClearShaderCache() specularIrradianceCS->Release(); specularIrradianceCS = nullptr; } + if (bc6hEncodeCS) { + bc6hEncodeCS->Release(); + bc6hEncodeCS = nullptr; + } } ID3D11ComputeShader* DynamicCubemaps::GetComputeShaderUpdate() @@ -308,6 +312,15 @@ ID3D11ComputeShader* DynamicCubemaps::GetComputeShaderSpecularIrradiance() return specularIrradianceCS; } +ID3D11ComputeShader* DynamicCubemaps::GetComputeShaderBC6HEncode() +{ + if (!bc6hEncodeCS) { + logger::debug("Compiling BC6HEncodeCS"); + bc6hEncodeCS = static_cast(Util::CompileShader(L"Data\\Shaders\\DynamicCubemaps\\BC6HEncodeCS.hlsl", {}, "cs_5_0")); + } + return bc6hEncodeCS; +} + void DynamicCubemaps::UpdateCubemapCapture(bool a_reflections) { auto renderer = globals::game::renderer; @@ -469,6 +482,62 @@ void DynamicCubemaps::Irradiance(bool a_reflections) context->CSSetUnorderedAccessViews(0, 1, &nullUAV, nullptr); } +void DynamicCubemaps::CompressToBC6H(bool a_reflections) +{ + auto context = globals::d3d::context; + + auto shader = GetComputeShaderBC6HEncode(); + if (!shader) { + logger::error("BC6HEncodeCS failed to compile; BC6H compression disabled"); + return; + } + + auto* srcSRV = a_reflections ? envReflectionsTextureArraySRV : envTextureArraySRV; + + context->CSSetShader(shader, nullptr, 0); + context->CSSetShaderResources(0, 1, &srcSRV); + + ID3D11Buffer* cb = bc6hEncodeCB->CB(); + context->CSSetConstantBuffers(0, 1, &cb); + + std::uint32_t mipDim = std::max(envTexture->desc.Width, envTexture->desc.Height); + + for (std::uint32_t level = 0; level < bc6hMipLevels; ++level) { + std::uint32_t srcWidth = std::max(1u, mipDim >> level); + std::uint32_t srcHeight = std::max(1u, mipDim >> level); + std::uint32_t blocksX = std::max(1u, srcWidth / 4); + std::uint32_t blocksY = std::max(1u, srcHeight / 4); + + BC6HEncodeCB cbData{}; + cbData.TextureSizeInBlocksX = blocksX; + cbData.TextureSizeInBlocksY = blocksY; + cbData.MipLevel = level; + bc6hEncodeCB->Update(cbData); + + context->CSSetUnorderedAccessViews(0, 1, &bc6hScratchUAVs[level], nullptr); + + std::uint32_t dispatchX = std::max(1u, (blocksX + 7) / 8); + std::uint32_t dispatchY = std::max(1u, (blocksY + 7) / 8); + context->Dispatch(dispatchX, dispatchY, 6); + } + + { + ID3D11ShaderResourceView* nullSRV = nullptr; + ID3D11UnorderedAccessView* nullUAV = nullptr; + ID3D11Buffer* nullBuffer = nullptr; + context->CSSetUnorderedAccessViews(0, 1, &nullUAV, nullptr); + context->CSSetShaderResources(0, 1, &nullSRV); + context->CSSetConstantBuffers(0, 1, &nullBuffer); + context->CSSetShader(nullptr, nullptr, 0); + } + + // BC formats are bitwise-compatible with matching block-equivalent uncompressed + // formats for CopyResource: an R32G32B32A32_UINT (W/4 × H/4) resource maps 1:1 + // to a BC6H_UF16 (W × H) resource because each block is 16 bytes either way. + auto dst = a_reflections ? envReflectionsTextureBC6H : envTextureBC6H; + context->CopyResource(dst->resource.get(), bc6hScratchTexture->resource.get()); +} + void DynamicCubemaps::UpdateCubemap() { ZoneScoped; @@ -507,11 +576,16 @@ void DynamicCubemaps::UpdateCubemap() break; case NextTask::kIrradiance: + nextTask = NextTask::kBC6HCompress; + Irradiance(false); + break; + + case NextTask::kBC6HCompress: if (activeReflections) nextTask = NextTask::kCapture2; else nextTask = NextTask::kCapture; - Irradiance(false); + CompressToBC6H(false); break; case NextTask::kCapture2: @@ -525,9 +599,14 @@ void DynamicCubemaps::UpdateCubemap() break; case NextTask::kIrradiance2: - nextTask = NextTask::kCapture; + nextTask = NextTask::kBC6HCompress2; Irradiance(true); break; + + case NextTask::kBC6HCompress2: + nextTask = NextTask::kCapture; + CompressToBC6H(true); + break; } } @@ -535,7 +614,10 @@ void DynamicCubemaps::PostDeferred() { auto context = globals::d3d::context; - ID3D11ShaderResourceView* views[2] = { (activeReflections ? envReflectionsTexture : envTexture)->srv.get(), envTexture->srv.get() }; + ID3D11ShaderResourceView* views[2] = { + (activeReflections ? envReflectionsTextureBC6H : envTextureBC6H)->srv.get(), + envTextureBC6H->srv.get() + }; context->PSSetShaderResources(30, 2, views); } @@ -546,6 +628,7 @@ void DynamicCubemaps::SetupResources() GetComputeShaderInferrence(); GetComputeShaderInferrenceReflections(); GetComputeShaderSpecularIrradiance(); + GetComputeShaderBC6HEncode(); auto renderer = globals::game::renderer; auto device = globals::d3d::device; @@ -622,13 +705,91 @@ void DynamicCubemaps::SetupResources() envReflectionsTexture->CreateSRV(srvDesc); envReflectionsTexture->CreateUAV(uavDesc); + // Texture2DArray SRVs used by BC6H encoder (Load() requires array dimension, not TextureCube) + { + D3D11_SHADER_RESOURCE_VIEW_DESC arraySRVDesc = {}; + arraySRVDesc.Format = DXGI_FORMAT_R11G11B10_FLOAT; + arraySRVDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2DARRAY; + arraySRVDesc.Texture2DArray.FirstArraySlice = 0; + arraySRVDesc.Texture2DArray.ArraySize = 6; + arraySRVDesc.Texture2DArray.MostDetailedMip = 0; + arraySRVDesc.Texture2DArray.MipLevels = MIPLEVELS; + DX::ThrowIfFailed(device->CreateShaderResourceView(envTexture->resource.get(), &arraySRVDesc, &envTextureArraySRV)); + DX::ThrowIfFailed(device->CreateShaderResourceView(envReflectionsTexture->resource.get(), &arraySRVDesc, &envReflectionsTextureArraySRV)); + } + envInferredTexture = new Texture2D(texDesc); envInferredTexture->CreateSRV(srvDesc); envInferredTexture->CreateUAV(uavDesc); + // BC6H scratch: R32G32B32A32_UINT at quarter-resolution, 6-face array. + // Encoded directly into here via UAV, then CopyResource'd to the BC6H texture. + // Mip count must match the BC6H target so block-equivalent dimensions align. + { + std::uint32_t scratchBase = std::max(1u, texDesc.Width / 4); + bc6hMipLevels = 0; + for (std::uint32_t d = scratchBase; d > 0; d >>= 1) + ++bc6hMipLevels; + // Clamp: must not exceed envTexture's mip count (source reads) or the UAV array size. + bc6hMipLevels = std::min(bc6hMipLevels, MIPLEVELS); + bc6hMipLevels = std::min(bc6hMipLevels, 8u); + + D3D11_TEXTURE2D_DESC scratchDesc = {}; + scratchDesc.Width = scratchBase; + scratchDesc.Height = std::max(1u, texDesc.Height / 4); + scratchDesc.MipLevels = bc6hMipLevels; + scratchDesc.ArraySize = 6; + scratchDesc.Format = DXGI_FORMAT_R32G32B32A32_UINT; + scratchDesc.SampleDesc.Count = 1; + scratchDesc.Usage = D3D11_USAGE_DEFAULT; + scratchDesc.BindFlags = D3D11_BIND_UNORDERED_ACCESS; + scratchDesc.MiscFlags = 0; + bc6hScratchTexture = new Texture2D(scratchDesc); + + D3D11_UNORDERED_ACCESS_VIEW_DESC scratchUAVDesc = {}; + scratchUAVDesc.Format = DXGI_FORMAT_R32G32B32A32_UINT; + scratchUAVDesc.ViewDimension = D3D11_UAV_DIMENSION_TEXTURE2DARRAY; + scratchUAVDesc.Texture2DArray.FirstArraySlice = 0; + scratchUAVDesc.Texture2DArray.ArraySize = 6; + for (std::uint32_t level = 0; level < bc6hMipLevels; ++level) { + scratchUAVDesc.Texture2DArray.MipSlice = level; + DX::ThrowIfFailed(device->CreateUnorderedAccessView(bc6hScratchTexture->resource.get(), &scratchUAVDesc, &bc6hScratchUAVs[level])); + } + } + + // BC6H compressed cubemap textures (shader-read-only). + { + D3D11_TEXTURE2D_DESC bc6hDesc = {}; + bc6hDesc.Width = texDesc.Width; + bc6hDesc.Height = texDesc.Height; + bc6hDesc.MipLevels = bc6hMipLevels; + bc6hDesc.ArraySize = 6; + bc6hDesc.Format = DXGI_FORMAT_BC6H_UF16; + bc6hDesc.SampleDesc.Count = 1; + bc6hDesc.Usage = D3D11_USAGE_DEFAULT; + bc6hDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE; + bc6hDesc.MiscFlags = D3D11_RESOURCE_MISC_TEXTURECUBE; + + D3D11_SHADER_RESOURCE_VIEW_DESC bc6hSRVDesc = {}; + bc6hSRVDesc.Format = DXGI_FORMAT_BC6H_UF16; + bc6hSRVDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURECUBE; + bc6hSRVDesc.TextureCube.MostDetailedMip = 0; + bc6hSRVDesc.TextureCube.MipLevels = bc6hMipLevels; + + envTextureBC6H = new Texture2D(bc6hDesc); + envTextureBC6H->CreateSRV(bc6hSRVDesc); + + envReflectionsTextureBC6H = new Texture2D(bc6hDesc); + envReflectionsTextureBC6H->CreateSRV(bc6hSRVDesc); + } + updateCubemapCB = new ConstantBuffer(ConstantBufferDesc()); } + { + bc6hEncodeCB = new ConstantBuffer(ConstantBufferDesc()); + } + { spmapCB = new ConstantBuffer(ConstantBufferDesc()); } diff --git a/src/Features/DynamicCubemaps.h b/src/Features/DynamicCubemaps.h index e67669c32c..7b23744d41 100644 --- a/src/Features/DynamicCubemaps.h +++ b/src/Features/DynamicCubemaps.h @@ -75,13 +75,39 @@ struct DynamicCubemaps : Feature kCapture, kInferrence, kIrradiance, + kBC6HCompress, kCapture2, kInferrence2, - kIrradiance2 + kIrradiance2, + kBC6HCompress2 }; NextTask nextTask = NextTask::kCapture; + // BC6H compression + struct alignas(16) BC6HEncodeCB + { + uint TextureSizeInBlocksX; + uint TextureSizeInBlocksY; + uint MipLevel; + uint pad; + }; + STATIC_ASSERT_ALIGNAS_16(BC6HEncodeCB); + + ID3D11ComputeShader* bc6hEncodeCS = nullptr; + ConstantBuffer* bc6hEncodeCB = nullptr; + + ID3D11ShaderResourceView* envTextureArraySRV = nullptr; + ID3D11ShaderResourceView* envReflectionsTextureArraySRV = nullptr; + + Texture2D* envTextureBC6H = nullptr; + Texture2D* envReflectionsTextureBC6H = nullptr; + Texture2D* bc6hScratchTexture = nullptr; + + uint32_t bc6hMipLevels = 0; + + ID3D11UnorderedAccessView* bc6hScratchUAVs[8] = {}; + // Editor window struct Settings @@ -158,6 +184,10 @@ struct DynamicCubemaps : Feature void Irradiance(bool a_reflections); + void CompressToBC6H(bool a_reflections); + + ID3D11ComputeShader* GetComputeShaderBC6HEncode(); + virtual bool SupportsVR() override { return true; }; virtual bool IsCore() const override { return true; }; };