载入中...
搜索中...
未找到
TerrainDetailGpuResolver.cpp
浏览该文件的文档.
2
7#include "graphics/Graphics.h"
8#include "graphics/Material.h"
9
10#include <cstdio>
11#include <glm/gtc/type_ptr.hpp>
12#include <map>
13
14namespace eve::asset_procgen {
15namespace {}
16
18 Impl(const asset::EvpackResourceReader& sourceReader, const asset::EvpackCapabilities& sourceCapabilities,
19 graphics::Graphics& sourceGraphics)
20 : reader(sourceReader), capabilities(sourceCapabilities), graphics(sourceGraphics), meshes(sourceGraphics),
21 images(sourceGraphics) {}
27 struct Resource {
28 graphics::Mesh* mesh = nullptr;
30 std::unique_ptr<graphics::Material> material;
31 std::unique_ptr<asset_graphics::EvpackStaticPrefab> prefab;
33 };
34 std::map<std::string, Resource> resources;
35};
36
38 const asset::EvpackCapabilities& capabilities,
39 graphics::Graphics& graphics)
40 : impl_(std::make_unique<Impl>(reader, capabilities, graphics)) {}
41
43 auto result = release();
44 if (!result) std::fprintf(stderr, "terrain Detail GPU release failed: %s\n", result.error()->message().c_str());
45}
46
48 const asset::EvpackCapabilities& capabilities,
49 graphics::Graphics& graphics)
50 : resolver_(std::make_unique<TerrainDetailGpuResolver>(reader, capabilities, graphics)) {}
51
53 const asset::EvpackResourceReader& reader, const asset::EvpackCapabilities& capabilities,
54 graphics::Graphics& graphics, const AssetRef& asset, const TerrainVegetationLimits& limits) {
55 EvpackInstanceSetLoader loader(reader);
56 auto loaded = loader.load(asset, capabilities);
57 if (!loaded) return Result<std::unique_ptr<TerrainDetailRuntime>>::failure(loaded.status());
58 auto realization = realizeTerrainVegetation(nullptr, &loaded.value(), limits);
59 if (!realization)
60 return Result<std::unique_ptr<TerrainDetailRuntime>>::failure(realization.status());
61
62 auto runtime = std::unique_ptr<TerrainDetailRuntime>(
63 new TerrainDetailRuntime(reader, capabilities, graphics));
64 // Resolve and validate every prototype before RenderSystem3D opens a frame. GPU uploads from the collector
65 // callback can wait on the active frame and deadlock; publication is therefore deferred until preparation passes.
66 auto prepared = buildTerrainVegetationGpuPlan(realization.value(), *runtime->resolver_, {});
67 if (!prepared) return Result<std::unique_ptr<TerrainDetailRuntime>>::failure(prepared.status());
68 runtime->renderer_ = std::make_unique<TerrainVegetationRenderer>(
69 std::move(realization).takeValue(), *runtime->resolver_);
70 return Result<std::unique_ptr<TerrainDetailRuntime>>::success(std::move(runtime));
71}
72
74 auto result = release();
75 if (!result) std::fprintf(stderr, "terrain Detail runtime release failed: %s\n",
76 result.error()->message().c_str());
77}
78
80 if (!renderer_)
81 return Result<void>::failure(Diagnostic::error(DiagnosticCode::Conflict, "terrain Detail runtime is released",
82 {}, {}, "asset.procgen.terrainDetailGpu"));
83 return renderer_->setFrame(frame);
84}
85
87 return renderer_ ? renderer_->lastSubmissionError() : nullptr;
88}
89
91 renderer_.reset();
92 if (!resolver_) return Result<void>::success();
93 auto released = resolver_->release();
94 if (!released) return released;
95 resolver_.reset();
96 return Result<void>::success();
97}
98
101 if (!request.detail)
103 Diagnostic::error(DiagnosticCode::NotFound, "terrain Detail metadata is required",
104 std::string(request.prototype), {}, "asset.procgen.terrainDetailGpu"));
105 const auto& detail = *request.detail;
106 if (detail.resourceAsset.empty())
108 Diagnostic::error(DiagnosticCode::NotFound, "terrain Detail resource is unresolved", detail.prototype, {},
109 "asset.procgen.terrainDetailGpu"));
110 const std::string key = detail.prototype + "\n" + detail.renderMode + "\n" + detail.resourceAsset;
111 if (const auto found = impl_->resources.find(key); found != impl_->resources.end()) {
112 if (found->second.slots.parts.empty() &&
113 (found->second.slots.meshId == graphics::kInvalidGpuDrivenSlot ||
114 found->second.slots.materialId == graphics::kInvalidGpuDrivenSlot))
116 Diagnostic::error(DiagnosticCode::Conflict, "terrain Detail resource cleanup is pending",
117 detail.prototype, {}, "asset.procgen.terrainDetailGpu"));
119 }
120 auto reference = AssetRef::parse(detail.resourceAsset);
122 if (detail.usePrototypeMesh || detail.renderMode == "VertexLit") {
123 auto prefab = asset_graphics::EvpackStaticPrefab::load(impl_->reader, impl_->meshes, impl_->images,
124 reference.value(), impl_->capabilities);
126 auto parts = prefab.value()->prepareGpuDriven(impl_->graphics);
129 resource.prefab = std::move(prefab).takeValue();
130 resource.slots.parts.reserve(parts.value().size());
131 for (const auto& source : parts.value())
132 resource.slots.parts.push_back({source.localTransform, source.meshId, source.materialId, source.flags,
133 source.lodGroupId});
134 const auto slots = resource.slots;
135 impl_->resources.emplace(key, std::move(resource));
137 }
138 auto geometry = buildTerrainDetailCard(detail);
139 if (!geometry) return Result<TerrainVegetationGpuPrototype>::failure(geometry.status());
140 auto mesh = impl_->meshes.uploadMesh(geometry.value().positions.data(), geometry.value().normals.data(),
141 geometry.value().texcoords.data(),
142 static_cast<int>(geometry.value().positions.size() / 3),
143 geometry.value().indices.data(), static_cast<int>(geometry.value().indices.size()));
145 asset_graphics::EvpackImageLoader imageLoader(impl_->reader, impl_->images);
146 auto image = imageLoader.load(reference.value(), impl_->capabilities);
147 if (!image) {
148 auto released = impl_->meshes.releaseMesh(mesh.value());
149 if (!released) {
150 Impl::Resource cleanup;
151 cleanup.mesh = mesh.value();
152 impl_->resources.emplace(key, std::move(cleanup));
153 return Result<TerrainVegetationGpuPrototype>::failure(released.status());
154 }
156 }
157 Impl::Resource resource;
158 resource.mesh = mesh.value();
159 resource.texture = image.value().texture;
160 resource.material = std::make_unique<graphics::Material>();
161 resource.material->setSurfaceMode("masked");
162 resource.material->setAlphaCutoff(.5f);
163 resource.material->setDoubleSided(true);
164 resource.material->setCameraFacing(geometry.value().cameraFacing);
165 resource.material->setAlbedoTexture(resource.texture);
166 resource.material->setRoughness(1.f);
167 if (!impl_->graphics.gpuDrivenMaterialUsable(resource.material.get())) {
168 auto imageReleased = impl_->images.releaseImage(resource.texture);
169 auto meshReleased = impl_->meshes.releaseMesh(resource.mesh);
170 if (imageReleased) resource.texture = nullptr;
171 if (meshReleased) resource.mesh = nullptr;
172 if (!imageReleased || !meshReleased) {
173 const auto status = !imageReleased ? imageReleased.status() : meshReleased.status();
174 impl_->resources.emplace(key, std::move(resource));
176 }
178 DiagnosticCode::Unsupported, "terrain Detail material is unavailable to GPU-driven rendering",
179 detail.prototype, {}, "asset.procgen.terrainDetailGpu"));
180 }
181 resource.slots.meshId = impl_->graphics.gpuDrivenMeshRecord(resource.mesh);
182 resource.slots.materialId = impl_->graphics.gpuDrivenMaterialRecord(resource.material.get());
183 if (resource.slots.meshId == graphics::kInvalidGpuDrivenSlot ||
184 resource.slots.materialId == graphics::kInvalidGpuDrivenSlot) {
185 auto materialReleased = impl_->graphics.gpuDrivenReleaseMaterialRecord(resource.material.get());
186 auto imageReleased = impl_->images.releaseImage(resource.texture);
187 auto meshReleased = impl_->meshes.releaseMesh(resource.mesh);
188 if (materialReleased) resource.material.reset();
189 if (imageReleased) resource.texture = nullptr;
190 if (meshReleased) resource.mesh = nullptr;
191 if (!materialReleased || !imageReleased || !meshReleased) {
192 const auto status = !materialReleased ? materialReleased.status()
193 : !imageReleased ? imageReleased.status()
194 : meshReleased.status();
195 impl_->resources.emplace(key, std::move(resource));
197 }
199 Diagnostic::error(DiagnosticCode::Failed, "terrain Detail GPU table registration failed", detail.prototype,
200 {}, "asset.procgen.terrainDetailGpu"));
201 }
202 const auto slots = resource.slots;
203 impl_->resources.emplace(key, std::move(resource));
205}
206
207Result<void> TerrainDetailGpuResolver::drawShadow(
208 const TerrainVegetationGpuPrototypeRequest& request, const std::array<float, 16>& transform,
209 const std::array<float, 16>& lightViewProjection) {
210 if (!request.detail)
212 Diagnostic::error(DiagnosticCode::NotFound, "terrain Detail shadow metadata is required",
213 std::string(request.prototype), {}, "asset.procgen.terrainDetailGpu"));
214 const auto& detail = *request.detail;
215 const std::string key = detail.prototype + "\n" + detail.renderMode + "\n" + detail.resourceAsset;
216 const auto found = impl_->resources.find(key);
217 // Shadow passes precede the frame's GPU collector. The first frame prepares the resource in that collector;
218 // subsequent shadow passes consume it. Uploading inside an active shadow render pass can deadlock the backend.
219 if (found == impl_->resources.end()) return Result<void>::success();
220 if (found->second.prefab)
221 return found->second.prefab->drawShadow(impl_->graphics, transform, lightViewProjection);
222 if (!found->second.mesh || !found->second.texture)
224 "terrain Detail shadow resource cleanup is pending",
225 detail.prototype, {}, "asset.procgen.terrainDetailGpu"));
226 const glm::mat4 lightMvp = glm::make_mat4(lightViewProjection.data()) * glm::make_mat4(transform.data());
227 impl_->graphics.drawMeshShadowAlpha(found->second.mesh, lightMvp, found->second.texture, true);
228 return Result<void>::success();
229}
230
231Result<void> TerrainDetailGpuResolver::release() {
232 Status failed;
233 for (auto iterator = impl_->resources.begin(); iterator != impl_->resources.end();) {
234 if (iterator->second.material) {
235 auto material = impl_->graphics.gpuDrivenReleaseMaterialRecord(iterator->second.material.get());
236 if (material)
237 iterator->second.material.reset();
238 else
239 failed = material.status();
240 }
241 if (iterator->second.prefab) {
242 auto prefab = iterator->second.prefab->release();
243 if (prefab)
244 iterator->second.prefab.reset();
245 else
246 failed = prefab.status();
247 }
250 if (iterator->second.texture) {
251 image = impl_->images.releaseImage(iterator->second.texture);
252 if (image) iterator->second.texture = nullptr;
253 }
254 if (iterator->second.mesh) {
255 mesh = impl_->meshes.releaseMesh(iterator->second.mesh);
256 if (mesh) iterator->second.mesh = nullptr;
257 }
258 if (!iterator->second.texture && !iterator->second.mesh && !iterator->second.material &&
259 !iterator->second.prefab)
260 iterator = impl_->resources.erase(iterator);
261 else {
262 failed = !image ? image.status() : mesh.status();
263 ++iterator;
264 }
265 }
266 if (failed.isFailure()) return Result<void>::failure(failed);
267 return Result<void>::success();
268}
269
270} // namespace eve::asset_procgen
std::vector< eve::artifact::PartView > parts
std::string prefab
AuthorityStoreHandleRef reference
Definition Authority.cpp:24
Transactional graphics consumers for canonical runtime assets.
Transactional EVIMG runtime texture loading.
const GltfImportRequest & request
std::uint32_t key
vk::UniqueImage image
wgpu::PopErrorScopeStatus status
int detail
Mesh * mesh
Material * material
bool found
std::string resource
LocalPageCacheEntry slots[ShadowConfig::kLocalSlots]
Canonical card geometry for texture-backed Unity terrain details.
Default GPU resolver for Unity terrain Detail resources.
const UnitySourceAsset & source
const AssetImportLimits & limits
Stable asset identity backed by PersistentId.
Definition ResourceRef.h:53
static Result< AssetRef > parse(std::string_view text)
Parse an asset://<canonical UUID> reference.
A structured explanation of a failed, degraded, or noteworthy result.
Definition Diagnostic.h:94
static Diagnostic error(DiagnosticCode code, std::string message, std::string path={}, DiagnosticDetails details={}, std::string source={})
Construct an error diagnostic with the standard error severity.
Definition Diagnostic.h:125
Move-only operation result carrying either a value or Status.
Definition Result.h:155
static Result success(T value)
Construct a successful result owning value.
Definition Result.h:164
static Result failure(Status status)
Construct a failed result from a structured status.
Definition Result.h:175
Structured status and zero or more diagnostics for an operation.
Definition Status.h:68
Immutable reader retaining an admitted pack by shared ownership.
Capability-aware adapter from admitted EVIMG assets to backend textures.
static Result< std::unique_ptr< EvpackStaticPrefab > > load(const asset::EvpackResourceReader &reader, graphics::IMeshResourceFactory &meshes, graphics::IImageResourceFactory &images, const AssetRef &asset, const asset::EvpackCapabilities &capabilities)
Validate a template and stage its mesh, material and image dependencies; failures release staged uplo...
Result-based adapter over the engine's established graphics resource factory.
Result-based adapter over the engine's established graphics resource factory.
Capability-aware eve.instance-set/5 EVINST decoder with v1-v4 compatibility.
Result< LoadedInstanceSet > load(const AssetRef &instances, const asset::EvpackCapabilities &capabilities, const InstanceSetLoadLimits &limits={}) const
Validate metadata, exact byte layout and every TRS record transactionally.
Owning lazy GPU resource resolver for texture-backed terrain Detail prototypes. @ownership Uploaded m...
Result< TerrainVegetationGpuPrototype > resolve(const TerrainVegetationGpuPrototypeRequest &prototype) override
Load and cache one Detail card, image, and masked material transactionally.
~TerrainDetailGpuResolver() override
Releases TerrainDetailGpuResolver resources.
TerrainDetailGpuResolver(const asset::EvpackResourceReader &reader, const asset::EvpackCapabilities &capabilities, graphics::Graphics &graphics)
Constructs a TerrainDetailGpuResolver.
Result< void > release()
Release all backend leases; failed releases remain owned for retry.
Owning runtime for one cooked Unity Terrain Detail instance set. @ownership Owns the realization,...
static Result< std::unique_ptr< TerrainDetailRuntime > > load(const asset::EvpackResourceReader &reader, const asset::EvpackCapabilities &capabilities, graphics::Graphics &graphics, const AssetRef &asset, const TerrainVegetationLimits &limits={})
Load, realize, and register one Detail set atomically; GPU resources resolve on first render.
Result< void > setFrame(TerrainVegetationGpuFrame frame)
Update the absolute simulation time used for deterministic grass motion.
TerrainDetailRuntime(const TerrainDetailRuntime &)=delete
Result< void > release()
Unregister rendering and release all backend resources; safe to retry after failure.
~TerrainDetailRuntime()
Releases TerrainDetailRuntime resources.
const Diagnostic * lastSubmissionError() const
Return the latest asynchronous render-submission diagnostic, if any. @ownership Borrowed; the runtime...
GPU mesh handle (+ optional CPU morph targets).
Definition Mesh.h:25
GPU texture created via Graphics::newTexture. Owns GPU resources through an opaque backend handle.
Definition Texture.h:18
Result< TerrainVegetationRealization > realizeTerrainVegetation(LoadedPointGraph *graph, const LoadedInstanceSet *explicitInstances, const TerrainVegetationLimits &limits)
Execute an optional terrain PCG graph and merge an optional baked instance set.
Result< TerrainDetailCardGeometry > buildTerrainDetailCard(const RuntimeInstancePrototype &prototype)
Build bottom-anchored unit cards for a texture-backed terrain Detail prototype.
Result< TerrainVegetationGpuPlan > buildTerrainVegetationGpuPlan(const TerrainVegetationRealization &realization, ITerrainVegetationGpuResolver &resolver, const TerrainVegetationGpuFrame &frame)
Resolve every prototype and build GPU records transactionally.
constexpr uint32_t kInvalidGpuDrivenSlot
GPU-driven rendering shared constants + std430 GPU layouts.
Actual runtime device capabilities used for variant selection.
Definition Evpack.h:92
std::unique_ptr< asset_graphics::EvpackStaticPrefab > prefab
Impl(const asset::EvpackResourceReader &sourceReader, const asset::EvpackCapabilities &sourceCapabilities, graphics::Graphics &sourceGraphics)
asset_graphics::GraphicsImageFactoryAdapter images
asset_graphics::GraphicsMeshFactoryAdapter meshes
Explicit frame inputs for deterministic terrain Detail animation.
One owning realization's prototype request passed to the graphics resource provider.
GPU table slots resolved for one vegetation prototype.
Hard limits for one deterministic terrain vegetation realization.