| // |
| // Copyright 2021 The ANGLE Project Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| // |
| // CLMemoryVk.cpp: Implements the class methods for CLMemoryVk. |
| |
| #include "libANGLE/renderer/vulkan/CLMemoryVk.h" |
| #include "libANGLE/renderer/vulkan/CLContextVk.h" |
| #include "libANGLE/renderer/vulkan/vk_cl_utils.h" |
| #include "libANGLE/renderer/vulkan/vk_renderer.h" |
| #include "libANGLE/renderer/vulkan/vk_utils.h" |
| #include "libANGLE/renderer/vulkan/vk_wrapper.h" |
| |
| #include "libANGLE/renderer/CLMemoryImpl.h" |
| #include "libANGLE/renderer/Format.h" |
| #include "libANGLE/renderer/FormatID_autogen.h" |
| |
| #include "libANGLE/CLBuffer.h" |
| #include "libANGLE/CLContext.h" |
| #include "libANGLE/CLImage.h" |
| #include "libANGLE/CLMemory.h" |
| #include "libANGLE/Error.h" |
| #include "libANGLE/cl_utils.h" |
| |
| #include "CL/cl_half.h" |
| |
| namespace rx |
| { |
| namespace |
| { |
| cl_int NormalizeFloatValue(float value, float maximum) |
| { |
| if (value < 0) |
| { |
| return 0; |
| } |
| if (value > 1.f) |
| { |
| return static_cast<cl_int>(maximum); |
| } |
| float valueToRound = (value * maximum); |
| |
| if (fabsf(valueToRound) < 0x1.0p23f) |
| { |
| constexpr float magic[2] = {0x1.0p23f, -0x1.0p23f}; |
| float magicVal = magic[valueToRound < 0.0f]; |
| valueToRound += magicVal; |
| valueToRound -= magicVal; |
| } |
| |
| return static_cast<cl_int>(valueToRound); |
| } |
| |
| angle::FormatID CLImageFormatToAngleFormat(cl_image_format format) |
| { |
| switch (format.image_channel_order) |
| { |
| case CL_R: |
| case CL_LUMINANCE: |
| case CL_INTENSITY: |
| return angle::Format::CLRFormatToID(format.image_channel_data_type); |
| case CL_RG: |
| return angle::Format::CLRGFormatToID(format.image_channel_data_type); |
| case CL_RGB: |
| return angle::Format::CLRGBFormatToID(format.image_channel_data_type); |
| case CL_RGBA: |
| return angle::Format::CLRGBAFormatToID(format.image_channel_data_type); |
| case CL_BGRA: |
| return angle::Format::CLBGRAFormatToID(format.image_channel_data_type); |
| case CL_sRGBA: |
| return angle::Format::CLsRGBAFormatToID(format.image_channel_data_type); |
| case CL_DEPTH: |
| return angle::Format::CLDEPTHFormatToID(format.image_channel_data_type); |
| case CL_DEPTH_STENCIL: |
| return angle::Format::CLDEPTHSTENCILFormatToID(format.image_channel_data_type); |
| default: |
| return angle::FormatID::NONE; |
| } |
| } |
| |
| } // namespace |
| |
| CLMemoryVk::CLMemoryVk(const cl::Memory &memory) |
| : CLMemoryImpl(memory), |
| mContext(&memory.getContext().getImpl<CLContextVk>()), |
| mRenderer(mContext->getRenderer()), |
| mMappedMemory(nullptr), |
| mMapCount(0), |
| mParent(nullptr) |
| {} |
| |
| CLMemoryVk::~CLMemoryVk() |
| { |
| mContext->mAssociatedObjects->mMemories.erase(mMemory.getNative()); |
| } |
| |
| VkBufferUsageFlags CLMemoryVk::getVkUsageFlags() |
| { |
| return cl_vk::GetBufferUsageFlags(mMemory.getFlags()); |
| } |
| |
| VkMemoryPropertyFlags CLMemoryVk::getVkMemPropertyFlags() |
| { |
| return cl_vk::GetMemoryPropertyFlags(mMemory.getFlags()); |
| } |
| |
| angle::Result CLMemoryVk::map(uint8_t *&ptrOut, size_t offset) |
| { |
| if (!isMapped()) |
| { |
| ANGLE_TRY(mapImpl()); |
| } |
| ptrOut = mMappedMemory + offset; |
| return angle::Result::Continue; |
| } |
| |
| angle::Result CLMemoryVk::copyTo(void *dst, size_t srcOffset, size_t size) |
| { |
| uint8_t *src = nullptr; |
| ANGLE_TRY(map(src, srcOffset)); |
| std::memcpy(dst, src, size); |
| unmap(); |
| return angle::Result::Continue; |
| } |
| |
| angle::Result CLMemoryVk::copyTo(CLMemoryVk *dst, size_t srcOffset, size_t dstOffset, size_t size) |
| { |
| uint8_t *dstPtr = nullptr; |
| ANGLE_TRY(dst->map(dstPtr, dstOffset)); |
| ANGLE_TRY(copyTo(dstPtr, srcOffset, size)); |
| dst->unmap(); |
| return angle::Result::Continue; |
| } |
| |
| angle::Result CLMemoryVk::copyFrom(const void *src, size_t srcOffset, size_t size) |
| { |
| uint8_t *dst = nullptr; |
| ANGLE_TRY(map(dst, srcOffset)); |
| std::memcpy(dst, src, size); |
| unmap(); |
| return angle::Result::Continue; |
| } |
| |
| // Create a sub-buffer from the given buffer object |
| angle::Result CLMemoryVk::createSubBuffer(const cl::Buffer &buffer, |
| cl::MemFlags flags, |
| size_t size, |
| CLMemoryImpl::Ptr *subBufferOut) |
| { |
| ASSERT(buffer.isSubBuffer()); |
| |
| CLBufferVk *bufferVk = new CLBufferVk(buffer); |
| if (!bufferVk) |
| { |
| ANGLE_CL_RETURN_ERROR(CL_OUT_OF_HOST_MEMORY); |
| } |
| ANGLE_TRY(bufferVk->create(nullptr)); |
| *subBufferOut = CLMemoryImpl::Ptr(bufferVk); |
| |
| return angle::Result::Continue; |
| } |
| |
| CLBufferVk::CLBufferVk(const cl::Buffer &buffer) : CLMemoryVk(buffer) |
| { |
| if (buffer.isSubBuffer()) |
| { |
| mParent = &buffer.getParent()->getImpl<CLBufferVk>(); |
| } |
| mDefaultBufferCreateInfo = {}; |
| mDefaultBufferCreateInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; |
| mDefaultBufferCreateInfo.size = buffer.getSize(); |
| mDefaultBufferCreateInfo.usage = getVkUsageFlags(); |
| mDefaultBufferCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; |
| } |
| |
| CLBufferVk::~CLBufferVk() |
| { |
| if (isMapped()) |
| { |
| unmap(); |
| } |
| mBuffer.destroy(mRenderer); |
| } |
| |
| vk::BufferHelper &CLBufferVk::getBuffer() |
| { |
| if (isSubBuffer()) |
| { |
| return getParent()->getBuffer(); |
| } |
| return mBuffer; |
| } |
| |
| angle::Result CLBufferVk::create(void *hostPtr) |
| { |
| if (!isSubBuffer()) |
| { |
| VkBufferCreateInfo createInfo = mDefaultBufferCreateInfo; |
| createInfo.size = getSize(); |
| VkMemoryPropertyFlags memFlags = getVkMemPropertyFlags(); |
| if (IsError(mBuffer.init(mContext, createInfo, memFlags))) |
| { |
| ANGLE_CL_RETURN_ERROR(CL_OUT_OF_RESOURCES); |
| } |
| if (mMemory.getFlags().intersects(CL_MEM_USE_HOST_PTR | CL_MEM_COPY_HOST_PTR)) |
| { |
| ASSERT(hostPtr); |
| ANGLE_CL_IMPL_TRY_ERROR(setDataImpl(static_cast<uint8_t *>(hostPtr), getSize(), 0), |
| CL_OUT_OF_RESOURCES); |
| } |
| } |
| return angle::Result::Continue; |
| } |
| |
| angle::Result CLBufferVk::copyToWithPitch(void *hostPtr, |
| size_t srcOffset, |
| size_t size, |
| size_t rowPitch, |
| size_t slicePitch, |
| cl::Coordinate region, |
| const size_t elementSize) |
| { |
| uint8_t *ptrInBase = nullptr; |
| uint8_t *ptrOutBase = nullptr; |
| cl::BufferRect stagingBufferRect{ |
| {static_cast<int>(0), static_cast<int>(0), static_cast<int>(0)}, |
| {region.x, region.y, region.z}, |
| 0, |
| 0, |
| elementSize}; |
| |
| ptrOutBase = static_cast<uint8_t *>(hostPtr); |
| ANGLE_TRY(getBuffer().map(mContext, &ptrInBase)); |
| |
| for (size_t slice = 0; slice < region.z; slice++) |
| { |
| for (size_t row = 0; row < region.y; row++) |
| { |
| size_t stagingBufferOffset = stagingBufferRect.getRowOffset(slice, row); |
| size_t hostPtrOffset = (slice * slicePitch + row * rowPitch); |
| uint8_t *dst = ptrOutBase + hostPtrOffset; |
| uint8_t *src = ptrInBase + stagingBufferOffset; |
| memcpy(dst, src, region.x * elementSize); |
| } |
| } |
| getBuffer().unmap(mContext->getRenderer()); |
| return angle::Result::Continue; |
| } |
| |
| angle::Result CLBufferVk::mapImpl() |
| { |
| ASSERT(!isMapped()); |
| |
| if (isSubBuffer()) |
| { |
| ANGLE_TRY(mParent->map(mMappedMemory, getOffset())); |
| return angle::Result::Continue; |
| } |
| ANGLE_TRY(mBuffer.map(mContext, &mMappedMemory)); |
| return angle::Result::Continue; |
| } |
| |
| void CLBufferVk::unmapImpl() |
| { |
| if (!isSubBuffer()) |
| { |
| mBuffer.unmap(mRenderer); |
| } |
| mMappedMemory = nullptr; |
| } |
| |
| angle::Result CLBufferVk::setRect(const void *data, |
| const cl::BufferRect &srcRect, |
| const cl::BufferRect &rect) |
| { |
| ASSERT(srcRect.valid() && rect.valid()); |
| ASSERT(srcRect.mSize == rect.mSize); |
| |
| uint8_t *mapPtr = nullptr; |
| ANGLE_TRY(map(mapPtr)); |
| const uint8_t *srcData = reinterpret_cast<const uint8_t *>(data); |
| for (size_t slice = 0; slice < rect.mSize.depth; slice++) |
| { |
| for (size_t row = 0; row < rect.mSize.height; row++) |
| { |
| const uint8_t *src = srcData + srcRect.getRowOffset(slice, row); |
| uint8_t *dst = mapPtr + rect.getRowOffset(slice, row); |
| |
| memcpy(dst, src, srcRect.mSize.width * srcRect.mElementSize); |
| } |
| } |
| |
| return angle::Result::Continue; |
| } |
| |
| angle::Result CLBufferVk::getRect(const cl::BufferRect &srcRect, |
| const cl::BufferRect &outRect, |
| void *outData) |
| { |
| ASSERT(srcRect.valid() && outRect.valid()); |
| ASSERT(srcRect.mSize == outRect.mSize); |
| |
| uint8_t *mapPtr = nullptr; |
| ANGLE_TRY(map(mapPtr)); |
| uint8_t *dstData = reinterpret_cast<uint8_t *>(outData); |
| for (size_t slice = 0; slice < srcRect.mSize.depth; slice++) |
| { |
| for (size_t row = 0; row < srcRect.mSize.height; row++) |
| { |
| const uint8_t *src = mapPtr + srcRect.getRowOffset(slice, row); |
| uint8_t *dst = dstData + outRect.getRowOffset(slice, row); |
| |
| memcpy(dst, src, srcRect.mSize.width * srcRect.mElementSize); |
| } |
| } |
| |
| return angle::Result::Continue; |
| } |
| |
| std::vector<VkBufferCopy> CLBufferVk::rectCopyRegions(const cl::BufferRect &bufferRect) |
| { |
| std::vector<VkBufferCopy> copyRegions; |
| for (unsigned int slice = 0; slice < bufferRect.mSize.depth; slice++) |
| { |
| for (unsigned int row = 0; row < bufferRect.mSize.height; row++) |
| { |
| VkBufferCopy copyRegion = {}; |
| copyRegion.size = bufferRect.mSize.width * bufferRect.mElementSize; |
| copyRegion.srcOffset = copyRegion.dstOffset = bufferRect.getRowOffset(slice, row); |
| copyRegions.push_back(copyRegion); |
| } |
| } |
| return copyRegions; |
| } |
| |
| // offset is for mapped pointer |
| angle::Result CLBufferVk::setDataImpl(const uint8_t *data, size_t size, size_t offset) |
| { |
| // buffer cannot be in use state |
| ASSERT(mBuffer.valid()); |
| ASSERT(!isCurrentlyInUse()); |
| ASSERT(size + offset <= getSize()); |
| ASSERT(data != nullptr); |
| |
| // Assuming host visible buffers for now |
| // TODO: http://anglebug.com/42267019 |
| if (!mBuffer.isHostVisible()) |
| { |
| UNIMPLEMENTED(); |
| ANGLE_CL_RETURN_ERROR(CL_OUT_OF_RESOURCES); |
| } |
| |
| uint8_t *mapPointer = nullptr; |
| ANGLE_TRY(mBuffer.mapWithOffset(mContext, &mapPointer, offset)); |
| ASSERT(mapPointer != nullptr); |
| |
| std::memcpy(mapPointer, data, size); |
| mBuffer.unmap(mRenderer); |
| |
| return angle::Result::Continue; |
| } |
| |
| bool CLBufferVk::isCurrentlyInUse() const |
| { |
| return !mRenderer->hasResourceUseFinished(mBuffer.getResourceUse()); |
| } |
| |
| VkImageUsageFlags CLImageVk::getVkImageUsageFlags() |
| { |
| VkImageUsageFlags usageFlags = |
| VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT; |
| |
| if (mMemory.getFlags().intersects(CL_MEM_WRITE_ONLY)) |
| { |
| usageFlags |= VK_IMAGE_USAGE_STORAGE_BIT; |
| } |
| else if (mMemory.getFlags().intersects(CL_MEM_READ_ONLY)) |
| { |
| usageFlags |= VK_IMAGE_USAGE_SAMPLED_BIT; |
| } |
| else |
| { |
| usageFlags |= VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_STORAGE_BIT; |
| } |
| |
| return usageFlags; |
| } |
| |
| VkImageType CLImageVk::getVkImageType(const cl::ImageDescriptor &desc) |
| { |
| VkImageType imageType = VK_IMAGE_TYPE_MAX_ENUM; |
| |
| switch (desc.type) |
| { |
| case cl::MemObjectType::Image1D_Buffer: |
| case cl::MemObjectType::Image1D: |
| case cl::MemObjectType::Image1D_Array: |
| return VK_IMAGE_TYPE_1D; |
| case cl::MemObjectType::Image2D: |
| case cl::MemObjectType::Image2D_Array: |
| return VK_IMAGE_TYPE_2D; |
| case cl::MemObjectType::Image3D: |
| return VK_IMAGE_TYPE_3D; |
| default: |
| UNREACHABLE(); |
| } |
| |
| return imageType; |
| } |
| |
| angle::Result CLImageVk::createStagingBuffer(size_t size) |
| { |
| const VkBufferCreateInfo createInfo = {VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, |
| nullptr, |
| 0, |
| size, |
| getVkUsageFlags(), |
| VK_SHARING_MODE_EXCLUSIVE, |
| 0, |
| nullptr}; |
| if (IsError(mStagingBuffer.init(mContext, createInfo, getVkMemPropertyFlags()))) |
| { |
| ANGLE_CL_RETURN_ERROR(CL_OUT_OF_RESOURCES); |
| } |
| |
| mStagingBufferInitialized = true; |
| return angle::Result::Continue; |
| } |
| |
| angle::Result CLImageVk::copyStagingFrom(void *ptr, size_t offset, size_t size) |
| { |
| uint8_t *ptrOut; |
| uint8_t *ptrIn = static_cast<uint8_t *>(ptr); |
| ANGLE_TRY(getStagingBuffer().map(mContext, &ptrOut)); |
| std::memcpy(ptrOut, ptrIn + offset, size); |
| ANGLE_TRY(getStagingBuffer().flush(mRenderer)); |
| getStagingBuffer().unmap(mContext->getRenderer()); |
| return angle::Result::Continue; |
| } |
| |
| angle::Result CLImageVk::copyStagingTo(void *ptr, size_t offset, size_t size) |
| { |
| uint8_t *ptrOut; |
| ANGLE_TRY(getStagingBuffer().map(mContext, &ptrOut)); |
| ANGLE_TRY(getStagingBuffer().invalidate(mRenderer)); |
| std::memcpy(ptr, ptrOut + offset, size); |
| getStagingBuffer().unmap(mContext->getRenderer()); |
| return angle::Result::Continue; |
| } |
| |
| angle::Result CLImageVk::copyStagingToFromWithPitch(void *hostPtr, |
| const cl::Coordinate ®ion, |
| const size_t rowPitch, |
| const size_t slicePitch, |
| StagingBufferCopyDirection copyStagingTo) |
| { |
| uint8_t *ptrInBase = nullptr; |
| uint8_t *ptrOutBase = nullptr; |
| cl::BufferRect stagingBufferRect{{}, {region.x, region.y, region.z}, 0, 0, getElementSize()}; |
| |
| if (copyStagingTo == StagingBufferCopyDirection::ToHost) |
| { |
| ptrOutBase = static_cast<uint8_t *>(hostPtr); |
| ANGLE_TRY(getStagingBuffer().map(mContext, &ptrInBase)); |
| } |
| else |
| { |
| ptrInBase = static_cast<uint8_t *>(hostPtr); |
| ANGLE_TRY(getStagingBuffer().map(mContext, &ptrOutBase)); |
| } |
| for (size_t slice = 0; slice < region.z; slice++) |
| { |
| for (size_t row = 0; row < region.y; row++) |
| { |
| size_t stagingBufferOffset = stagingBufferRect.getRowOffset(slice, row); |
| size_t hostPtrOffset = (slice * slicePitch + row * rowPitch); |
| uint8_t *dst = (copyStagingTo == StagingBufferCopyDirection::ToHost) |
| ? ptrOutBase + hostPtrOffset |
| : ptrOutBase + stagingBufferOffset; |
| uint8_t *src = (copyStagingTo == StagingBufferCopyDirection::ToHost) |
| ? ptrInBase + stagingBufferOffset |
| : ptrInBase + hostPtrOffset; |
| memcpy(dst, src, region.x * getElementSize()); |
| } |
| } |
| getStagingBuffer().unmap(mContext->getRenderer()); |
| return angle::Result::Continue; |
| } |
| |
| CLImageVk::CLImageVk(const cl::Image &image) |
| : CLMemoryVk(image), |
| mExtent(cl::GetExtentFromDescriptor(image.getDescriptor())), |
| mAngleFormat(CLImageFormatToAngleFormat(image.getFormat())), |
| mStagingBufferInitialized(false), |
| mImageViewType(cl_vk::GetImageViewType(image.getDescriptor().type)) |
| { |
| if (image.getParent()) |
| { |
| mParent = &image.getParent()->getImpl<CLMemoryVk>(); |
| } |
| } |
| |
| CLImageVk::~CLImageVk() |
| { |
| if (isMapped()) |
| { |
| unmap(); |
| } |
| |
| if (mBufferViews.isInitialized()) |
| { |
| mBufferViews.release(mContext->getRenderer()); |
| } |
| |
| mImage.destroy(mRenderer); |
| mImageView.destroy(mContext->getDevice()); |
| if (isStagingBufferInitialized()) |
| { |
| mStagingBuffer.destroy(mRenderer); |
| } |
| } |
| |
| angle::Result CLImageVk::createFromBuffer() |
| { |
| ASSERT(mParent); |
| ASSERT(IsBufferType(getParentType())); |
| |
| // initialize the buffer views |
| mBufferViews.init(mContext->getRenderer(), 0, getSize()); |
| |
| return angle::Result::Continue; |
| } |
| |
| angle::Result CLImageVk::create(void *hostPtr) |
| { |
| if (mParent) |
| { |
| if (getType() == cl::MemObjectType::Image1D_Buffer) |
| { |
| return createFromBuffer(); |
| } |
| else |
| { |
| UNIMPLEMENTED(); |
| ANGLE_CL_RETURN_ERROR(CL_OUT_OF_RESOURCES); |
| } |
| } |
| |
| ANGLE_CL_IMPL_TRY_ERROR( |
| mImage.initStaging(mContext, false, mRenderer->getMemoryProperties(), |
| getVkImageType(getDescriptor()), cl_vk::GetExtent(mExtent), mAngleFormat, |
| mAngleFormat, VK_SAMPLE_COUNT_1_BIT, getVkImageUsageFlags(), 1, |
| (uint32_t)getArraySize()), |
| CL_OUT_OF_RESOURCES); |
| |
| if (mMemory.getFlags().intersects(CL_MEM_USE_HOST_PTR | CL_MEM_COPY_HOST_PTR)) |
| { |
| ASSERT(hostPtr); |
| ANGLE_CL_IMPL_TRY_ERROR(createStagingBuffer(getSize()), CL_OUT_OF_RESOURCES); |
| if (getDescriptor().rowPitch == 0 && getDescriptor().slicePitch == 0) |
| { |
| ANGLE_CL_IMPL_TRY_ERROR(copyStagingFrom(hostPtr, 0, getSize()), CL_OUT_OF_RESOURCES); |
| } |
| else |
| { |
| ANGLE_TRY(copyStagingToFromWithPitch( |
| hostPtr, {mExtent.width, mExtent.height, mExtent.depth}, getDescriptor().rowPitch, |
| getDescriptor().slicePitch, StagingBufferCopyDirection::ToStagingBuffer)); |
| } |
| VkBufferImageCopy copyRegion{}; |
| copyRegion.bufferOffset = 0; |
| copyRegion.bufferRowLength = 0; |
| copyRegion.bufferImageHeight = 0; |
| copyRegion.imageExtent = |
| cl_vk::GetExtent(getExtentForCopy({mExtent.width, mExtent.height, mExtent.depth})); |
| copyRegion.imageOffset = cl_vk::GetOffset(getOffsetForCopy(cl::kMemOffsetsZero)); |
| copyRegion.imageSubresource = getSubresourceLayersForCopy( |
| cl::kMemOffsetsZero, {mExtent.width, mExtent.height, mExtent.depth}, getType(), |
| ImageCopyWith::Buffer); |
| |
| ANGLE_CL_IMPL_TRY_ERROR(mImage.copyToBufferOneOff(mContext, &mStagingBuffer, copyRegion), |
| CL_OUT_OF_RESOURCES); |
| } |
| |
| ANGLE_TRY(initImageViewImpl()); |
| return angle::Result::Continue; |
| } |
| |
| angle::Result CLImageVk::initImageViewImpl() |
| { |
| VkImageViewCreateInfo viewInfo = {}; |
| viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; |
| viewInfo.flags = 0; |
| viewInfo.image = getImage().getImage().getHandle(); |
| viewInfo.format = getImage().getActualVkFormat(mContext->getRenderer()); |
| viewInfo.viewType = mImageViewType; |
| |
| viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; |
| // We don't support mip map levels and should have been validated |
| ASSERT(getDescriptor().numMipLevels == 0); |
| viewInfo.subresourceRange.baseMipLevel = getDescriptor().numMipLevels; |
| viewInfo.subresourceRange.levelCount = 1; |
| viewInfo.subresourceRange.baseArrayLayer = 0; |
| viewInfo.subresourceRange.layerCount = static_cast<uint32_t>(getArraySize()); |
| |
| // no swizzle support for now |
| viewInfo.components.r = VK_COMPONENT_SWIZZLE_IDENTITY; |
| viewInfo.components.g = VK_COMPONENT_SWIZZLE_IDENTITY; |
| viewInfo.components.b = VK_COMPONENT_SWIZZLE_IDENTITY; |
| viewInfo.components.a = VK_COMPONENT_SWIZZLE_IDENTITY; |
| |
| VkImageViewUsageCreateInfo imageViewUsageCreateInfo = {}; |
| imageViewUsageCreateInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_USAGE_CREATE_INFO; |
| imageViewUsageCreateInfo.usage = getVkImageUsageFlags(); |
| |
| viewInfo.pNext = &imageViewUsageCreateInfo; |
| |
| ANGLE_VK_TRY(mContext, mImageView.init(mContext->getDevice(), viewInfo)); |
| return angle::Result::Continue; |
| } |
| |
| bool CLImageVk::isCurrentlyInUse() const |
| { |
| return !mRenderer->hasResourceUseFinished(mImage.getResourceUse()); |
| } |
| |
| bool CLImageVk::containsHostMemExtension() |
| { |
| const vk::ExtensionNameList &enabledDeviceExtensions = mRenderer->getEnabledDeviceExtensions(); |
| return std::find(enabledDeviceExtensions.begin(), enabledDeviceExtensions.end(), |
| "VK_EXT_external_memory_host") != enabledDeviceExtensions.end(); |
| } |
| |
| void CLImageVk::packPixels(const void *fillColor, PixelColor *packedColor) |
| { |
| size_t channelCount = cl::GetChannelCount(getFormat().image_channel_order); |
| |
| switch (getFormat().image_channel_data_type) |
| { |
| case CL_UNORM_INT8: |
| { |
| float *srcVector = static_cast<float *>(const_cast<void *>(fillColor)); |
| if (getFormat().image_channel_order == CL_BGRA) |
| { |
| packedColor->u8[0] = |
| static_cast<unsigned char>(NormalizeFloatValue(srcVector[2], 255.f)); |
| packedColor->u8[1] = |
| static_cast<unsigned char>(NormalizeFloatValue(srcVector[1], 255.f)); |
| packedColor->u8[2] = |
| static_cast<unsigned char>(NormalizeFloatValue(srcVector[0], 255.f)); |
| packedColor->u8[3] = |
| static_cast<unsigned char>(NormalizeFloatValue(srcVector[3], 255.f)); |
| } |
| else |
| { |
| for (unsigned int i = 0; i < channelCount; i++) |
| packedColor->u8[i] = |
| static_cast<unsigned char>(NormalizeFloatValue(srcVector[i], 255.f)); |
| } |
| break; |
| } |
| case CL_SIGNED_INT8: |
| { |
| int *srcVector = static_cast<int *>(const_cast<void *>(fillColor)); |
| for (unsigned int i = 0; i < channelCount; i++) |
| packedColor->s8[i] = static_cast<char>(std::clamp(srcVector[i], -128, 127)); |
| break; |
| } |
| case CL_UNSIGNED_INT8: |
| { |
| unsigned int *srcVector = static_cast<unsigned int *>(const_cast<void *>(fillColor)); |
| for (unsigned int i = 0; i < channelCount; i++) |
| packedColor->u8[i] = static_cast<unsigned char>( |
| std::clamp(static_cast<unsigned int>(srcVector[i]), |
| static_cast<unsigned int>(0), static_cast<unsigned int>(255))); |
| break; |
| } |
| case CL_UNORM_INT16: |
| { |
| float *srcVector = static_cast<float *>(const_cast<void *>(fillColor)); |
| for (unsigned int i = 0; i < channelCount; i++) |
| packedColor->u16[i] = |
| static_cast<unsigned short>(NormalizeFloatValue(srcVector[i], 65535.f)); |
| break; |
| } |
| case CL_SIGNED_INT16: |
| { |
| int *srcVector = static_cast<int *>(const_cast<void *>(fillColor)); |
| for (unsigned int i = 0; i < channelCount; i++) |
| packedColor->s16[i] = static_cast<short>(std::clamp(srcVector[i], -32768, 32767)); |
| break; |
| } |
| case CL_UNSIGNED_INT16: |
| { |
| unsigned int *srcVector = static_cast<unsigned int *>(const_cast<void *>(fillColor)); |
| for (unsigned int i = 0; i < channelCount; i++) |
| packedColor->u16[i] = static_cast<unsigned short>( |
| std::clamp(static_cast<unsigned int>(srcVector[i]), |
| static_cast<unsigned int>(0), static_cast<unsigned int>(65535))); |
| break; |
| } |
| case CL_HALF_FLOAT: |
| { |
| float *srcVector = static_cast<float *>(const_cast<void *>(fillColor)); |
| for (unsigned int i = 0; i < channelCount; i++) |
| packedColor->fp16[i] = cl_half_from_float(srcVector[i], CL_HALF_RTE); |
| break; |
| } |
| case CL_SIGNED_INT32: |
| { |
| int *srcVector = static_cast<int *>(const_cast<void *>(fillColor)); |
| for (unsigned int i = 0; i < channelCount; i++) |
| packedColor->s32[i] = static_cast<int>(srcVector[i]); |
| break; |
| } |
| case CL_UNSIGNED_INT32: |
| { |
| unsigned int *srcVector = static_cast<unsigned int *>(const_cast<void *>(fillColor)); |
| for (unsigned int i = 0; i < channelCount; i++) |
| packedColor->u32[i] = static_cast<unsigned int>(srcVector[i]); |
| break; |
| } |
| case CL_FLOAT: |
| { |
| float *srcVector = static_cast<float *>(const_cast<void *>(fillColor)); |
| for (unsigned int i = 0; i < channelCount; i++) |
| packedColor->fp32[i] = srcVector[i]; |
| break; |
| } |
| default: |
| UNIMPLEMENTED(); |
| break; |
| } |
| } |
| |
| void CLImageVk::fillImageWithColor(const cl::MemOffsets &origin, |
| const cl::Coordinate ®ion, |
| uint8_t *imagePtr, |
| PixelColor *packedColor) |
| { |
| size_t elementSize = getElementSize(); |
| cl::BufferRect stagingBufferRect{ |
| {}, {mExtent.width, mExtent.height, mExtent.depth}, 0, 0, elementSize}; |
| uint8_t *ptrBase = imagePtr + (origin.z * stagingBufferRect.getSlicePitch()) + |
| (origin.y * stagingBufferRect.getRowPitch()) + (origin.x * elementSize); |
| for (size_t slice = 0; slice < region.z; slice++) |
| { |
| for (size_t row = 0; row < region.y; row++) |
| { |
| size_t stagingBufferOffset = stagingBufferRect.getRowOffset(slice, row); |
| uint8_t *pixelPtr = ptrBase + stagingBufferOffset; |
| for (size_t x = 0; x < region.x; x++) |
| { |
| memcpy(pixelPtr, packedColor, elementSize); |
| pixelPtr += elementSize; |
| } |
| } |
| } |
| } |
| |
| cl::Extents CLImageVk::getExtentForCopy(const cl::Coordinate ®ion) |
| { |
| cl::Extents extent = {}; |
| extent.width = region.x; |
| extent.height = region.y; |
| extent.depth = region.z; |
| switch (getDescriptor().type) |
| { |
| case cl::MemObjectType::Image1D_Array: |
| |
| extent.height = 1; |
| extent.depth = 1; |
| break; |
| case cl::MemObjectType::Image2D_Array: |
| extent.depth = 1; |
| break; |
| default: |
| break; |
| } |
| return extent; |
| } |
| |
| cl::Offset CLImageVk::getOffsetForCopy(const cl::MemOffsets &origin) |
| { |
| cl::Offset offset = {}; |
| offset.x = origin.x; |
| offset.y = origin.y; |
| offset.z = origin.z; |
| switch (getDescriptor().type) |
| { |
| case cl::MemObjectType::Image1D_Array: |
| offset.y = 0; |
| offset.z = 0; |
| break; |
| case cl::MemObjectType::Image2D_Array: |
| offset.z = 0; |
| break; |
| default: |
| break; |
| } |
| return offset; |
| } |
| |
| VkImageSubresourceLayers CLImageVk::getSubresourceLayersForCopy(const cl::MemOffsets &origin, |
| const cl::Coordinate ®ion, |
| cl::MemObjectType copyToType, |
| ImageCopyWith imageCopy) |
| { |
| VkImageSubresourceLayers subresource = {}; |
| subresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; |
| subresource.mipLevel = 0; |
| switch (getDescriptor().type) |
| { |
| case cl::MemObjectType::Image1D_Array: |
| subresource.baseArrayLayer = static_cast<uint32_t>(origin.y); |
| if (imageCopy == ImageCopyWith::Image) |
| { |
| subresource.layerCount = static_cast<uint32_t>(region.y); |
| } |
| else |
| { |
| subresource.layerCount = static_cast<uint32_t>(getArraySize()); |
| } |
| break; |
| case cl::MemObjectType::Image2D_Array: |
| subresource.baseArrayLayer = static_cast<uint32_t>(origin.z); |
| if (copyToType == cl::MemObjectType::Image2D || |
| copyToType == cl::MemObjectType::Image3D) |
| { |
| subresource.layerCount = 1; |
| } |
| else if (imageCopy == ImageCopyWith::Image) |
| { |
| subresource.layerCount = static_cast<uint32_t>(region.z); |
| } |
| else |
| { |
| subresource.layerCount = static_cast<uint32_t>(getArraySize()); |
| } |
| break; |
| default: |
| subresource.baseArrayLayer = 0; |
| subresource.layerCount = 1; |
| break; |
| } |
| return subresource; |
| } |
| |
| angle::Result CLImageVk::mapImpl() |
| { |
| ASSERT(!isMapped()); |
| |
| if (mParent) |
| { |
| ANGLE_TRY(mParent->map(mMappedMemory, getOffset())); |
| return angle::Result::Continue; |
| } |
| |
| ASSERT(isStagingBufferInitialized()); |
| ANGLE_TRY(getStagingBuffer().map(mContext, &mMappedMemory)); |
| |
| return angle::Result::Continue; |
| } |
| void CLImageVk::unmapImpl() |
| { |
| if (!mParent) |
| { |
| getStagingBuffer().unmap(mContext->getRenderer()); |
| } |
| mMappedMemory = nullptr; |
| } |
| |
| size_t CLImageVk::getRowPitch() const |
| { |
| return getFrontendObject().getRowSize(); |
| } |
| |
| size_t CLImageVk::getSlicePitch() const |
| { |
| return getFrontendObject().getSliceSize(); |
| } |
| |
| template <> |
| CLBufferVk *CLImageVk::getParent<CLBufferVk>() const |
| { |
| if (mParent) |
| { |
| ASSERT(cl::IsBufferType(getParentType())); |
| return static_cast<CLBufferVk *>(mParent); |
| } |
| return nullptr; |
| } |
| |
| template <> |
| CLImageVk *CLImageVk::getParent<CLImageVk>() const |
| { |
| if (mParent) |
| { |
| ASSERT(cl::IsImageType(getParentType())); |
| return static_cast<CLImageVk *>(mParent); |
| } |
| return nullptr; |
| } |
| |
| cl::MemObjectType CLImageVk::getParentType() const |
| { |
| if (mParent) |
| { |
| return mParent->getType(); |
| } |
| return cl::MemObjectType::InvalidEnum; |
| } |
| |
| angle::Result CLImageVk::getBufferView(const vk::BufferView **viewOut) |
| { |
| if (!mBufferViews.isInitialized()) |
| { |
| ANGLE_CL_RETURN_ERROR(CL_OUT_OF_RESOURCES); |
| } |
| |
| CLBufferVk *parent = getParent<CLBufferVk>(); |
| |
| return mBufferViews.getView( |
| mContext, parent->getBuffer(), parent->getOffset(), |
| mContext->getRenderer()->getFormat(CLImageFormatToAngleFormat(getFormat())), viewOut); |
| } |
| |
| } // namespace rx |