Files
AyeZeeBB 164fdffbd0 Descriptor heaps: dense custom maps no longer overflow the GPU's descriptor heap and crash it
The renderer gives each frame 131,072 shader-visible descriptors past a persistent 120,000, in
heaps of 333,333. Dense custom maps (the Los Santos City sublevels, San Andreas) draw more than
that in a frame, and the renderer wrote past the end of the heap: shaders read garbage
descriptors, which faulted or hung the GPU (page faults at nonsense addresses, in draws, texture
fetches and ray tracing alike). ReSkate now patches the device setup at boot so each heap is
D3D12's 1,000,000 and a frame may use 524,288; heaps are 644,288 descriptors. LS-B2, LS-B3 and
San Andreas (210,000 a frame at its peak) now hold.

Also in this change:
- Memory: perf memory owners/heap/gpu/report, a ledger of who commits the game's RAM; the
  render-resource pool no longer allocates its 115 MB twice; the EadpErrorsData arena is
  capped at 32 MiB (EA's error reporting is blocked anyway).
- Crash reports: tagged with the map, destination, graphics card and driver version (protocol
  v3), so Sentry can group GPU hangs by map and card.
- GPU diagnostics (--gpu-diagnostics): a fuller DRED report, the device-removal and video
  memory watches, a large-draw watch, a record of which game code made and freed each GPU heap
  and resource, checks of every GPU address bound, and a meter of each descriptor heap's use.
- World pools: peak use of entity pages, render instances and spatial blocks in the log.
- dingosdk_mod_mesh_check: checks every MeshSet a mod ships against its geometry; the MeshSet
  reader now knows static meshes' layout.
2026-10-15 13:57:11 -05:00

54 lines
3.1 KiB
C++

#pragma once
// Frostbite skinned MeshSet resources: one level of detail's triangles, and how each vertex is
// weighted to the skeleton's bones. Only what a skinned mesh needs; the layout was worked out
// on skate.'s costume meshes, first by gBGYo's ReSkate fork (github.com/gBGYo/ReSkate).
#include "binary_io.h"
#include <array>
#include <cstddef>
#include <cstdint>
#include <span>
#include <string>
#include <vector>
namespace dingosdk::frostbite {
struct MeshLod {
Guid chunk; // the geometry chunk: the vertex buffer, then the index buffer
std::uint32_t vertex_bytes{}, index_bytes{};
};
// The `lod`-th level of detail (0 the finest) of a MeshSet resource. Throws for a layout this
// reader does not know.
[[nodiscard]] MeshLod read_mesh_lod(std::span<const std::byte> resource, std::size_t lod);
// What a geometry comparison needs, of any MeshSet of the known layout, skinned or not and
// whatever its index size: how many levels of detail it has, a level's geometry chunk, and
// where that level's vertices are. Nothing of the skinning is read, so a mesh the skinned
// reader refuses for its bones still gives its positions. Throws for another layout, and for
// positions that are not three floats.
[[nodiscard]] std::size_t mesh_lod_count(std::span<const std::byte> resource);
[[nodiscard]] MeshLod mesh_lod_geometry(std::span<const std::byte> resource, std::size_t lod);
[[nodiscard]] std::vector<std::array<float, 3>> read_mesh_positions(std::span<const std::byte> resource, std::size_t lod,
std::span<const std::byte> geometry);
// A level of detail's geometry chunk and buffer sizes, of either layout check_mesh_lod reads (the
// skinned one, and world meshes' static one); `lods` gets how many levels there are.
[[nodiscard]] MeshLod any_mesh_lod_geometry(std::span<const std::byte> resource, std::size_t lod, std::size_t* lods = nullptr);
// What is wrong with a level of detail's geometry as the GPU would read it, a skinned or a static
// MeshSet: a section whose vertices or indices run past their buffer, or a triangle that
// names a vertex outside its section. Empty when it is sound. `index_format` gets the level's
// index format (33: 16-bit; anything else is read as 32-bit). Throws for another layout.
[[nodiscard]] std::vector<std::string> check_mesh_lod(std::span<const std::byte> resource, std::size_t lod,
std::span<const std::byte> geometry, std::uint32_t* index_format = nullptr);
struct SkinnedVertex {
std::array<float, 3> position{}; // model space
std::array<std::uint16_t, 8> bones{}; // skeleton bones
std::array<std::uint8_t, 8> weights{}; // summing to 255; 0 for an unused influence
};
struct SkinnedMesh {
std::vector<SkinnedVertex> vertices;
std::vector<std::uint32_t> triangles; // vertex indices, three a triangle
};
// That level's sections as one mesh, from its geometry chunk. Throws when they do not fit.
[[nodiscard]] SkinnedMesh read_skinned_mesh(std::span<const std::byte> resource, std::size_t lod,
std::span<const std::byte> geometry);
}