blob: c6952d4a923cc0a7522472e475ab0660497b7655 [file] [log] [blame]
// Copyright 2019 The Dawn Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "dawn_native/vulkan/UtilsVulkan.h"
#include "common/Assert.h"
#include "dawn_native/EnumMaskIterator.h"
#include "dawn_native/Format.h"
#include "dawn_native/vulkan/Forward.h"
#include "dawn_native/vulkan/TextureVk.h"
namespace dawn_native { namespace vulkan {
VkCompareOp ToVulkanCompareOp(wgpu::CompareFunction op) {
switch (op) {
case wgpu::CompareFunction::Never:
return VK_COMPARE_OP_NEVER;
case wgpu::CompareFunction::Less:
return VK_COMPARE_OP_LESS;
case wgpu::CompareFunction::LessEqual:
return VK_COMPARE_OP_LESS_OR_EQUAL;
case wgpu::CompareFunction::Greater:
return VK_COMPARE_OP_GREATER;
case wgpu::CompareFunction::GreaterEqual:
return VK_COMPARE_OP_GREATER_OR_EQUAL;
case wgpu::CompareFunction::Equal:
return VK_COMPARE_OP_EQUAL;
case wgpu::CompareFunction::NotEqual:
return VK_COMPARE_OP_NOT_EQUAL;
case wgpu::CompareFunction::Always:
return VK_COMPARE_OP_ALWAYS;
case wgpu::CompareFunction::Undefined:
UNREACHABLE();
}
}
// Convert Dawn texture aspects to Vulkan texture aspect flags
VkImageAspectFlags VulkanAspectMask(const Aspect& aspects) {
VkImageAspectFlags flags = 0;
for (Aspect aspect : IterateEnumMask(aspects)) {
switch (aspect) {
case Aspect::Color:
flags |= VK_IMAGE_ASPECT_COLOR_BIT;
break;
case Aspect::Depth:
flags |= VK_IMAGE_ASPECT_DEPTH_BIT;
break;
case Aspect::Stencil:
flags |= VK_IMAGE_ASPECT_STENCIL_BIT;
break;
case Aspect::CombinedDepthStencil:
flags |= VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;
break;
case Aspect::Plane0:
case Aspect::Plane1:
case Aspect::None:
UNREACHABLE();
}
}
return flags;
}
// Vulkan SPEC requires the source/destination region specified by each element of
// pRegions must be a region that is contained within srcImage/dstImage. Here the size of
// the image refers to the virtual size, while Dawn validates texture copy extent with the
// physical size, so we need to re-calculate the texture copy extent to ensure it should fit
// in the virtual size of the subresource.
Extent3D ComputeTextureCopyExtent(const TextureCopy& textureCopy, const Extent3D& copySize) {
Extent3D validTextureCopyExtent = copySize;
const TextureBase* texture = textureCopy.texture.Get();
Extent3D virtualSizeAtLevel = texture->GetMipLevelVirtualSize(textureCopy.mipLevel);
ASSERT(textureCopy.origin.x <= virtualSizeAtLevel.width);
ASSERT(textureCopy.origin.y <= virtualSizeAtLevel.height);
if (copySize.width > virtualSizeAtLevel.width - textureCopy.origin.x) {
ASSERT(texture->GetFormat().isCompressed);
validTextureCopyExtent.width = virtualSizeAtLevel.width - textureCopy.origin.x;
}
if (copySize.height > virtualSizeAtLevel.height - textureCopy.origin.y) {
ASSERT(texture->GetFormat().isCompressed);
validTextureCopyExtent.height = virtualSizeAtLevel.height - textureCopy.origin.y;
}
return validTextureCopyExtent;
}
VkBufferImageCopy ComputeBufferImageCopyRegion(const BufferCopy& bufferCopy,
const TextureCopy& textureCopy,
const Extent3D& copySize) {
TextureDataLayout passDataLayout;
passDataLayout.offset = bufferCopy.offset;
passDataLayout.rowsPerImage = bufferCopy.rowsPerImage;
passDataLayout.bytesPerRow = bufferCopy.bytesPerRow;
return ComputeBufferImageCopyRegion(passDataLayout, textureCopy, copySize);
}
VkBufferImageCopy ComputeBufferImageCopyRegion(const TextureDataLayout& dataLayout,
const TextureCopy& textureCopy,
const Extent3D& copySize) {
const Texture* texture = ToBackend(textureCopy.texture.Get());
VkBufferImageCopy region;
region.bufferOffset = dataLayout.offset;
// In Vulkan the row length is in texels while it is in bytes for Dawn
const TexelBlockInfo& blockInfo =
texture->GetFormat().GetAspectInfo(textureCopy.aspect).block;
ASSERT(dataLayout.bytesPerRow % blockInfo.byteSize == 0);
region.bufferRowLength = dataLayout.bytesPerRow / blockInfo.byteSize * blockInfo.width;
region.bufferImageHeight = dataLayout.rowsPerImage * blockInfo.height;
region.imageSubresource.aspectMask = VulkanAspectMask(textureCopy.aspect);
region.imageSubresource.mipLevel = textureCopy.mipLevel;
switch (textureCopy.texture->GetDimension()) {
case wgpu::TextureDimension::e2D: {
region.imageOffset.x = textureCopy.origin.x;
region.imageOffset.y = textureCopy.origin.y;
region.imageOffset.z = 0;
region.imageSubresource.baseArrayLayer = textureCopy.origin.z;
region.imageSubresource.layerCount = copySize.depthOrArrayLayers;
Extent3D imageExtent = ComputeTextureCopyExtent(textureCopy, copySize);
region.imageExtent.width = imageExtent.width;
region.imageExtent.height = imageExtent.height;
region.imageExtent.depth = 1;
break;
}
case wgpu::TextureDimension::e3D: {
region.imageOffset.x = textureCopy.origin.x;
region.imageOffset.y = textureCopy.origin.y;
region.imageOffset.z = textureCopy.origin.z;
region.imageSubresource.baseArrayLayer = 0;
region.imageSubresource.layerCount = 1;
Extent3D imageExtent = ComputeTextureCopyExtent(textureCopy, copySize);
region.imageExtent.width = imageExtent.width;
region.imageExtent.height = imageExtent.height;
region.imageExtent.depth = imageExtent.depthOrArrayLayers;
break;
}
case wgpu::TextureDimension::e1D:
UNREACHABLE();
}
return region;
}
}} // namespace dawn_native::vulkan