mirror of
https://github.com/barkeser2002/flower.git
synced 2026-09-25 18:56:16 +03:00
629 lines
21 KiB
C++
629 lines
21 KiB
C++
#include "gpu_asset.h"
|
|
#include "rhi.h"
|
|
|
|
|
|
#pragma warning(disable: 4006)
|
|
|
|
#include <assimp/Importer.hpp>
|
|
#include <assimp/scene.h>
|
|
#include <assimp/postprocess.h>
|
|
#include <assimp/GltfMaterial.h>
|
|
#include <util/assimp_helper.h>
|
|
|
|
#include <asset/asset_texture.h>
|
|
|
|
namespace engine
|
|
{
|
|
static std::string getRuntimeUniqueGPUAssetName(const std::string& in)
|
|
{
|
|
static size_t GRuntimeId = 0;
|
|
GRuntimeId++;
|
|
return std::format("GPUAssetId: {}. {}.", GRuntimeId, in);
|
|
}
|
|
|
|
GPUImageAsset::GPUImageAsset(
|
|
VulkanContext* context,
|
|
GPUImageAsset* fallback,
|
|
VkFormat format,
|
|
const std::string& name,
|
|
uint32_t mipmapCount,
|
|
uint32_t width,
|
|
uint32_t height,
|
|
uint32_t depth)
|
|
: m_context(context), LRUAssetInterface(fallback)
|
|
{
|
|
CHECK(m_image == nullptr && "You must ensure image asset only init once.");
|
|
|
|
VkImageCreateInfo info{};
|
|
info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
|
|
info.flags = {};
|
|
info.imageType = depth != 1 ? VK_IMAGE_TYPE_3D : VK_IMAGE_TYPE_2D;
|
|
info.format = format;
|
|
info.extent.width = width;
|
|
info.extent.height = height;
|
|
info.extent.depth = depth;
|
|
info.arrayLayers = 1;
|
|
info.mipLevels = mipmapCount;
|
|
info.samples = VK_SAMPLE_COUNT_1_BIT;
|
|
info.tiling = VK_IMAGE_TILING_OPTIMAL;
|
|
info.usage = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
|
|
info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
|
info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
|
|
|
m_image = std::make_unique<VulkanImage>(m_context, getRuntimeUniqueGPUAssetName(name).c_str(), info, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
|
|
}
|
|
|
|
GPUImageAsset::~GPUImageAsset()
|
|
{
|
|
if (m_bindlessIndex != ~0)
|
|
{
|
|
m_context->getBindlessTexture().freeBindlessImpl(m_bindlessIndex, m_context->isReleaseing() ? nullptr : m_context->getEngineTextureWhite()->m_image.get());
|
|
}
|
|
|
|
m_image.reset();
|
|
}
|
|
|
|
void GPUImageAsset::prepareToUpload(RHICommandBufferBase& cmd, VkImageSubresourceRange range)
|
|
{
|
|
CHECK(m_bindlessIndex == ~0);
|
|
m_image->transitionLayout(cmd, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, range);
|
|
}
|
|
|
|
void GPUImageAsset::finishUpload(RHICommandBufferBase& cmd, VkImageSubresourceRange range)
|
|
{
|
|
m_image->transitionLayout(cmd, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, range);
|
|
m_bindlessIndex = m_context->getBindlessTexture().updateTextureToBindlessDescriptorSet(m_image->getOrCreateView(buildBasicImageSubresource(), m_image->getInfo().imageType == VK_IMAGE_TYPE_3D ? VK_IMAGE_VIEW_TYPE_3D : VK_IMAGE_VIEW_TYPE_2D));
|
|
|
|
CHECK(m_bindlessIndex != ~0);
|
|
}
|
|
|
|
void RawAssetTextureLoadTask::uploadFunction(
|
|
uint32_t stageBufferOffset,
|
|
void* bufferPtrStart,
|
|
RHICommandBufferBase& commandBuffer,
|
|
VulkanBuffer& stageBuffer)
|
|
{
|
|
VkImageSubresourceRange rangeAllMips = buildBasicImageSubresource();
|
|
rangeAllMips.levelCount = (uint32_t)cacheBin->mipmapDatas.size();;
|
|
|
|
imageAssetGPU->prepareToUpload(commandBuffer, buildBasicImageSubresource());
|
|
|
|
uint32_t bufferOffset = 0;
|
|
uint32_t bufferSize = 0;
|
|
|
|
VkBufferImageCopy region{};
|
|
region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
|
region.imageSubresource.baseArrayLayer = 0;
|
|
region.imageSubresource.layerCount = 1;
|
|
region.imageOffset = { 0, 0, 0 };
|
|
region.bufferRowLength = 0;
|
|
region.bufferImageHeight = 0;
|
|
|
|
std::vector<VkBufferImageCopy> copyRegions{};
|
|
const auto& mipmapDatas = cacheBin->mipmapDatas;
|
|
for (uint32_t level = 0; level < rangeAllMips.levelCount; level++)
|
|
{
|
|
const auto& currentMip = mipmapDatas.at(level);
|
|
const uint32_t currentMipSize = (uint32_t)currentMip.size();
|
|
|
|
uint32_t mipWidth = std::max<uint32_t>(imageAssetGPU->getImage().getExtent().width >> level, 1);
|
|
uint32_t mipHeight = std::max<uint32_t>(imageAssetGPU->getImage().getExtent().height >> level, 1);
|
|
uint32_t mipDepth = std::max<uint32_t>(imageAssetGPU->getImage().getExtent().depth >> level, 1);
|
|
|
|
memcpy((void*)((char*)bufferPtrStart + bufferOffset), currentMip.data(), currentMipSize);
|
|
|
|
region.bufferOffset = stageBufferOffset + bufferOffset;
|
|
region.imageSubresource.mipLevel = level;
|
|
region.imageExtent = { mipWidth, mipHeight, mipDepth };
|
|
|
|
copyRegions.push_back(region);
|
|
|
|
bufferOffset += currentMipSize;
|
|
bufferSize += currentMipSize;
|
|
}
|
|
|
|
vkCmdCopyBufferToImage(commandBuffer.cmd, stageBuffer, imageAssetGPU->getImage().getImage(), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, (uint32_t)copyRegions.size(), copyRegions.data());
|
|
|
|
imageAssetGPU->finishUpload(commandBuffer, rangeAllMips);
|
|
}
|
|
|
|
extern void buildMipmapDataRGBA8(
|
|
stbi_uc* srcPixels,
|
|
AssetTextureBin& outBinData,
|
|
float alphaCutOff,
|
|
uint32_t mipmapCount,
|
|
bool bSRGB,
|
|
uint32_t inWidth,
|
|
uint32_t inHeight);
|
|
|
|
RawAssetTextureLoadTask::RawAssetTextureLoadTask()
|
|
{
|
|
cacheBin = std::make_unique<AssetTextureBin>();
|
|
}
|
|
|
|
std::shared_ptr<RawAssetTextureLoadTask> RawAssetTextureLoadTask::buildTexture(
|
|
bool bEngineTex,
|
|
VulkanContext* context, const std::filesystem::path& path, const UUID& uuid, VkFormat format, bool bSRGB, bool bMipmap)
|
|
{
|
|
if (bEngineTex)
|
|
{
|
|
ASSERT(!context->isEngineAssetExist(uuid), "Persistent asset has exist, don't register repeatly.");
|
|
}
|
|
else
|
|
{
|
|
if (context->isLRUAssetExist(uuid))
|
|
{
|
|
return nullptr;
|
|
}
|
|
}
|
|
|
|
|
|
int32_t texWidth, texHeight, texChannels;
|
|
stbi_uc* pixels = stbi_load(path.string().c_str(), &texWidth, &texHeight, &texChannels, 4);
|
|
|
|
if (!pixels)
|
|
{
|
|
LOG_ERROR("Fail to load image {0}.", path.string());
|
|
return nullptr;
|
|
}
|
|
|
|
std::shared_ptr<RawAssetTextureLoadTask> newTask = std::make_shared<RawAssetTextureLoadTask>();
|
|
|
|
const bool bPOT = isPOT(texWidth) && isPOT(texHeight);
|
|
uint32_t mipmapCount = 1;
|
|
if (bMipmap && bPOT)
|
|
{
|
|
uint32_t maxDim = math::max(texWidth, texHeight);
|
|
mipmapCount = std::bit_width(maxDim);
|
|
}
|
|
|
|
buildMipmapDataRGBA8(pixels, *newTask->cacheBin, 1.0f, mipmapCount, bSRGB, texWidth, texHeight);
|
|
|
|
auto newAsset = std::make_shared<GPUImageAsset>(
|
|
context,
|
|
bEngineTex ? nullptr : context->getEngineTextureWhite().get(),
|
|
format,
|
|
path.stem().string(),
|
|
mipmapCount,
|
|
texWidth,
|
|
texHeight,
|
|
1);
|
|
|
|
// New engine asset.
|
|
if (bEngineTex)
|
|
{
|
|
context->insertEngineAsset(uuid, newAsset);
|
|
}
|
|
else
|
|
{
|
|
context->insertLRUAsset(uuid, newAsset);
|
|
}
|
|
|
|
newTask->imageAssetGPU = newAsset;
|
|
|
|
stbi_image_free(pixels);
|
|
return newTask;
|
|
}
|
|
|
|
std::shared_ptr<RawAssetTextureLoadTask> RawAssetTextureLoadTask::buildEngine3dTexture(
|
|
VulkanContext* context, const std::filesystem::path& path, const UUID& uuid, VkFormat format,
|
|
math::uvec3 dim)
|
|
{
|
|
ASSERT(!context->isEngineAssetExist(uuid), "Persistent asset has exist, don't register repeatly.");
|
|
|
|
auto newAsset = std::make_shared<GPUImageAsset>(
|
|
context,
|
|
nullptr,
|
|
format,
|
|
path.string(),
|
|
1, // Mipmap count.
|
|
dim.x,
|
|
dim.y,
|
|
dim.z);
|
|
context->insertEngineAsset(uuid, newAsset);
|
|
|
|
std::shared_ptr<RawAssetTextureLoadTask> newTask = std::make_shared<RawAssetTextureLoadTask>();
|
|
newTask->imageAssetGPU = newAsset;
|
|
|
|
newTask->cacheBin->mipmapDatas.resize(1);
|
|
newTask->cacheBin->mipmapDatas[0].resize(dim.x * dim.y * dim.z * 4 * 4);
|
|
|
|
auto file = std::ifstream(path, std::ios::binary);
|
|
|
|
file.seekg(0, std::ios::end);
|
|
int length = (int)file.tellg();
|
|
|
|
CHECK(length == newTask->cacheBin->mipmapDatas[0].size());
|
|
file.seekg(0, std::ios::beg);
|
|
file.read((char*)newTask->cacheBin->mipmapDatas[0].data(), length);
|
|
|
|
return newTask;
|
|
}
|
|
|
|
std::shared_ptr<RawAssetTextureLoadTask> RawAssetTextureLoadTask::buildEngineFlatTexture(
|
|
VulkanContext* context, const std::string& name, const UUID& uuid, const glm::uvec4& color, const glm::uvec3& size, VkFormat format)
|
|
{
|
|
ASSERT(!context->isEngineAssetExist(uuid), "Persistent asset has exist, don't register repeatly.");
|
|
|
|
auto newAsset = std::make_shared<GPUImageAsset>(
|
|
context,
|
|
nullptr,
|
|
format,
|
|
name,
|
|
1, // Mipmap count.
|
|
size.x,
|
|
size.y,
|
|
size.z);
|
|
|
|
// New engine asset.
|
|
context->insertEngineAsset(uuid, newAsset);
|
|
|
|
// Create new task.
|
|
std::shared_ptr<RawAssetTextureLoadTask> newTask = std::make_shared<RawAssetTextureLoadTask>();
|
|
newTask->imageAssetGPU = newAsset;
|
|
|
|
// Prepare upload data.
|
|
newTask->cacheBin->mipmapDatas.resize(1);
|
|
newTask->cacheBin->mipmapDatas[0].resize(size.x * size.y * size.z * 4);
|
|
auto& mip0 = newTask->cacheBin->mipmapDatas[0];
|
|
|
|
for (size_t i = 0; i < mip0.size(); i += 4)
|
|
{
|
|
mip0[i + 0] = uint8_t(color.x);
|
|
mip0[i + 1] = uint8_t(color.y);
|
|
mip0[i + 2] = uint8_t(color.z);
|
|
mip0[i + 3] = uint8_t(color.w);
|
|
}
|
|
|
|
// NOTE: GPU Memory align, which make small texture size min is 512 byte. And may size no equal.
|
|
// But at least one thing is guarantee is that cache data size must less than upload Size.
|
|
CHECK(mip0.size() <= newTask->uploadSize());
|
|
return newTask;
|
|
}
|
|
|
|
GPUStaticMeshAsset::GPUStaticMeshAsset(
|
|
VulkanContext* context,
|
|
UUID assetId,
|
|
GPUStaticMeshAsset* fallback,
|
|
const std::string& name,
|
|
VkDeviceSize tangentSize,
|
|
VkDeviceSize tangentStripSize,
|
|
VkDeviceSize normalSize,
|
|
VkDeviceSize normalStripSize,
|
|
VkDeviceSize uv0Size,
|
|
VkDeviceSize uv0StripSize,
|
|
VkDeviceSize positionsSize,
|
|
VkDeviceSize positionStripSize,
|
|
VkDeviceSize indicesSize,
|
|
VkDeviceSize indexStripSize)
|
|
: m_context(context), LRUAssetInterface(fallback)
|
|
, m_assetId(assetId)
|
|
, m_tangentsSize(tangentSize)
|
|
, m_tangentStripSize(tangentStripSize)
|
|
, m_normalSize(normalSize)
|
|
, m_normalStripSize(normalStripSize)
|
|
, m_uv0Size(uv0Size)
|
|
, m_uv0StripSize(uv0StripSize)
|
|
, m_positionsSize(positionsSize)
|
|
, m_positionStripSize(positionStripSize)
|
|
, m_indicesSize(indicesSize)
|
|
, m_indexStripSize(indexStripSize)
|
|
{
|
|
ASSERT(
|
|
m_tangents == nullptr
|
|
&& m_normals == nullptr
|
|
&& m_uv0s == nullptr
|
|
&& m_indices == nullptr
|
|
&& m_positions == nullptr
|
|
, "You must ensure mesh asset only init once.");
|
|
|
|
// Bindless fetch, transfer copy.
|
|
auto bufferFlagBasic = VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT;
|
|
VmaAllocationCreateFlags bufferFlagVMA = {};
|
|
if (m_context->getGraphicsCardState().bSupportRaytrace)
|
|
{
|
|
// Raytracing accelerate struct, random shader fetch by address.
|
|
bufferFlagBasic |= VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT;
|
|
bufferFlagVMA = {};
|
|
}
|
|
|
|
m_tangents = std::make_unique<VulkanBuffer>(
|
|
m_context,
|
|
getRuntimeUniqueGPUAssetName(name + "_tangents"),
|
|
bufferFlagBasic | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT,
|
|
bufferFlagVMA,
|
|
tangentSize
|
|
);
|
|
m_normals = std::make_unique<VulkanBuffer>(
|
|
m_context,
|
|
getRuntimeUniqueGPUAssetName(name + "_normals"),
|
|
bufferFlagBasic | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT,
|
|
bufferFlagVMA,
|
|
normalSize
|
|
);
|
|
m_uv0s = std::make_unique<VulkanBuffer>(
|
|
m_context,
|
|
getRuntimeUniqueGPUAssetName(name + "_uv0s"),
|
|
bufferFlagBasic | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT,
|
|
bufferFlagVMA,
|
|
uv0Size
|
|
);
|
|
|
|
m_positions = std::make_unique<VulkanBuffer>(
|
|
m_context,
|
|
getRuntimeUniqueGPUAssetName(name + "_positions"),
|
|
bufferFlagBasic | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT,
|
|
bufferFlagVMA,
|
|
positionsSize
|
|
);
|
|
|
|
ASSERT(
|
|
(positionsSize / positionStripSize) == (tangentSize / tangentStripSize) &&
|
|
(positionsSize / positionStripSize) == (normalSize / normalStripSize) &&
|
|
(positionsSize / positionStripSize) == (uv0Size / uv0StripSize)
|
|
, "Vertices data no correct!");
|
|
|
|
m_indices = std::make_unique<VulkanBuffer>(
|
|
m_context,
|
|
getRuntimeUniqueGPUAssetName(name + "_indices"),
|
|
bufferFlagBasic | VK_BUFFER_USAGE_INDEX_BUFFER_BIT,
|
|
bufferFlagVMA,
|
|
indicesSize
|
|
);
|
|
|
|
m_tangentsBindless = m_context->getBindlessSSBOs().updateBufferToBindlessDescriptorSet(m_tangents->getVkBuffer(), 0, m_tangentsSize);
|
|
m_normalsBindless = m_context->getBindlessSSBOs().updateBufferToBindlessDescriptorSet(m_normals->getVkBuffer(), 0, m_normalSize);
|
|
m_uv0sBindless = m_context->getBindlessSSBOs().updateBufferToBindlessDescriptorSet(m_uv0s->getVkBuffer(), 0, m_uv0Size);
|
|
m_indicesBindless = m_context->getBindlessSSBOs().updateBufferToBindlessDescriptorSet(m_indices->getVkBuffer(), 0, m_indicesSize);
|
|
m_positionBindless = m_context->getBindlessSSBOs().updateBufferToBindlessDescriptorSet(m_positions->getVkBuffer(), 0, m_positionsSize);
|
|
}
|
|
|
|
GPUStaticMeshAsset::~GPUStaticMeshAsset()
|
|
{
|
|
if (m_indicesBindless != ~0)
|
|
{
|
|
m_context->getBindlessSSBOs().freeBindlessImpl(m_indicesBindless, m_context->isReleaseing() ? nullptr : m_context->getEngineStaticMeshBox()->getIndices());
|
|
}
|
|
if (m_tangentsBindless != ~0)
|
|
{
|
|
m_context->getBindlessSSBOs().freeBindlessImpl(m_tangentsBindless, m_context->isReleaseing() ? nullptr : m_context->getEngineStaticMeshBox()->getTangents());
|
|
}
|
|
if (m_normalsBindless != ~0)
|
|
{
|
|
m_context->getBindlessSSBOs().freeBindlessImpl(m_normalsBindless, m_context->isReleaseing() ? nullptr : m_context->getEngineStaticMeshBox()->getNormals());
|
|
}
|
|
if (m_uv0sBindless != ~0)
|
|
{
|
|
m_context->getBindlessSSBOs().freeBindlessImpl(m_uv0sBindless, m_context->isReleaseing() ? nullptr : m_context->getEngineStaticMeshBox()->getUv0s());
|
|
}
|
|
if (m_positionBindless != ~0)
|
|
{
|
|
m_context->getBindlessSSBOs().freeBindlessImpl(m_positionBindless, m_context->isReleaseing() ? nullptr : m_context->getEngineStaticMeshBox()->getPosition());
|
|
}
|
|
|
|
m_indicesBindless = ~0;
|
|
m_tangentsBindless = ~0;
|
|
m_uv0sBindless = ~0;
|
|
m_normalsBindless = ~0;
|
|
m_positionBindless = ~0;
|
|
|
|
m_indices.reset();
|
|
m_tangents.reset();
|
|
m_normals.reset();
|
|
m_uv0s.reset();
|
|
m_positions.reset();
|
|
|
|
m_blasBuilder.destroy();
|
|
}
|
|
|
|
BLASBuilder& GPUStaticMeshAsset::getOrBuilddBLAS()
|
|
{
|
|
if (!m_blasBuilder.isInit())
|
|
{
|
|
std::vector<StaticMeshSubMesh> submeshes;
|
|
if (m_context->isEngineAssetExist(m_assetId))
|
|
{
|
|
// Engine asset. one sub mesh.
|
|
submeshes.resize(1);
|
|
submeshes[0].bounds = m_context->getEngineMeshRenderBounds(m_assetId);
|
|
submeshes[0].indicesCount = getIndicesCount();
|
|
submeshes[0].indicesStart = 0;
|
|
submeshes[0].material = {};
|
|
}
|
|
else
|
|
{
|
|
auto asset = std::dynamic_pointer_cast<AssetStaticMesh>(getAssetSystem()->getAsset(m_assetId));
|
|
submeshes = asset->getSubMeshes();
|
|
}
|
|
|
|
const uint32_t maxVertex = getVerticesCount();
|
|
|
|
std::vector<BLASBuilder::BlasInput> allBlas(submeshes.size());
|
|
for (size_t i = 0; i < submeshes.size(); i++)
|
|
{
|
|
const auto& submesh = submeshes[i];
|
|
|
|
const uint32_t maxPrimitiveCount = submesh.indicesCount / 3;
|
|
|
|
// Describe buffer as array of VertexObj.
|
|
VkAccelerationStructureGeometryTrianglesDataKHR triangles{ VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_TRIANGLES_DATA_KHR };
|
|
triangles.vertexFormat = VK_FORMAT_R32G32B32_SFLOAT; // vec3 vertex position data.
|
|
triangles.vertexData.deviceAddress = m_positions->getDeviceAddress();
|
|
triangles.vertexStride = m_positionStripSize;
|
|
triangles.indexType = VK_INDEX_TYPE_UINT32;
|
|
triangles.indexData.deviceAddress = m_indices->getDeviceAddress();
|
|
triangles.maxVertex = maxVertex;
|
|
|
|
// Identify the above data as containing opaque triangles.
|
|
VkAccelerationStructureGeometryKHR asGeom{ VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_KHR };
|
|
asGeom.geometryType = VK_GEOMETRY_TYPE_TRIANGLES_KHR;
|
|
asGeom.flags = VK_GEOMETRY_NO_DUPLICATE_ANY_HIT_INVOCATION_BIT_KHR;
|
|
asGeom.geometry.triangles = triangles;
|
|
|
|
VkAccelerationStructureBuildRangeInfoKHR offset{ };
|
|
offset.firstVertex = 0; // No vertex offset, current all vertex buffer start from zero.
|
|
offset.primitiveCount = maxPrimitiveCount;
|
|
offset.primitiveOffset = submesh.indicesStart * sizeof(VertexIndexType);
|
|
offset.transformOffset = 0;
|
|
|
|
allBlas[i].asGeometry.emplace_back(asGeom);
|
|
allBlas[i].asBuildOffsetInfo.emplace_back(offset);
|
|
}
|
|
m_blasBuilder.build(allBlas,
|
|
VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR |
|
|
VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_COMPACTION_BIT_KHR);
|
|
}
|
|
|
|
return m_blasBuilder;
|
|
}
|
|
|
|
bool GPUStaticMeshAsset::isEngineAsset() const
|
|
{
|
|
return getContext()->isEngineAssetExist(m_assetId);
|
|
}
|
|
|
|
void AssetRawStaticMeshLoadTask::uploadFunction(
|
|
uint32_t stageBufferOffset,
|
|
void* bufferPtrStart, RHICommandBufferBase& commandBuffer, VulkanBuffer& stageBuffer)
|
|
{
|
|
CHECK(uploadSize() == uint32_t(
|
|
cacheIndices.size() + cacheTangents.size() + cacheNormals.size() + cacheUv0s.size() + cachePositions.size()));
|
|
|
|
uint32_t indicesOffsetInSrcBuffer = 0;
|
|
uint32_t tangentOffsetInSrcBuffer = indicesOffsetInSrcBuffer + uint32_t(cacheIndices.size());
|
|
uint32_t normalOffsetInSrcBuffer = tangentOffsetInSrcBuffer + uint32_t(cacheTangents.size());
|
|
uint32_t uv0OffsetInSrcBuffer = normalOffsetInSrcBuffer + uint32_t(cacheNormals.size());
|
|
uint32_t positionsOffsetInSrcBuffer = uv0OffsetInSrcBuffer + uint32_t(cacheUv0s.size());
|
|
|
|
memcpy((void*)((char*)bufferPtrStart + indicesOffsetInSrcBuffer), cacheIndices.data(), cacheIndices.size());
|
|
memcpy((void*)((char*)bufferPtrStart + tangentOffsetInSrcBuffer), cacheTangents.data(), cacheTangents.size());
|
|
memcpy((void*)((char*)bufferPtrStart + normalOffsetInSrcBuffer), cacheNormals.data(), cacheNormals.size());
|
|
memcpy((void*)((char*)bufferPtrStart + uv0OffsetInSrcBuffer), cacheUv0s.data(), cacheUv0s.size());
|
|
memcpy((void*)((char*)bufferPtrStart + positionsOffsetInSrcBuffer), cachePositions.data(), cachePositions.size());
|
|
|
|
{
|
|
VkBufferCopy regionIndex{};
|
|
regionIndex.size = VkDeviceSize(cacheIndices.size());
|
|
regionIndex.srcOffset = stageBufferOffset + indicesOffsetInSrcBuffer;
|
|
regionIndex.dstOffset = 0;
|
|
vkCmdCopyBuffer(
|
|
commandBuffer.cmd,
|
|
stageBuffer,
|
|
meshAssetGPU->getIndices()->getVkBuffer(),
|
|
1,
|
|
®ionIndex);
|
|
}
|
|
|
|
{
|
|
VkBufferCopy regionVertex{};
|
|
regionVertex.size = VkDeviceSize(cacheTangents.size());
|
|
regionVertex.srcOffset = stageBufferOffset + tangentOffsetInSrcBuffer;
|
|
regionVertex.dstOffset = 0;
|
|
vkCmdCopyBuffer(
|
|
commandBuffer.cmd,
|
|
stageBuffer,
|
|
meshAssetGPU->getTangents()->getVkBuffer(),
|
|
1,
|
|
®ionVertex);
|
|
}
|
|
{
|
|
VkBufferCopy regionVertex{};
|
|
regionVertex.size = VkDeviceSize(cacheNormals.size());
|
|
regionVertex.srcOffset = stageBufferOffset + normalOffsetInSrcBuffer;
|
|
regionVertex.dstOffset = 0;
|
|
vkCmdCopyBuffer(
|
|
commandBuffer.cmd,
|
|
stageBuffer,
|
|
meshAssetGPU->getNormals()->getVkBuffer(),
|
|
1,
|
|
®ionVertex);
|
|
}
|
|
{
|
|
VkBufferCopy regionVertex{};
|
|
regionVertex.size = VkDeviceSize(cacheUv0s.size());
|
|
regionVertex.srcOffset = stageBufferOffset + uv0OffsetInSrcBuffer;
|
|
regionVertex.dstOffset = 0;
|
|
vkCmdCopyBuffer(
|
|
commandBuffer.cmd,
|
|
stageBuffer,
|
|
meshAssetGPU->getUv0s()->getVkBuffer(),
|
|
1,
|
|
®ionVertex);
|
|
}
|
|
|
|
{
|
|
VkBufferCopy regionVertex{};
|
|
regionVertex.size = VkDeviceSize(cachePositions.size());
|
|
regionVertex.srcOffset = stageBufferOffset + positionsOffsetInSrcBuffer;
|
|
regionVertex.dstOffset = 0;
|
|
vkCmdCopyBuffer(
|
|
commandBuffer.cmd,
|
|
stageBuffer,
|
|
meshAssetGPU->getPosition()->getVkBuffer(),
|
|
1,
|
|
®ionVertex);
|
|
}
|
|
}
|
|
|
|
std::shared_ptr<AssetRawStaticMeshLoadTask> AssetRawStaticMeshLoadTask::buildFromPath(
|
|
VulkanContext* context,
|
|
const std::filesystem::path& path,
|
|
const UUID& uuid,
|
|
StaticMeshRenderBounds& outBounds)
|
|
{
|
|
ASSERT(!context->isEngineAssetExist(uuid), "Build from path is persistent asset, only init once.");
|
|
|
|
Assimp::Importer importer;
|
|
const aiScene* scene = importer.ReadFile(path.string(),
|
|
aiProcessPreset_TargetRealtime_Fast | aiProcess_FlipUVs | aiProcess_GenBoundingBoxes);
|
|
if (!scene || scene->mFlags & AI_SCENE_FLAGS_INCOMPLETE || !scene->mRootNode)
|
|
{
|
|
LOG_ERROR("Assimp import fail: {0}.", importer.GetErrorString());
|
|
return nullptr;
|
|
}
|
|
|
|
AssimpStaticMeshImporter processor(path);
|
|
processor.processNode(scene->mRootNode, scene);
|
|
|
|
auto newTask = std::make_shared<AssetRawStaticMeshLoadTask>();
|
|
|
|
newTask->cacheTangents.resize(processor.getVerticesCount() * sizeof(processor.getTangents()[0]));
|
|
newTask->cacheNormals.resize(processor.getVerticesCount() * sizeof(processor.getNormals()[0]));
|
|
newTask->cacheUv0s.resize(processor.getVerticesCount() * sizeof(processor.getUv0s()[0]));
|
|
newTask->cachePositions.resize(processor.getVerticesCount() * sizeof(processor.getPositions()[0]));
|
|
newTask->cacheIndices.resize(processor.getIndicesCount() * sizeof(processor.getIndices()[0]));
|
|
|
|
{
|
|
memcpy((void*)(newTask->cacheTangents.data()), (void*)processor.getTangents().data(), newTask->cacheTangents.size());
|
|
memcpy((void*)(newTask->cacheNormals.data()), (void*)processor.getNormals().data(), newTask->cacheNormals.size());
|
|
memcpy((void*)(newTask->cacheUv0s.data()), (void*)processor.getUv0s().data(), newTask->cacheUv0s.size());
|
|
memcpy((void*)(newTask->cachePositions.data()), (void*)processor.getPositions().data(), newTask->cachePositions.size());
|
|
memcpy((void*)(newTask->cacheIndices.data()), (void*)processor.getIndices().data(), newTask->cacheIndices.size());
|
|
}
|
|
|
|
|
|
ASSERT(processor.getSubmeshInfo().size() == 1, "Engine mesh only support one material and one submesh!");
|
|
outBounds = processor.getSubmeshInfo()[0].bounds;
|
|
|
|
auto newAsset = std::make_shared<GPUStaticMeshAsset>(
|
|
context,
|
|
uuid,
|
|
nullptr,
|
|
path.string(),
|
|
newTask->cacheTangents.size(),
|
|
sizeof(processor.getTangents()[0]),
|
|
newTask->cacheNormals.size(),
|
|
sizeof(processor.getNormals()[0]),
|
|
newTask->cacheUv0s.size(),
|
|
sizeof(processor.getUv0s()[0]),
|
|
newTask->cachePositions.size(),
|
|
sizeof(processor.getPositions()[0]),
|
|
newTask->cacheIndices.size(),
|
|
sizeof(processor.getIndices()[0])
|
|
);
|
|
|
|
context->insertEngineAsset(uuid, newAsset);
|
|
newTask->meshAssetGPU = newAsset;
|
|
return newTask;
|
|
}
|
|
} |