载入中...
搜索中...
未找到
GraphicsInternal.h
浏览该文件的文档.
1#pragma once
2
3// Shared implementation helpers for the Vulkan graphics backend.
4// Re-generated from the merged dev single-TU Graphics.cpp (pure move).
5// Anonymous namespace: each TU gets its own internal copy.
6
8#include "common/Exception.h"
10
11#include <algorithm>
12#include <cmath>
13#include <cstdint>
14#include <cstdio>
15#include <cstdlib>
16#include <cstring>
17#include <memory>
18#include <stdexcept>
19#include <string>
20#include <utility>
21#include <vector>
22#if !defined(_WIN32)
23#include <unistd.h>
24#endif
25
26namespace eve::graphics::vulkan {
27namespace {
28
29
30constexpr auto kHostVisibleCoherent = vk::MemoryPropertyFlagBits::eHostVisible |
31 vk::MemoryPropertyFlagBits::eHostCoherent;
32
33template <typename T, size_t N>
35std::vector<T> embeddedSpirv(const T (&words)[N]) {
36 return {words, words + N};
37}
38
39template <typename Slots>
41auto &currentSlot(Slots &slots, size_t slotCount, size_t slotIndex) {
42 if (slots.size() != slotCount) slots.resize(slotCount);
43 return slots[slotIndex];
44}
45
46template <typename FrameBuffers>
48void releaseFrame2dBuffers(FrameBuffers &buffers) {
49 for (auto &buffer : buffers.solidBufs) buffer.release();
50 buffers.solidBufs.clear();
51 for (auto &buffer : buffers.texBufs) buffer.release();
52 buffers.texBufs.clear();
53}
54
56void setViewportAndScissor(vk::CommandBuffer cb, uint32_t width, uint32_t height) {
57 const vk::Viewport viewport{0.f, 0.f, float(width), float(height), 0.f, 1.f};
58 const vk::Rect2D scissor{{0, 0}, {width, height}};
59 cb.setViewport(0, 1, &viewport);
60 cb.setScissor(0, 1, &scissor);
61}
62
64vk::PipelineLayout createPipelineLayout(vkb::Device &device,
65 vk::DescriptorSetLayout setLayout = {},
66 const vk::PushConstantRange *pushConstant = nullptr) {
67 vk::PipelineLayoutCreateInfo info{};
68 if (setLayout) {
69 info.setLayoutCount = 1;
70 info.pSetLayouts = &setLayout;
71 }
72 if (pushConstant) {
73 info.pushConstantRangeCount = 1;
74 info.pPushConstantRanges = pushConstant;
75 }
76 return device->createPipelineLayout(info);
77}
78
80vk::PushConstantRange pushConstantRange(vk::ShaderStageFlags stages, uint32_t size) {
81 vk::PushConstantRange range{};
82 range.stageFlags = stages;
83 range.size = size;
84 return range;
85}
86
88void destroySampler(vkb::Device &device, vk::Sampler &sampler) {
89 if (!sampler) return;
90 device->destroySampler(sampler);
91 sampler = vk::Sampler{};
92}
93
95void destroyPipeline(vkb::Device &device, vk::Pipeline &pipeline) {
96 if (!pipeline) return;
97 device->destroyPipeline(pipeline);
98 pipeline = vk::Pipeline{};
99}
100
102void destroyPipelineLayout(vkb::Device &device, vk::PipelineLayout &layout) {
103 if (!layout) return;
104 device->destroyPipelineLayout(layout);
105 layout = vk::PipelineLayout{};
106}
107
111vkb::HostVertexBuffer &meshDrawVertices(GpuMesh &mesh) {
112 if (!mesh.dynamic) return mesh.vertices;
113 const size_t slot = size_t((mesh.dynamicWriteCount - 1) % GpuMesh::kDynamicVertexCopies);
114 return mesh.dynVertices[slot];
115}
116
118vkb::GenericBuffer &meshDrawIndices(GpuMesh &mesh) {
119 if (!mesh.dynamic) return mesh.indices;
120 const size_t slot = size_t((mesh.dynamicWriteCount - 1) % GpuMesh::kDynamicVertexCopies);
121 return mesh.dynIndices[slot];
122}
123
125void drawIndexedMesh(vk::CommandBuffer cb, GpuMesh &mesh, uint32_t count = 1, uint32_t first = 0) {
126 const vk::DeviceSize offset = 0;
127 cb.bindVertexBuffers(0, 1, meshDrawVertices(mesh), &offset);
128 cb.bindIndexBuffer(meshDrawIndices(mesh).buffer, 0, mesh.indexType);
129 cb.drawIndexed(mesh.indexCount, count, 0, 0, first);
130}
131
136void ensureDynamicRing(GpuMesh &gpu) {
137 if (gpu.dynamic) return;
138 gpu.dynamic = true;
139 gpu.dynamicWriteCount = 0;
140 gpu.cpuIndices.resize(gpu.indexCount);
141 if (gpu.indexCount > 0 && gpu.indices.buffer) {
142 void *ptr = gpu.indices.map();
143 if (gpu.indexType == vk::IndexType::eUint16) {
144 const auto *src = static_cast<const uint16_t *>(ptr);
145 for (uint32_t i = 0; i < gpu.indexCount; ++i)
146 gpu.cpuIndices[size_t(i)] = src[i];
147 } else {
149 std::memcpy(gpu.cpuIndices.data(), ptr,
151 size_t(gpu.indexCount) * sizeof(uint32_t));
152 }
153 gpu.indices.unmap();
154 }
155 gpu.indexType = vk::IndexType::eUint32;
156}
157
161void writeDynamicMesh(GpuMesh &gpu, const std::vector<MeshVertex> &verts, vkb::Device &device,
162 vkb::FrameSlot frame, const uint32_t *indices, int indexCount) {
163 const size_t slot = size_t(gpu.dynamicWriteCount % GpuMesh::kDynamicVertexCopies);
164 gpu.vertexCount = uint32_t(verts.size());
165 gpu.dynVertices[slot].allocate<MeshVertex>(frame, device, verts);
166 if (indices && indexCount > 0) {
167 gpu.cpuIndices.assign(indices, indices + indexCount);
168 gpu.indexCount = uint32_t(indexCount);
169 }
170 if (!gpu.cpuIndices.empty()) {
171 auto &ib = gpu.dynIndices[slot];
172 ib.allocate(frame, device, vk::BufferUsageFlagBits::eIndexBuffer,
174 vk::DeviceSize(gpu.cpuIndices.size()) * sizeof(uint32_t),
175 kHostVisibleCoherent);
176 ib.updateLocal(frame, gpu.cpuIndices.data(),
178 vk::DeviceSize(gpu.cpuIndices.size()) * sizeof(uint32_t));
179 }
180 ++gpu.dynamicWriteCount;
181}
182
184std::unique_ptr<GpuMesh> uploadGpuMesh(vkb::Device &device, vkb::FrameSlot frame,
185 const std::vector<MeshVertex> &vertices,
186 const std::vector<uint32_t> &indices) {
187 auto gpu = std::make_unique<GpuMesh>();
188 gpu->vertexCount = uint32_t(vertices.size());
189 gpu->vertices.allocate<MeshVertex>(frame, device, vertices);
190 gpu->indices.allocate(frame, device, vk::BufferUsageFlagBits::eIndexBuffer,
191 indices.size() * sizeof(uint32_t), kHostVisibleCoherent);
192 gpu->indices.updateLocal(frame, indices.data(), indices.size() * sizeof(uint32_t));
193 gpu->indexCount = uint32_t(indices.size());
194 return gpu;
195}
196
199std::unique_ptr<GpuMesh> uploadGpuMesh16(vkb::Device &device, vkb::FrameSlot frame,
200 const std::vector<MeshVertex> &vertices,
201 const std::vector<uint16_t> &indices) {
202 auto gpu = std::make_unique<GpuMesh>();
203 gpu->vertexCount = uint32_t(vertices.size());
204 gpu->vertices.allocate<MeshVertex>(frame, device, vertices);
205 gpu->indices.allocate(frame, device, vk::BufferUsageFlagBits::eIndexBuffer,
206 indices.size() * sizeof(uint16_t), kHostVisibleCoherent);
207 gpu->indices.updateLocal(frame, indices.data(), indices.size() * sizeof(uint16_t));
208 gpu->indexCount = uint32_t(indices.size());
209 gpu->indexType = vk::IndexType::eUint16;
210 return gpu;
211}
212
214std::unique_ptr<Mesh> makeMeshHandle(GpuMesh &gpu) {
215 auto mesh = std::make_unique<Mesh>();
216 mesh->indexCount = int(gpu.indexCount);
217 mesh->gpuVertexCount = int(gpu.vertexCount);
218 mesh->gpuHandle = &gpu;
219 return mesh;
220}
221
223void assignMeshBounds(Mesh *mesh, const std::vector<MeshVertex> &verts) {
224 if (!mesh || verts.empty()) return;
226 glm::vec3 c(0.f);
227 for (const auto &v : verts) c += v.pos;
228 c /= float(verts.size());
229 mesh->boundsCx = c.x;
230 mesh->boundsCy = c.y;
231 mesh->boundsCz = c.z;
232 float r = 0.f;
233 for (const auto &v : verts) {
234 const glm::vec3 d = v.pos - c;
235 const float len = std::sqrt(d.x * d.x + d.y * d.y + d.z * d.z);
236 if (len > r) r = len;
237 }
238 // Same degenerate-mesh rule as Mesh::computeBounds: keep a tiny non-zero
239 // sphere so hasBounds() stays meaningful for culling.
240 mesh->boundsRadius = r > 0.f ? r : 1e-4f;
241}
242
245void updateRingLocal(vkb::GenericBuffer &ring, vk::DeviceSize byteOffset, const void *data,
246 vk::DeviceSize bytes) {
247 if (!ring.buffer || !data || bytes == 0) return;
248 void *ptr = ring.map();
250 std::memcpy(static_cast<char *>(ptr) + byteOffset, data, size_t(bytes));
251 ring.unmap();
252}
253
254template <typename T>
256inline T alignUpValue(T value, T align) {
257 return align > 0 ? (value + align - 1) / align * align : value;
258}
259
261vk::PipelineColorBlendAttachmentState makeBlendAttachment(BlendMode mode) {
262 vk::PipelineColorBlendAttachmentState att{};
263 att.colorWriteMask =
264 vk::ColorComponentFlagBits::eR | vk::ColorComponentFlagBits::eG |
265 vk::ColorComponentFlagBits::eB | vk::ColorComponentFlagBits::eA;
266 att.blendEnable = true;
267 if (mode == BlendMode::Additive) {
268 att.srcColorBlendFactor = vk::BlendFactor::eSrcAlpha;
269 att.dstColorBlendFactor = vk::BlendFactor::eOne;
270 att.colorBlendOp = vk::BlendOp::eAdd;
271 att.srcAlphaBlendFactor = vk::BlendFactor::eOne;
272 att.dstAlphaBlendFactor = vk::BlendFactor::eOne;
273 att.alphaBlendOp = vk::BlendOp::eAdd;
274 } else if (mode == BlendMode::Premultiplied) {
275 att.srcColorBlendFactor = vk::BlendFactor::eOne;
276 att.dstColorBlendFactor = vk::BlendFactor::eOneMinusSrcAlpha;
277 att.colorBlendOp = vk::BlendOp::eAdd;
278 att.srcAlphaBlendFactor = vk::BlendFactor::eOne;
279 att.dstAlphaBlendFactor = vk::BlendFactor::eOneMinusSrcAlpha;
280 att.alphaBlendOp = vk::BlendOp::eAdd;
281 } else if (mode == BlendMode::Multiply) {
282 att.srcColorBlendFactor = vk::BlendFactor::eDstColor;
283 att.dstColorBlendFactor = vk::BlendFactor::eOneMinusSrcAlpha;
284 att.colorBlendOp = vk::BlendOp::eAdd;
285 att.srcAlphaBlendFactor = vk::BlendFactor::eOne;
286 att.dstAlphaBlendFactor = vk::BlendFactor::eOneMinusSrcAlpha;
287 att.alphaBlendOp = vk::BlendOp::eAdd;
288 } else {
289 att.srcColorBlendFactor = vk::BlendFactor::eSrcAlpha;
290 att.dstColorBlendFactor = vk::BlendFactor::eOneMinusSrcAlpha;
291 att.colorBlendOp = vk::BlendOp::eAdd;
292 att.srcAlphaBlendFactor = vk::BlendFactor::eOne;
293 att.dstAlphaBlendFactor = vk::BlendFactor::eOneMinusSrcAlpha;
294 att.alphaBlendOp = vk::BlendOp::eAdd;
295 }
296 return att;
297}
298
300class ShaderModulePair {
301public:
303 ShaderModulePair(vkb::Device &device, const std::vector<uint32_t> &vert,
304 const std::vector<uint32_t> &frag)
306 : device(device),
308 vert(vkb::PipelineBuilder::createShaderModule(device.instance, vert)),
310 frag(vkb::PipelineBuilder::createShaderModule(device.instance, frag)) {}
311
313 ~ShaderModulePair() {
314 device->destroyShaderModule(vert);
315 device->destroyShaderModule(frag);
316 }
317
318 ShaderModulePair(const ShaderModulePair &) = delete;
319 ShaderModulePair &operator=(const ShaderModulePair &) = delete;
320
321 vkb::Device &device;
322 vk::ShaderModule vert;
323 vk::ShaderModule frag;
324};
325
326
327
329vk::Format pickGBufferColorFormat(vkb::Device &device) {
330 (void)device;
331 return vk::Format::eR8G8B8A8Unorm;
332}
333
335vk::SampleCountFlagBits sampleCountFlagFor(int samples) {
336 if (samples >= 8) return vk::SampleCountFlagBits::e8;
337 if (samples >= 4) return vk::SampleCountFlagBits::e4;
338 if (samples >= 2) return vk::SampleCountFlagBits::e2;
339 return vk::SampleCountFlagBits::e1;
340}
341
342
343
345uint32_t rgba8MipBytes(uint32_t width, uint32_t height) {
346 // Matches VKBuilder GenericImage::upload packing for eR8G8B8A8Unorm.
347 return 4u * width * height;
348}
349
351void appendBoxFilteredMip(std::vector<uint8_t> &out, const uint8_t *src, uint32_t srcW,
352 uint32_t srcH, uint32_t dstW, uint32_t dstH) {
353 const size_t base = out.size();
354 out.resize(base + size_t(rgba8MipBytes(dstW, dstH)));
355 uint8_t *dst = out.data() + base;
356 for (uint32_t y = 0; y < dstH; ++y) {
357 const uint32_t y0 = std::min(y * 2u, srcH - 1u);
358 const uint32_t y1 = std::min(y0 + 1u, srcH - 1u);
359 for (uint32_t x = 0; x < dstW; ++x) {
360 const uint32_t x0 = std::min(x * 2u, srcW - 1u);
361 const uint32_t x1 = std::min(x0 + 1u, srcW - 1u);
362 uint32_t acc[4] = {0, 0, 0, 0};
363 const uint32_t samples[4][2] = {{x0, y0}, {x1, y0}, {x0, y1}, {x1, y1}};
364 for (const auto &s : samples) {
365 const size_t i = (size_t(s[1]) * srcW + s[0]) * 4u;
366 acc[0] += src[i + 0];
367 acc[1] += src[i + 1];
368 acc[2] += src[i + 2];
369 acc[3] += src[i + 3];
370 }
371 const size_t o = (size_t(y) * dstW + x) * 4u;
372 dst[o + 0] = static_cast<uint8_t>((acc[0] + 2u) / 4u);
373 dst[o + 1] = static_cast<uint8_t>((acc[1] + 2u) / 4u);
374 dst[o + 2] = static_cast<uint8_t>((acc[2] + 2u) / 4u);
375 dst[o + 3] = static_cast<uint8_t>((acc[3] + 2u) / 4u);
376 }
377 }
378}
379
382std::vector<uint8_t> buildMipChain2D(const uint8_t *rgba, uint32_t width, uint32_t height,
383 uint32_t mipLevels) {
384 std::vector<uint8_t> packed;
385 packed.reserve(size_t(width) * size_t(height) * 4u * 2u);
386 packed.insert(packed.end(), rgba, rgba + size_t(rgba8MipBytes(width, height)));
387
388 uint32_t srcW = width;
389 uint32_t srcH = height;
390 size_t srcOffset = 0;
391 for (uint32_t level = 1; level < mipLevels; ++level) {
392 const uint32_t dstW = std::max(srcW >> 1, 1u);
393 const uint32_t dstH = std::max(srcH >> 1, 1u);
394 const uint8_t *src = packed.data() + srcOffset;
395 srcOffset = packed.size();
397 appendBoxFilteredMip(packed, src, srcW, srcH, dstW, dstH);
398 srcW = dstW;
399 srcH = dstH;
400 }
401 return packed;
402}
403
409std::vector<uint8_t> buildMipChainCube(const uint8_t *rgbaFaces, uint32_t faceSize,
410 uint32_t mipLevels) {
412 return eve::graphics::buildGgxCubemapMipChain(rgbaFaces, faceSize, mipLevels);
413}
414
416TextureCreateInfo normalizeTextureInfo(TextureCreateInfo info) {
417 if (info.generateMipmaps && info.sampler.mipmap == MipmapMode::Disabled)
418 info.sampler.mipmap = MipmapMode::Linear;
419 if (info.sampler.maxAnisotropy < 1.f) info.sampler.maxAnisotropy = 1.f;
420 return info;
421}
422
423
424
426std::string normalizeTexPath(std::string path) {
427 for (char &c : path) {
428 if (c == '\\') c = '/';
429 }
430 while (path.size() >= 2 && path[0] == '.' && path[1] == '/') path.erase(0, 2);
431 while (path.size() > 1 && path.back() == '/') path.pop_back();
432 return path;
433}
434
435} // namespace
436} // namespace eve::graphics::vulkan
double value
float y
Definition AnimClip.cpp:738
float x
Definition AnimClip.cpp:738
const std::string & s
std::vector< std::uint32_t > verts
Definition Builder.cpp:27
std::string layout
std::uint32_t indexCount
vkb::Device & device
vk::ShaderModule vert
vk::ShaderModule frag
vk::UniqueSampler sampler
double r
std::vector< std::uint32_t > indices
float v
std::int32_t c
std::int32_t first
std::uint32_t height
std::uint32_t width
void * ptr
size_t offset
Range range
std::uint64_t bytes
int level
std::unique_ptr< gpgpu::GpuBuffer > buffer
Definition OnnxGpgpu.cpp:26
std::vector< Point > vertices
std::string path
Definition PlayHost.cpp:110
std::function< eve::Result< void >()> release
Definition Procgen.cpp:86
float d
Mesh * mesh
LocalPageCacheEntry slots[ShadowConfig::kLocalSlots]
std::uint32_t count
float size
Definition TreeMesh.cpp:156
std::vector< uint8_t > buildGgxCubemapMipChain(const uint8_t *rgbaFaces, uint32_t faceSize, uint32_t mipLevels, uint32_t sampleCount=32u)
Build a mip-major RGBA8 IBL chain: GGX specular mips plus final diffuse irradiance.
eve::BlendMode BlendMode
Compatibility alias for the shared 2D blend mode.
Definition BlendMode.h:8
std::string pushConstant()
Pushes constant.
WidgetDesc viewport(std::string id, float width, float height)
Viewport.
Definition Widget.cpp:443
static constexpr size_t kDynamicVertexCopies
Ring copies for per-frame updated meshes (skin/morph/sprite stack). Writing the next copy never races...
Definition Graphics.h:294
glm::uvec4 info