terrain: virtual texture update on async compute

This commit is contained in:
Turánszki János
2022-10-03 15:50:54 +02:00
parent 62b309fbb3
commit 1eba681e74
4 changed files with 80 additions and 70 deletions
+5
View File
@@ -4221,6 +4221,11 @@ void UpdateRenderDataAsync(
}
}
for (size_t i = 0; i < vis.scene->terrains.GetCount(); ++i)
{
vis.scene->terrains[i].UpdateVirtualTextures(cmd);
}
device->EventEnd(cmd);
}
+71 -69
View File
@@ -311,8 +311,7 @@ namespace wi::terrain
// Check whether there are any materials that would write to virtual textures:
bool virtual_texture_any = false;
bool virtual_texture_available[MaterialComponent::TEXTURESLOT_COUNT] = {};
virtual_texture_available[MaterialComponent::SURFACEMAP] = true; // this is always needed to bake individual material properties
virtual_texture_available[MaterialComponent::TEXTURESLOT_COUNT] = {};
MaterialComponent* virtual_materials[4] = {
&material_Base,
&material_Slope,
@@ -323,6 +322,7 @@ namespace wi::terrain
{
for (int i = 0; i < MaterialComponent::TEXTURESLOT_COUNT; ++i)
{
virtual_texture_available[i] = false;
switch (i)
{
case MaterialComponent::BASECOLORMAP:
@@ -339,6 +339,7 @@ namespace wi::terrain
}
}
}
virtual_texture_available[MaterialComponent::SURFACEMAP] = true; // this is always needed to bake individual material properties
for (auto it = chunks.begin(); it != chunks.end();)
{
@@ -552,6 +553,13 @@ namespace wi::terrain
if (need_update)
{
// Shrink the uvs to avoid wrap sampling across edge by object rendering shaders:
float virtual_texture_resolution_rcp = 1.0f / float(chunk_data.required_texture_resolution);
material->texMulAdd.x = float(chunk_data.required_texture_resolution - 1) * virtual_texture_resolution_rcp;
material->texMulAdd.y = float(chunk_data.required_texture_resolution - 1) * virtual_texture_resolution_rcp;
material->texMulAdd.z = 0.5f * virtual_texture_resolution_rcp;
material->texMulAdd.w = 0.5f * virtual_texture_resolution_rcp;
virtual_texture_updates.push_back(chunk);
}
@@ -561,73 +569,6 @@ namespace wi::terrain
it++;
}
// Execute batched virtual texture updates:
if (!virtual_texture_updates.empty())
{
CommandList cmd = device->BeginCommandList();
device->EventBegin("TerrainVirtualTextureUpdate", cmd);
auto range = wi::profiler::BeginRangeGPU("TerrainVirtualTextureUpdate", cmd);
device->Barrier(virtual_texture_barriers_begin.data(), (uint32_t)virtual_texture_barriers_begin.size(), cmd);
device->BindComputeShader(wi::renderer::GetShader(wi::enums::CSTYPE_TERRAIN_VIRTUALTEXTURE_UPDATE), cmd);
ShaderMaterial materials[4];
material_Base.WriteShaderMaterial(&materials[0]);
material_Slope.WriteShaderMaterial(&materials[1]);
material_LowAltitude.WriteShaderMaterial(&materials[2]);
material_HighAltitude.WriteShaderMaterial(&materials[3]);
device->BindDynamicConstantBuffer(materials, 0, cmd);
for (auto& chunk : virtual_texture_updates)
{
auto it = chunks.find(chunk);
if (it == chunks.end())
continue;
ChunkData& chunk_data = it->second;
const GPUResource* res[] = {
&chunk_data.region_weights_texture,
};
device->BindResources(res, 0, arraysize(res), cmd);
MaterialComponent* material = scene->materials.GetComponent(chunk_data.entity);
if (material != nullptr)
{
// Shrink the uvs to avoid wrap sampling across edge by object rendering shaders:
float virtual_texture_resolution_rcp = 1.0f / float(chunk_data.required_texture_resolution);
material->texMulAdd.x = float(chunk_data.required_texture_resolution - 1) * virtual_texture_resolution_rcp;
material->texMulAdd.y = float(chunk_data.required_texture_resolution - 1) * virtual_texture_resolution_rcp;
material->texMulAdd.z = 0.5f * virtual_texture_resolution_rcp;
material->texMulAdd.w = 0.5f * virtual_texture_resolution_rcp;
for (int i = 0; i < MaterialComponent::TEXTURESLOT_COUNT; ++i)
{
if (virtual_texture_available[i])
{
const Texture& texture = material->textures[i].resource.GetTexture();
device->BindUAV(&texture, i, cmd);
device->ClearUAV(&texture, 0, cmd);
if (texture.GetDesc().mip_levels > 1)
{
wi::renderer::AddDeferredMIPGen(material->textures[i].resource.GetTexture());
}
}
}
}
device->Dispatch(chunk_data.required_texture_resolution / 8u, chunk_data.required_texture_resolution / 8u, 1, cmd);
}
device->Barrier(virtual_texture_barriers_end.data(), (uint32_t)virtual_texture_barriers_end.size(), cmd);
wi::renderer::ProcessDeferredMipGenRequests(cmd);
wi::profiler::EndRange(range);
device->EventEnd(cmd);
}
// Start the generation on a background thread and keep it running until the next frame
wi::jobsystem::Execute(generator->workload, [=](wi::jobsystem::JobArgs args) {
@@ -974,6 +915,67 @@ namespace wi::terrain
generator->cancelled.store(false); // the next generation can run
}
void Terrain::UpdateVirtualTextures(CommandList cmd) const
{
if (virtual_texture_updates.empty())
return;
GraphicsDevice* device = GetDevice();
device->EventBegin("TerrainVirtualTextureUpdate", cmd);
auto range = wi::profiler::BeginRangeGPU("TerrainVirtualTextureUpdate", cmd);
device->Barrier(virtual_texture_barriers_begin.data(), (uint32_t)virtual_texture_barriers_begin.size(), cmd);
device->BindComputeShader(wi::renderer::GetShader(wi::enums::CSTYPE_TERRAIN_VIRTUALTEXTURE_UPDATE), cmd);
ShaderMaterial materials[4];
material_Base.WriteShaderMaterial(&materials[0]);
material_Slope.WriteShaderMaterial(&materials[1]);
material_LowAltitude.WriteShaderMaterial(&materials[2]);
material_HighAltitude.WriteShaderMaterial(&materials[3]);
device->BindDynamicConstantBuffer(materials, 0, cmd);
for (auto& chunk : virtual_texture_updates)
{
auto it = chunks.find(chunk);
if (it == chunks.end())
continue;
const ChunkData& chunk_data = it->second;
const GPUResource* res[] = {
&chunk_data.region_weights_texture,
};
device->BindResources(res, 0, arraysize(res), cmd);
const MaterialComponent* material = scene->materials.GetComponent(chunk_data.entity);
if (material != nullptr)
{
for (int i = 0; i < MaterialComponent::TEXTURESLOT_COUNT; ++i)
{
if (virtual_texture_available[i])
{
const Texture& texture = material->textures[i].resource.GetTexture();
device->BindUAV(&texture, i, cmd);
if (texture.GetDesc().mip_levels > 1)
{
wi::renderer::AddDeferredMIPGen(material->textures[i].resource.GetTexture());
}
}
}
}
device->Dispatch(chunk_data.required_texture_resolution / 8u, chunk_data.required_texture_resolution / 8u, 1, cmd);
}
device->Barrier(virtual_texture_barriers_end.data(), (uint32_t)virtual_texture_barriers_end.size(), cmd);
wi::renderer::ProcessDeferredMipGenRequests(cmd);
wi::profiler::EndRange(range);
device->EventEnd(cmd);
}
void Terrain::BakeVirtualTexturesToFiles()
{
if (terrainEntity == INVALID_ENTITY)
+3
View File
@@ -119,6 +119,7 @@ namespace wi::terrain
wi::vector<Chunk> virtual_texture_updates;
wi::vector<wi::graphics::GPUBarrier> virtual_texture_barriers_begin;
wi::vector<wi::graphics::GPUBarrier> virtual_texture_barriers_end;
bool virtual_texture_available[wi::scene::MaterialComponent::TEXTURESLOT_COUNT] = {};
constexpr bool IsCenterToCamEnabled() const { return _flags & CENTER_TO_CAM; }
constexpr bool IsRemovalEnabled() const { return _flags & REMOVAL; }
@@ -161,6 +162,8 @@ namespace wi::terrain
void Generation_Update(const wi::scene::CameraComponent& camera);
// Tells the generation thread that it should be cancelled and blocks until that is confirmed
void Generation_Cancel();
// Updates the virtual textures on GPU by compute shaders
void UpdateVirtualTextures(wi::graphics::CommandList cmd) const;
// The virtual textures will be compressed and saved into resources. They can be serialized from there
void BakeVirtualTexturesToFiles();
// Creates the blend weight texture for a chunk data
+1 -1
View File
@@ -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 = 66;
const int revision = 67;
const std::string version_string = std::to_string(major) + "." + std::to_string(minor) + "." + std::to_string(revision);