Terrain BC compression (#587)
This commit is contained in:
@@ -1096,9 +1096,9 @@ struct VolumetricCloudCapturePushConstants
|
||||
struct TerrainVirtualTexturePush
|
||||
{
|
||||
uint2 offset;
|
||||
float2 resolution_rcp;
|
||||
uint map_type;
|
||||
int region_weights_textureRO;
|
||||
int output_textureRW;
|
||||
};
|
||||
struct VirtualTextureResidencyUpdatePush
|
||||
{
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,5 +1,8 @@
|
||||
#include "globals.hlsli"
|
||||
|
||||
#define ASPM_HLSL
|
||||
#include "compressonator/bcn_common_kernel.h"
|
||||
|
||||
static const uint region_count = 4;
|
||||
|
||||
PUSHCONSTANT(push, TerrainVirtualTexturePush);
|
||||
@@ -10,94 +13,131 @@ struct Terrain
|
||||
};
|
||||
ConstantBuffer<Terrain> terrain : register(b0);
|
||||
|
||||
RWTexture2D<uint2> output_bc1_unorm : register(u0);
|
||||
RWTexture2D<uint4> output_bc3_unorm : register(u1);
|
||||
RWTexture2D<uint4> output_bc5_unorm : register(u2);
|
||||
|
||||
[numthreads(8, 8, 1)]
|
||||
void main(uint3 DTid : SV_DispatchThreadID, uint2 GTid : SV_GroupThreadID)
|
||||
{
|
||||
Texture2D<float4> region_weights_texture = bindless_textures[push.region_weights_textureRO];
|
||||
RWTexture2D<unorm float4> output = bindless_rwtextures[push.output_textureRW];
|
||||
|
||||
const uint2 pixel = DTid.xy + push.offset;
|
||||
float3 block_rgb[BLOCK_SIZE_4X4];
|
||||
float block_x[BLOCK_SIZE_4X4];
|
||||
float block_y[BLOCK_SIZE_4X4];
|
||||
|
||||
float2 output_dim;
|
||||
output.GetDimensions(output_dim.x, output_dim.y);
|
||||
const float2 uv = (pixel.xy + 0.5f) / output_dim;
|
||||
|
||||
float4 region_weights = region_weights_texture.SampleLevel(sampler_linear_clamp, uv, 0);
|
||||
|
||||
float weight_sum = 0;
|
||||
float4 total_color = 0;
|
||||
for (uint i = 0; i < region_count; ++i)
|
||||
for (uint y = 0; y < 4; ++y)
|
||||
{
|
||||
float weight = region_weights[i];
|
||||
|
||||
ShaderMaterial material = terrain.materials[i];
|
||||
|
||||
switch (push.map_type)
|
||||
for (uint x = 0; x < 4; ++x)
|
||||
{
|
||||
const uint2 pixel = push.offset + DTid.xy * 4 + uint2(x, y);
|
||||
const float2 uv = (pixel.xy + 0.5f) * push.resolution_rcp;
|
||||
|
||||
default:
|
||||
case 0:
|
||||
{
|
||||
float4 baseColor = material.baseColor;
|
||||
[branch]
|
||||
if (material.textures[BASECOLORMAP].IsValid())
|
||||
float4 region_weights = region_weights_texture.SampleLevel(sampler_linear_clamp, uv, 0);
|
||||
|
||||
float weight_sum = 0;
|
||||
float4 total_color = 0;
|
||||
for (uint i = 0; i < region_count; ++i)
|
||||
{
|
||||
Texture2D tex = bindless_textures[material.textures[BASECOLORMAP].texture_descriptor];
|
||||
float2 dim = 0;
|
||||
tex.GetDimensions(dim.x, dim.y);
|
||||
float2 diff = dim / output_dim;
|
||||
float lod = log2(max(diff.x, diff.y));
|
||||
float2 overscale = lod < 0 ? diff : 1;
|
||||
float4 baseColorMap = tex.SampleLevel(sampler_linear_wrap, uv / overscale, lod);
|
||||
baseColor *= baseColorMap;
|
||||
}
|
||||
total_color += baseColor * weight;
|
||||
}
|
||||
break;
|
||||
float weight = region_weights[i];
|
||||
|
||||
case 1:
|
||||
{
|
||||
float2 normal = float2(0.5, 0.5);
|
||||
[branch]
|
||||
if (material.textures[NORMALMAP].IsValid())
|
||||
ShaderMaterial material = terrain.materials[i];
|
||||
|
||||
switch (push.map_type)
|
||||
{
|
||||
|
||||
default:
|
||||
case 0:
|
||||
{
|
||||
float4 baseColor = material.baseColor;
|
||||
[branch]
|
||||
if (material.textures[BASECOLORMAP].IsValid())
|
||||
{
|
||||
Texture2D tex = bindless_textures[material.textures[BASECOLORMAP].texture_descriptor];
|
||||
float2 dim = 0;
|
||||
tex.GetDimensions(dim.x, dim.y);
|
||||
float2 diff = dim * push.resolution_rcp;
|
||||
float lod = log2(max(diff.x, diff.y));
|
||||
float2 overscale = lod < 0 ? diff : 1;
|
||||
float4 baseColorMap = tex.SampleLevel(sampler_linear_wrap, uv / overscale, lod);
|
||||
baseColor *= baseColorMap;
|
||||
}
|
||||
total_color += baseColor * weight;
|
||||
}
|
||||
break;
|
||||
|
||||
case 1:
|
||||
{
|
||||
float2 normal = float2(0.5, 0.5);
|
||||
[branch]
|
||||
if (material.textures[NORMALMAP].IsValid())
|
||||
{
|
||||
Texture2D tex = bindless_textures[material.textures[NORMALMAP].texture_descriptor];
|
||||
float2 dim = 0;
|
||||
tex.GetDimensions(dim.x, dim.y);
|
||||
float2 diff = dim * push.resolution_rcp;
|
||||
float lod = log2(max(diff.x, diff.y));
|
||||
float2 overscale = lod < 0 ? diff : 1;
|
||||
float2 normalMap = tex.SampleLevel(sampler_linear_wrap, uv / overscale, lod).rg;
|
||||
normal = normalMap;
|
||||
}
|
||||
total_color += float4(normal.rg, 1, 1) * weight;
|
||||
}
|
||||
break;
|
||||
|
||||
case 2:
|
||||
{
|
||||
float4 surface = float4(1, material.roughness, material.metalness, material.reflectance);
|
||||
[branch]
|
||||
if (material.textures[SURFACEMAP].IsValid())
|
||||
{
|
||||
Texture2D tex = bindless_textures[material.textures[SURFACEMAP].texture_descriptor];
|
||||
float2 dim = 0;
|
||||
tex.GetDimensions(dim.x, dim.y);
|
||||
float2 diff = dim * push.resolution_rcp;
|
||||
float lod = log2(max(diff.x, diff.y));
|
||||
float2 overscale = lod < 0 ? diff : 1;
|
||||
float4 surfaceMap = tex.SampleLevel(sampler_linear_wrap, uv / overscale, lod);
|
||||
surface *= surfaceMap;
|
||||
}
|
||||
total_color += surface * weight;
|
||||
}
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
weight_sum += weight;
|
||||
}
|
||||
total_color /= weight_sum;
|
||||
|
||||
const uint idx = x + y * 4;
|
||||
if (push.map_type == 1)
|
||||
{
|
||||
Texture2D tex = bindless_textures[material.textures[NORMALMAP].texture_descriptor];
|
||||
float2 dim = 0;
|
||||
tex.GetDimensions(dim.x, dim.y);
|
||||
float2 diff = dim / output_dim;
|
||||
float lod = log2(max(diff.x, diff.y));
|
||||
float2 overscale = lod < 0 ? diff : 1;
|
||||
float2 normalMap = tex.SampleLevel(sampler_linear_wrap, uv / overscale, lod).rg;
|
||||
normal = normalMap;
|
||||
block_x[idx] = total_color.r;
|
||||
block_y[idx] = total_color.g;
|
||||
}
|
||||
total_color += float4(normal.rg, 1, 1) * weight;
|
||||
}
|
||||
break;
|
||||
|
||||
case 2:
|
||||
{
|
||||
float4 surface = float4(1, material.roughness, material.metalness, material.reflectance);
|
||||
[branch]
|
||||
if (material.textures[SURFACEMAP].IsValid())
|
||||
if (push.map_type == 2)
|
||||
{
|
||||
Texture2D tex = bindless_textures[material.textures[SURFACEMAP].texture_descriptor];
|
||||
float2 dim = 0;
|
||||
tex.GetDimensions(dim.x, dim.y);
|
||||
float2 diff = dim / output_dim;
|
||||
float lod = log2(max(diff.x, diff.y));
|
||||
float2 overscale = lod < 0 ? diff : 1;
|
||||
float4 surfaceMap = tex.SampleLevel(sampler_linear_wrap, uv / overscale, lod);
|
||||
surface *= surfaceMap;
|
||||
block_rgb[idx] = total_color.rgb;
|
||||
block_x[idx] = total_color.a;
|
||||
}
|
||||
else
|
||||
{
|
||||
block_rgb[idx] = total_color.rgb;
|
||||
}
|
||||
total_color += surface * weight;
|
||||
}
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
weight_sum += weight;
|
||||
}
|
||||
total_color /= weight_sum;
|
||||
|
||||
output[pixel] = total_color;
|
||||
if (push.map_type == 1)
|
||||
{
|
||||
output_bc5_unorm[DTid.xy] = CompressBlockBC5_UNORM(block_x, block_y, CMP_QUALITY0);
|
||||
}
|
||||
if (push.map_type == 2)
|
||||
{
|
||||
output_bc3_unorm[DTid.xy] = CompressBlockBC3_UNORM(block_rgb, block_x, CMP_QUALITY2, /*isSRGB =*/ false);
|
||||
}
|
||||
else
|
||||
{
|
||||
output_bc1_unorm[DTid.xy] = CompressBlockBC1_UNORM(block_rgb, CMP_QUALITY0, /*isSRGB =*/ false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -697,6 +697,16 @@ namespace wi::graphics
|
||||
int32_t bottom = 0;
|
||||
};
|
||||
|
||||
struct Box
|
||||
{
|
||||
uint32_t left = 0;
|
||||
uint32_t top = 0;
|
||||
uint32_t front = 0;
|
||||
uint32_t right = 0;
|
||||
uint32_t bottom = 0;
|
||||
uint32_t back = 0;
|
||||
};
|
||||
|
||||
struct SparseTextureProperties
|
||||
{
|
||||
uint32_t tile_width = 0; // width of 1 tile in texels
|
||||
|
||||
@@ -203,6 +203,7 @@ namespace wi::graphics
|
||||
virtual void DispatchMeshIndirect(const GPUBuffer* args, uint64_t args_offset, CommandList cmd) {}
|
||||
virtual void CopyResource(const GPUResource* pDst, const GPUResource* pSrc, CommandList cmd) = 0;
|
||||
virtual void CopyBuffer(const GPUBuffer* pDst, uint64_t dst_offset, const GPUBuffer* pSrc, uint64_t src_offset, uint64_t size, CommandList cmd) = 0;
|
||||
virtual void CopyTexture(const Texture* dst, uint32_t dstX, uint32_t dstY, uint32_t dstZ, uint32_t dstMip, uint32_t dstSlice, const Texture* src, uint32_t srcMip, uint32_t srcSlice, CommandList cmd, const Box* srcbox = nullptr) = 0;
|
||||
virtual void QueryBegin(const GPUQueryHeap *heap, uint32_t index, CommandList cmd) = 0;
|
||||
virtual void QueryEnd(const GPUQueryHeap *heap, uint32_t index, CommandList cmd) = 0;
|
||||
virtual void QueryResolve(const GPUQueryHeap* heap, uint32_t index, uint32_t count, const GPUBuffer* dest, uint64_t dest_offset, CommandList cmd) = 0;
|
||||
|
||||
@@ -6135,6 +6135,44 @@ using namespace dx12_internal;
|
||||
|
||||
commandlist.GetGraphicsCommandList()->CopyBufferRegion(dst_internal->resource.Get(), dst_offset, src_internal->resource.Get(), src_offset, size);
|
||||
}
|
||||
void GraphicsDevice_DX12::CopyTexture(const Texture* dst, uint32_t dstX, uint32_t dstY, uint32_t dstZ, uint32_t dstMip, uint32_t dstSlice, const Texture* src, uint32_t srcMip, uint32_t srcSlice, CommandList cmd, const Box* srcbox)
|
||||
{
|
||||
CommandList_DX12& commandlist = GetCommandList(cmd);
|
||||
auto src_internal = to_internal((const GPUBuffer*)src);
|
||||
auto dst_internal = to_internal((const GPUBuffer*)dst);
|
||||
CD3DX12_TEXTURE_COPY_LOCATION src_location(src_internal->resource.Get(), D3D12CalcSubresource(srcMip, srcSlice, 0, src->desc.mip_levels, src->desc.array_size));
|
||||
CD3DX12_TEXTURE_COPY_LOCATION dst_location(dst_internal->resource.Get(), D3D12CalcSubresource(dstMip, dstSlice, 0, dst->desc.mip_levels, dst->desc.array_size));
|
||||
if (srcbox == nullptr)
|
||||
{
|
||||
commandlist.GetGraphicsCommandList()->CopyTextureRegion(
|
||||
&dst_location,
|
||||
dstX,
|
||||
dstY,
|
||||
dstZ,
|
||||
&src_location,
|
||||
nullptr
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
D3D12_BOX d3dbox = {};
|
||||
d3dbox.left = srcbox->left;
|
||||
d3dbox.top = srcbox->top;
|
||||
d3dbox.front = srcbox->front;
|
||||
d3dbox.right = srcbox->right;
|
||||
d3dbox.bottom = srcbox->bottom;
|
||||
d3dbox.back = srcbox->back;
|
||||
commandlist.GetGraphicsCommandList()->CopyTextureRegion(
|
||||
&dst_location,
|
||||
dstX,
|
||||
dstY,
|
||||
dstZ,
|
||||
&src_location,
|
||||
&d3dbox
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
void GraphicsDevice_DX12::QueryBegin(const GPUQueryHeap* heap, uint32_t index, CommandList cmd)
|
||||
{
|
||||
CommandList_DX12& commandlist = GetCommandList(cmd);
|
||||
|
||||
@@ -307,6 +307,7 @@ namespace wi::graphics
|
||||
void DispatchMeshIndirect(const GPUBuffer* args, uint64_t args_offset, CommandList cmd) override;
|
||||
void CopyResource(const GPUResource* pDst, const GPUResource* pSrc, CommandList cmd) override;
|
||||
void CopyBuffer(const GPUBuffer* pDst, uint64_t dst_offset, const GPUBuffer* pSrc, uint64_t src_offset, uint64_t size, CommandList cmd) override;
|
||||
void CopyTexture(const Texture* dst, uint32_t dstX, uint32_t dstY, uint32_t dstZ, uint32_t dstMip, uint32_t dstSlice, const Texture* src, uint32_t srcMip, uint32_t srcSlice, CommandList cmd, const Box* srcbox) override;
|
||||
void QueryBegin(const GPUQueryHeap* heap, uint32_t index, CommandList cmd) override;
|
||||
void QueryEnd(const GPUQueryHeap* heap, uint32_t index, CommandList cmd) override;
|
||||
void QueryResolve(const GPUQueryHeap* heap, uint32_t index, uint32_t count, const GPUBuffer* dest, uint64_t dest_offset, CommandList cmd) override;
|
||||
|
||||
@@ -7706,8 +7706,8 @@ using namespace vulkan_internal;
|
||||
void GraphicsDevice_Vulkan::CopyBuffer(const GPUBuffer* pDst, uint64_t dst_offset, const GPUBuffer* pSrc, uint64_t src_offset, uint64_t size, CommandList cmd)
|
||||
{
|
||||
CommandList_Vulkan& commandlist = GetCommandList(cmd);
|
||||
auto internal_state_src = to_internal((const GPUBuffer*)pSrc);
|
||||
auto internal_state_dst = to_internal((const GPUBuffer*)pDst);
|
||||
auto internal_state_src = to_internal(pSrc);
|
||||
auto internal_state_dst = to_internal(pDst);
|
||||
|
||||
VkBufferCopy copy = {};
|
||||
copy.srcOffset = src_offset;
|
||||
@@ -7720,6 +7720,55 @@ using namespace vulkan_internal;
|
||||
1, ©
|
||||
);
|
||||
}
|
||||
void GraphicsDevice_Vulkan::CopyTexture(const Texture* dst, uint32_t dstX, uint32_t dstY, uint32_t dstZ, uint32_t dstMip, uint32_t dstSlice, const Texture* src, uint32_t srcMip, uint32_t srcSlice, CommandList cmd, const Box* srcbox)
|
||||
{
|
||||
CommandList_Vulkan& commandlist = GetCommandList(cmd);
|
||||
auto src_internal = to_internal(src);
|
||||
auto dst_internal = to_internal(dst);
|
||||
|
||||
VkImageCopy copy = {};
|
||||
copy.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
copy.dstSubresource.baseArrayLayer = dstSlice;
|
||||
copy.dstSubresource.layerCount = 1;
|
||||
copy.dstSubresource.mipLevel = dstMip;
|
||||
copy.dstOffset.x = dstX;
|
||||
copy.dstOffset.y = dstY;
|
||||
copy.dstOffset.z = dstZ;
|
||||
|
||||
copy.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
copy.srcSubresource.baseArrayLayer = srcSlice;
|
||||
copy.srcSubresource.layerCount = 1;
|
||||
copy.srcSubresource.mipLevel = srcMip;
|
||||
|
||||
if (srcbox == nullptr)
|
||||
{
|
||||
copy.srcOffset.x = 0;
|
||||
copy.srcOffset.y = 0;
|
||||
copy.srcOffset.z = 0;
|
||||
copy.extent.width = std::min(dst->desc.width, src->desc.width);
|
||||
copy.extent.height = std::min(dst->desc.height, src->desc.height);
|
||||
copy.extent.depth = std::min(dst->desc.depth, src->desc.depth);
|
||||
}
|
||||
else
|
||||
{
|
||||
copy.srcOffset.x = srcbox->left;
|
||||
copy.srcOffset.y = srcbox->top;
|
||||
copy.srcOffset.z = srcbox->front;
|
||||
copy.extent.width = srcbox->right - srcbox->left;
|
||||
copy.extent.height = srcbox->bottom - srcbox->top;
|
||||
copy.extent.depth = srcbox->back - srcbox->front;
|
||||
}
|
||||
|
||||
vkCmdCopyImage(
|
||||
commandlist.GetCommandBuffer(),
|
||||
src_internal->resource,
|
||||
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
|
||||
dst_internal->resource,
|
||||
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
||||
1,
|
||||
©
|
||||
);
|
||||
}
|
||||
void GraphicsDevice_Vulkan::QueryBegin(const GPUQueryHeap* heap, uint32_t index, CommandList cmd)
|
||||
{
|
||||
CommandList_Vulkan& commandlist = GetCommandList(cmd);
|
||||
|
||||
@@ -402,6 +402,7 @@ namespace wi::graphics
|
||||
void DispatchMeshIndirect(const GPUBuffer* args, uint64_t args_offset, CommandList cmd) override;
|
||||
void CopyResource(const GPUResource* pDst, const GPUResource* pSrc, CommandList cmd) override;
|
||||
void CopyBuffer(const GPUBuffer* pDst, uint64_t dst_offset, const GPUBuffer* pSrc, uint64_t src_offset, uint64_t size, CommandList cmd) override;
|
||||
void CopyTexture(const Texture* dst, uint32_t dstX, uint32_t dstY, uint32_t dstZ, uint32_t dstMip, uint32_t dstSlice, const Texture* src, uint32_t srcMip, uint32_t srcSlice, CommandList cmd, const Box* srcbox) override;
|
||||
void QueryBegin(const GPUQueryHeap* heap, uint32_t index, CommandList cmd) override;
|
||||
void QueryEnd(const GPUQueryHeap* heap, uint32_t index, CommandList cmd) override;
|
||||
void QueryResolve(const GPUQueryHeap* heap, uint32_t index, uint32_t count, const GPUBuffer* dest, uint64_t dest_offset, CommandList cmd) override;
|
||||
|
||||
+96
-20
@@ -233,13 +233,6 @@ namespace wi::terrain
|
||||
bool success = device->CreateTexture(&desc, nullptr, &texture);
|
||||
assert(success);
|
||||
|
||||
for (uint32_t i = 0; i < texture.desc.mip_levels; ++i)
|
||||
{
|
||||
int subresource = 0;
|
||||
subresource = device->CreateSubresource(&texture, SubresourceType::UAV, 0, 1, i, 1);
|
||||
assert(subresource == i);
|
||||
}
|
||||
|
||||
residencyMap = {};
|
||||
feedbackMap = {};
|
||||
requestBuffer = {};
|
||||
@@ -1459,13 +1452,17 @@ namespace wi::terrain
|
||||
// This should have been created on generation thread, but if not (serialized), create it last minute:
|
||||
CreateChunkRegionTexture(chunk_data);
|
||||
|
||||
const uint32_t min_resolution = 128u;
|
||||
const uint32_t min_resolution = 256u;
|
||||
const uint32_t min_mips = 7u;
|
||||
#ifdef TERRAIN_VIRTUAL_TEXTURE_DEBUG
|
||||
const uint32_t max_resolution = 2048;
|
||||
const uint32_t max_mips = 10u;
|
||||
#else
|
||||
const uint32_t max_resolution = 16384u;
|
||||
const uint32_t max_mips = 13u;
|
||||
#endif // TERRAIN_VIRTUAL_TEXTURE_DEBUG
|
||||
const uint32_t required_resolution = dist < 2 ? max_resolution : min_resolution;
|
||||
const uint32_t required_mips = dist < 2 ? max_mips : min_mips;
|
||||
|
||||
chunk_data.vt.resize(3); // base, normal, surface
|
||||
for (uint32_t map_type = 0; map_type < chunk_data.vt.size(); ++map_type)
|
||||
@@ -1480,17 +1477,21 @@ namespace wi::terrain
|
||||
desc.width = required_resolution;
|
||||
desc.height = required_resolution;
|
||||
desc.misc_flags = ResourceMiscFlag::SPARSE;
|
||||
desc.bind_flags = BindFlag::SHADER_RESOURCE | BindFlag::UNORDERED_ACCESS;
|
||||
desc.mip_levels = 0;
|
||||
desc.bind_flags = BindFlag::SHADER_RESOURCE;
|
||||
desc.mip_levels = required_mips;
|
||||
desc.layout = ResourceState::SHADER_RESOURCE_COMPUTE;
|
||||
|
||||
if (map_type == MaterialComponent::NORMALMAP)
|
||||
switch (map_type)
|
||||
{
|
||||
desc.format = Format::R8G8_UNORM;
|
||||
}
|
||||
else
|
||||
{
|
||||
desc.format = Format::R8G8B8A8_UNORM;
|
||||
default:
|
||||
desc.format = Format::BC1_UNORM;
|
||||
break;
|
||||
case MaterialComponent::NORMALMAP:
|
||||
desc.format = Format::BC5_UNORM;
|
||||
break;
|
||||
case MaterialComponent::SURFACEMAP:
|
||||
desc.format = Format::BC3_UNORM;
|
||||
break;
|
||||
}
|
||||
vt.init(page_allocator, desc);
|
||||
|
||||
@@ -1504,8 +1505,8 @@ namespace wi::terrain
|
||||
|
||||
material->textures[map_type].lod_clamp = (float)vt.lod_count - 1;
|
||||
virtual_textures_in_use.push_back(&vt);
|
||||
virtual_texture_barriers_before_update.push_back(GPUBarrier::Image(&vt.texture, vt.texture.desc.layout, ResourceState::UNORDERED_ACCESS));
|
||||
virtual_texture_barriers_after_update.push_back(GPUBarrier::Image(&vt.texture, ResourceState::UNORDERED_ACCESS, vt.texture.desc.layout));
|
||||
virtual_texture_barriers_before_update.push_back(GPUBarrier::Image(&vt.texture, vt.texture.desc.layout, ResourceState::COPY_DST));
|
||||
virtual_texture_barriers_after_update.push_back(GPUBarrier::Image(&vt.texture, ResourceState::COPY_DST, vt.texture.desc.layout));
|
||||
|
||||
if (!vt.residencyMap.IsValid())
|
||||
continue;
|
||||
@@ -1668,6 +1669,46 @@ namespace wi::terrain
|
||||
material_HighAltitude.WriteShaderMaterial(&materials[3]);
|
||||
device->BindDynamicConstantBuffer(materials, 0, cmd);
|
||||
|
||||
static Texture bc1_raw;
|
||||
if (!bc1_raw.IsValid())
|
||||
{
|
||||
TextureDesc td;
|
||||
td.width = 512 / 4;
|
||||
td.height = 256 / 4;
|
||||
td.format = Format::R32G32_UINT;
|
||||
td.bind_flags = BindFlag::UNORDERED_ACCESS;
|
||||
td.layout = ResourceState::UNORDERED_ACCESS;
|
||||
bool success = device->CreateTexture(&td, nullptr, &bc1_raw);
|
||||
assert(success);
|
||||
}
|
||||
static Texture bc3_raw;
|
||||
if (!bc3_raw.IsValid())
|
||||
{
|
||||
TextureDesc td;
|
||||
td.width = 256 / 4;
|
||||
td.height = 256 / 4;
|
||||
td.format = Format::R32G32B32A32_UINT;
|
||||
td.bind_flags = BindFlag::UNORDERED_ACCESS;
|
||||
td.layout = ResourceState::UNORDERED_ACCESS;
|
||||
bool success = device->CreateTexture(&td, nullptr, &bc3_raw);
|
||||
assert(success);
|
||||
}
|
||||
static Texture bc5_raw;
|
||||
if (!bc5_raw.IsValid())
|
||||
{
|
||||
TextureDesc td;
|
||||
td.width = 256 / 4;
|
||||
td.height = 256 / 4;
|
||||
td.format = Format::R32G32B32A32_UINT;
|
||||
td.bind_flags = BindFlag::UNORDERED_ACCESS;
|
||||
td.layout = ResourceState::UNORDERED_ACCESS;
|
||||
bool success = device->CreateTexture(&td, nullptr, &bc5_raw);
|
||||
assert(success);
|
||||
}
|
||||
device->BindUAV(&bc1_raw, 0, cmd);
|
||||
device->BindUAV(&bc3_raw, 1, cmd);
|
||||
device->BindUAV(&bc5_raw, 2, cmd);
|
||||
|
||||
for (const VirtualTexture* vt : virtual_textures_in_use)
|
||||
{
|
||||
for (auto& request : vt->update_requests)
|
||||
@@ -1692,18 +1733,53 @@ namespace wi::terrain
|
||||
std::min(request_lod_resolution.x, vt->texture.sparse_properties->tile_width),
|
||||
std::min(request_lod_resolution.y, vt->texture.sparse_properties->tile_height)
|
||||
);
|
||||
const uint2 bc_size = uint2(
|
||||
(size.x + 3u) / 4u,
|
||||
(size.y + 3u) / 4u
|
||||
);
|
||||
|
||||
TerrainVirtualTexturePush push;
|
||||
push.offset = uint2(
|
||||
request.tile_x * size.x,
|
||||
request.tile_y * size.y
|
||||
);
|
||||
push.resolution_rcp.x = 1.0f / request_lod_resolution.x;
|
||||
push.resolution_rcp.y = 1.0f / request_lod_resolution.y;
|
||||
push.map_type = vt->map_type;
|
||||
push.region_weights_textureRO = device->GetDescriptorIndex(&vt->region_weights_texture, SubresourceType::SRV);
|
||||
push.output_textureRW = device->GetDescriptorIndex(&vt->texture, SubresourceType::UAV, mip);
|
||||
device->PushConstants(&push, sizeof(push), cmd);
|
||||
|
||||
device->Dispatch((size.x + 7u) / 8u, (size.y + 7u) / 8u, 1, cmd);
|
||||
device->Dispatch((bc_size.x + 7u) / 8u, (bc_size.y + 7u) / 8u, 1, cmd);
|
||||
|
||||
// Sadly we can't write directly into block compressed texture, so we must copy from raw block format to real BC format:
|
||||
const Texture* bc_raw = nullptr;
|
||||
switch (vt->map_type)
|
||||
{
|
||||
default:
|
||||
bc_raw = &bc1_raw;
|
||||
break;
|
||||
case MaterialComponent::NORMALMAP:
|
||||
bc_raw = &bc5_raw;
|
||||
break;
|
||||
case MaterialComponent::SURFACEMAP:
|
||||
bc_raw = &bc3_raw;
|
||||
break;
|
||||
}
|
||||
GPUBarrier barrier = GPUBarrier::Image(bc_raw, bc_raw->desc.layout, ResourceState::COPY_SRC);
|
||||
device->Barrier(&barrier, 1, cmd);
|
||||
Box srcbox;
|
||||
srcbox.left = 0;
|
||||
srcbox.right = bc_size.x;
|
||||
srcbox.top = 0;
|
||||
srcbox.bottom = bc_size.y;
|
||||
srcbox.front = 0;
|
||||
srcbox.back = 1;
|
||||
device->CopyTexture(
|
||||
&vt->texture, request.tile_x * size.x, request.tile_y * size.y, 0, mip, 0,
|
||||
bc_raw, 0, 0, cmd, &srcbox
|
||||
);
|
||||
std::swap(barrier.image.layout_before, barrier.image.layout_after);
|
||||
device->Barrier(&barrier, 1, cmd);
|
||||
}
|
||||
}
|
||||
vt->update_requests.clear();
|
||||
|
||||
@@ -9,7 +9,7 @@ namespace wi::version
|
||||
// minor features, major updates, breaking compatibility changes
|
||||
const int minor = 71;
|
||||
// minor bug fixes, alterations, refactors, updates
|
||||
const int revision = 77;
|
||||
const int revision = 78;
|
||||
|
||||
const std::string version_string = std::to_string(major) + "." + std::to_string(minor) + "." + std::to_string(revision);
|
||||
|
||||
|
||||
@@ -508,6 +508,36 @@ ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, WHETHER IN
|
||||
OTHERWISE, ARISING FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM OTHER DEALINGS IN THE FONT
|
||||
SOFTWARE.
|
||||
|
||||
|
||||
###############################################################################################################################
|
||||
|
||||
Compressonator: https://github.com/GPUOpen-Tools/compressonator
|
||||
|
||||
//===============================================================================
|
||||
// Copyright (c) 2021 Advanced Micro Devices, Inc. All rights reserved.
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
//===============================================================================
|
||||
|
||||
|
||||
|
||||
###############################################################################################################################
|
||||
|
||||
###############################################################################################################################
|
||||
|
||||
Reference in New Issue
Block a user