Vulkan now supports offsets when uploading texture data.
This allows `MorphStressTest` to work on Vulkan. However, `Horse` is still broken because it provides positions but not tangents. Separate fix for that is coming. Partial fix for #5109.
This commit is contained in:
committed by
Mathias Agopian
parent
c0ba260ddf
commit
72feb044a3
@@ -340,7 +340,7 @@ void VulkanContext::createEmptyTexture(VulkanStagePool& stagePool) {
|
||||
TextureUsage::SUBPASS_INPUT, stagePool);
|
||||
uint32_t black = 0;
|
||||
PixelBufferDescriptor pbd(&black, 4, PixelDataFormat::RGBA, PixelDataType::UBYTE);
|
||||
emptyTexture->update2DImage(pbd, 1, 1, 0);
|
||||
emptyTexture->updateImage(pbd, 1, 1, 1, 0, 0, 0, 0);
|
||||
}
|
||||
|
||||
} // namespace filament
|
||||
|
||||
@@ -865,8 +865,8 @@ void VulkanDriver::updateBufferObject(Handle<HwBufferObject> boh, BufferDescript
|
||||
void VulkanDriver::update2DImage(Handle<HwTexture> th,
|
||||
uint32_t level, uint32_t xoffset, uint32_t yoffset, uint32_t width, uint32_t height,
|
||||
PixelBufferDescriptor&& data) {
|
||||
assert_invariant(xoffset == 0 && yoffset == 0 && "Offsets not yet supported.");
|
||||
handle_cast<VulkanTexture*>(th)->update2DImage(data, width, height, level);
|
||||
handle_cast<VulkanTexture*>(th)->updateImage(data, width, height, 1,
|
||||
xoffset, yoffset, 0, level);
|
||||
scheduleDestroy(std::move(data));
|
||||
}
|
||||
|
||||
@@ -879,8 +879,8 @@ void VulkanDriver::update3DImage(
|
||||
uint32_t level, uint32_t xoffset, uint32_t yoffset, uint32_t zoffset,
|
||||
uint32_t width, uint32_t height, uint32_t depth,
|
||||
PixelBufferDescriptor&& data) {
|
||||
assert_invariant(xoffset == 0 && yoffset == 0 && zoffset == 0 && "Offsets not yet supported.");
|
||||
handle_cast<VulkanTexture*>(th)->update3DImage(data, width, height, depth, level);
|
||||
handle_cast<VulkanTexture*>(th)->updateImage(data, width, height, depth,
|
||||
xoffset, yoffset, zoffset, level);
|
||||
scheduleDestroy(std::move(data));
|
||||
}
|
||||
|
||||
|
||||
@@ -195,13 +195,8 @@ VulkanTexture::~VulkanTexture() {
|
||||
}
|
||||
}
|
||||
|
||||
void VulkanTexture::update2DImage(const PixelBufferDescriptor& data, uint32_t width,
|
||||
uint32_t height, int miplevel) {
|
||||
update3DImage(std::move(data), width, height, 1, miplevel);
|
||||
}
|
||||
|
||||
void VulkanTexture::update3DImage(const PixelBufferDescriptor& data, uint32_t width, uint32_t height,
|
||||
uint32_t depth, int miplevel) {
|
||||
void VulkanTexture::updateImage(const PixelBufferDescriptor& data, uint32_t width, uint32_t height,
|
||||
uint32_t depth, uint32_t xoffset, uint32_t yoffset, uint32_t zoffset, uint32_t miplevel) {
|
||||
assert_invariant(width <= this->width && height <= this->height && depth <= this->depth);
|
||||
const PixelBufferDescriptor* hostData = &data;
|
||||
PixelBufferDescriptor reshapedData;
|
||||
@@ -213,41 +208,67 @@ void VulkanTexture::update3DImage(const PixelBufferDescriptor& data, uint32_t wi
|
||||
hostData = &reshapedData;
|
||||
}
|
||||
|
||||
// If format conversion is both required and supported, use vkCmdBlitImage. Otherwise, use
|
||||
// vkCmdCopyBufferToImage.
|
||||
|
||||
// If format conversion is both required and supported, use vkCmdBlitImage.
|
||||
const VkFormat hostFormat = backend::getVkFormat(hostData->format, hostData->type);
|
||||
const VkFormat deviceFormat = getVkFormatLinear(mVkFormat);
|
||||
|
||||
if (hostFormat != deviceFormat && hostFormat != VK_FORMAT_UNDEFINED) {
|
||||
updateWithBlitImage(*hostData, width, height, depth, miplevel);
|
||||
} else {
|
||||
updateWithCopyBuffer(*hostData, width, height, depth, miplevel);
|
||||
assert_invariant(xoffset == 0 && yoffset == 0 && zoffset == 0 &&
|
||||
"Offsets not yet supported when format conversion is required.");
|
||||
updateImageWithBlit(*hostData, width, height, depth, miplevel);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void VulkanTexture::updateWithCopyBuffer(const PixelBufferDescriptor& hostData, uint32_t width,
|
||||
uint32_t height, uint32_t depth, uint32_t miplevel) {
|
||||
// Otherwise, use vkCmdCopyBufferToImage.
|
||||
void* mapped = nullptr;
|
||||
VulkanStage const* stage = mStagePool.acquireStage(hostData.size);
|
||||
VulkanStage const* stage = mStagePool.acquireStage(hostData->size);
|
||||
vmaMapMemory(mContext.allocator, stage->memory, &mapped);
|
||||
memcpy(mapped, hostData.buffer, hostData.size);
|
||||
memcpy(mapped, hostData->buffer, hostData->size);
|
||||
vmaUnmapMemory(mContext.allocator, stage->memory);
|
||||
vmaFlushAllocation(mContext.allocator, stage->memory, 0, hostData.size);
|
||||
vmaFlushAllocation(mContext.allocator, stage->memory, 0, hostData->size);
|
||||
|
||||
const VkCommandBuffer cmdbuffer = mContext.commands->get().cmdbuffer;
|
||||
|
||||
const VkImageSubresourceRange range = { mAspect, miplevel, 1, 0, 1 };
|
||||
const VkImageLayout textureLayout = getDefaultImageLayout(usage);
|
||||
transitionLayout(cmdbuffer, range, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
|
||||
VkBufferImageCopy copyRegion = {
|
||||
.bufferOffset = {},
|
||||
.bufferRowLength = {},
|
||||
.bufferImageHeight = {},
|
||||
.imageSubresource = {
|
||||
.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
|
||||
.mipLevel = miplevel,
|
||||
.baseArrayLayer = 0,
|
||||
.layerCount = 1
|
||||
},
|
||||
.imageOffset = { int32_t(xoffset), int32_t(yoffset), int32_t(zoffset) },
|
||||
.imageExtent = { width, height, depth }
|
||||
};
|
||||
|
||||
copyBufferToImage(cmdbuffer, stage->buffer, mTextureImage, width, height, depth,
|
||||
nullptr, miplevel);
|
||||
VkImageSubresourceRange transitionRange = {
|
||||
.aspectMask = mAspect,
|
||||
.baseMipLevel = miplevel,
|
||||
.levelCount = 1,
|
||||
.baseArrayLayer = 0,
|
||||
.layerCount = 1
|
||||
};
|
||||
|
||||
transitionLayout(cmdbuffer, range, textureLayout);
|
||||
// Vulkan specifies subregions for 3D textures differently than from 2D arrays.
|
||||
if (target == SamplerType::SAMPLER_2D_ARRAY) {
|
||||
copyRegion.imageOffset.z = 0;
|
||||
copyRegion.imageExtent.depth = 1;
|
||||
copyRegion.imageSubresource.baseArrayLayer = zoffset;
|
||||
copyRegion.imageSubresource.layerCount = depth;
|
||||
transitionRange.baseArrayLayer = zoffset;
|
||||
transitionRange.layerCount = depth;
|
||||
}
|
||||
|
||||
transitionLayout(cmdbuffer, transitionRange, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
|
||||
|
||||
vkCmdCopyBufferToImage(cmdbuffer, stage->buffer, mTextureImage,
|
||||
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ©Region);
|
||||
|
||||
transitionLayout(cmdbuffer, transitionRange, getDefaultImageLayout(usage));
|
||||
}
|
||||
|
||||
void VulkanTexture::updateWithBlitImage(const PixelBufferDescriptor& hostData, uint32_t width,
|
||||
void VulkanTexture::updateImageWithBlit(const PixelBufferDescriptor& hostData, uint32_t width,
|
||||
uint32_t height, uint32_t depth, uint32_t miplevel) {
|
||||
void* mapped = nullptr;
|
||||
VulkanStageImage const* stage = mStagePool.acquireImage(
|
||||
@@ -310,8 +331,19 @@ void VulkanTexture::updateCubeImage(const PixelBufferDescriptor& data,
|
||||
|
||||
transitionLayout(cmdbuffer, range, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
|
||||
|
||||
copyBufferToImage(cmdbuffer, stage->buffer, mTextureImage, width, height, 1,
|
||||
&faceOffsets, miplevel);
|
||||
VkBufferImageCopy regions[6] = {{}};
|
||||
VkExtent3D extent { width, height, 1 };
|
||||
for (size_t face = 0; face < 6; face++) {
|
||||
auto& region = regions[face];
|
||||
region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
region.imageSubresource.baseArrayLayer = face;
|
||||
region.imageSubresource.layerCount = 1;
|
||||
region.imageSubresource.mipLevel = miplevel;
|
||||
region.imageExtent = extent;
|
||||
region.bufferOffset = faceOffsets.offsets[face];
|
||||
}
|
||||
vkCmdCopyBufferToImage(cmdbuffer, stage->buffer, mTextureImage,
|
||||
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 6, regions);
|
||||
|
||||
transitionLayout(cmdbuffer, range, textureLayout);
|
||||
}
|
||||
@@ -373,37 +405,6 @@ VkImageView VulkanTexture::getImageView(VkImageSubresourceRange range) {
|
||||
return imageView;
|
||||
}
|
||||
|
||||
void VulkanTexture::copyBufferToImage(VkCommandBuffer cmd, VkBuffer buffer, VkImage image,
|
||||
uint32_t width, uint32_t height, uint32_t depth, FaceOffsets const* faceOffsets, uint32_t miplevel) {
|
||||
VkExtent3D extent { width, height, depth };
|
||||
if (target == SamplerType::SAMPLER_CUBEMAP) {
|
||||
assert_invariant(faceOffsets);
|
||||
VkBufferImageCopy regions[6] = {{}};
|
||||
for (size_t face = 0; face < 6; face++) {
|
||||
auto& region = regions[face];
|
||||
region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
region.imageSubresource.baseArrayLayer = face;
|
||||
region.imageSubresource.layerCount = 1;
|
||||
region.imageSubresource.mipLevel = miplevel;
|
||||
region.imageExtent = extent;
|
||||
region.bufferOffset = faceOffsets->offsets[face];
|
||||
}
|
||||
vkCmdCopyBufferToImage(cmd, buffer, image,
|
||||
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 6, regions);
|
||||
return;
|
||||
}
|
||||
VkBufferImageCopy region = {};
|
||||
region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
region.imageSubresource.mipLevel = miplevel;
|
||||
region.imageSubresource.layerCount = 1;
|
||||
region.imageExtent = extent;
|
||||
if (target == SamplerType::SAMPLER_2D_ARRAY) {
|
||||
region.imageExtent.depth = 1;
|
||||
region.imageSubresource.layerCount = depth;
|
||||
}
|
||||
vkCmdCopyBufferToImage(cmd, buffer, image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ®ion);
|
||||
}
|
||||
|
||||
void VulkanTexture::transitionLayout(VkCommandBuffer commands, const VkImageSubresourceRange& range,
|
||||
VkImageLayout newLayout) {
|
||||
// In debug builds, ensure that all subresources in the given range have the same layout.
|
||||
|
||||
@@ -31,10 +31,12 @@ struct VulkanTexture : public HwTexture {
|
||||
TextureFormat format, uint8_t samples, uint32_t w, uint32_t h, uint32_t depth,
|
||||
TextureUsage usage, VulkanStagePool& stagePool, VkComponentMapping swizzle = {});
|
||||
~VulkanTexture();
|
||||
void update2DImage(const PixelBufferDescriptor& data, uint32_t width, uint32_t height,
|
||||
int miplevel);
|
||||
void update3DImage(const PixelBufferDescriptor& data, uint32_t width, uint32_t height,
|
||||
uint32_t depth, int miplevel);
|
||||
|
||||
// Uploads data into a subregion of a 2D or 3D texture.
|
||||
void updateImage(const PixelBufferDescriptor& data, uint32_t width, uint32_t height,
|
||||
uint32_t depth, uint32_t xoffset, uint32_t yoffset, uint32_t zoffset, uint32_t miplevel);
|
||||
|
||||
// Uploads data into all 6 faces of a cubemap for a given miplevel.
|
||||
void updateCubeImage(const PixelBufferDescriptor& data, const FaceOffsets& faceOffsets,
|
||||
uint32_t miplevel);
|
||||
|
||||
@@ -63,16 +65,7 @@ private:
|
||||
// Gets or creates a cached VkImageView for a range of miplevels and array layers.
|
||||
VkImageView getImageView(VkImageSubresourceRange range);
|
||||
|
||||
// Issues a copy from a VkBuffer to a specified miplevel in a VkImage. The given width and
|
||||
// height define a subregion within the miplevel.
|
||||
void copyBufferToImage(VkCommandBuffer cmdbuffer, VkBuffer buffer, VkImage image,
|
||||
uint32_t width, uint32_t height, uint32_t depth,
|
||||
FaceOffsets const* faceOffsets, uint32_t miplevel);
|
||||
|
||||
void updateWithCopyBuffer(const PixelBufferDescriptor& hostData, uint32_t width,
|
||||
uint32_t height, uint32_t depth, uint32_t miplevel);
|
||||
|
||||
void updateWithBlitImage(const PixelBufferDescriptor& hostData, uint32_t width,
|
||||
void updateImageWithBlit(const PixelBufferDescriptor& hostData, uint32_t width,
|
||||
uint32_t height, uint32_t depth, uint32_t miplevel);
|
||||
|
||||
VulkanTexture* mSidecarMSAA = nullptr;
|
||||
|
||||
Reference in New Issue
Block a user