xref: /aosp_15_r20/external/angle/src/libANGLE/renderer/vulkan/CLMemoryVk.cpp (revision 8975f5c5ed3d1c378011245431ada316dfb6f244)
1 //
2 // Copyright 2021 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6 // CLMemoryVk.cpp: Implements the class methods for CLMemoryVk.
7 
8 #include "libANGLE/renderer/vulkan/CLMemoryVk.h"
9 #include "libANGLE/renderer/vulkan/CLContextVk.h"
10 #include "libANGLE/renderer/vulkan/vk_cl_utils.h"
11 #include "libANGLE/renderer/vulkan/vk_renderer.h"
12 #include "libANGLE/renderer/vulkan/vk_utils.h"
13 #include "libANGLE/renderer/vulkan/vk_wrapper.h"
14 
15 #include "libANGLE/renderer/CLMemoryImpl.h"
16 #include "libANGLE/renderer/Format.h"
17 #include "libANGLE/renderer/FormatID_autogen.h"
18 
19 #include "libANGLE/CLBuffer.h"
20 #include "libANGLE/CLContext.h"
21 #include "libANGLE/CLImage.h"
22 #include "libANGLE/CLMemory.h"
23 #include "libANGLE/Error.h"
24 #include "libANGLE/cl_utils.h"
25 
26 #include "CL/cl_half.h"
27 
28 namespace rx
29 {
30 namespace
31 {
NormalizeFloatValue(float value,float maximum)32 cl_int NormalizeFloatValue(float value, float maximum)
33 {
34     if (value < 0)
35     {
36         return 0;
37     }
38     if (value > 1.f)
39     {
40         return static_cast<cl_int>(maximum);
41     }
42     float valueToRound = (value * maximum);
43 
44     if (fabsf(valueToRound) < 0x1.0p23f)
45     {
46         constexpr float magic[2] = {0x1.0p23f, -0x1.0p23f};
47         float magicVal           = magic[valueToRound < 0.0f];
48         valueToRound += magicVal;
49         valueToRound -= magicVal;
50     }
51 
52     return static_cast<cl_int>(valueToRound);
53 }
54 
CLImageFormatToAngleFormat(cl_image_format format)55 angle::FormatID CLImageFormatToAngleFormat(cl_image_format format)
56 {
57     switch (format.image_channel_order)
58     {
59         case CL_R:
60         case CL_LUMINANCE:
61         case CL_INTENSITY:
62             return angle::Format::CLRFormatToID(format.image_channel_data_type);
63         case CL_RG:
64             return angle::Format::CLRGFormatToID(format.image_channel_data_type);
65         case CL_RGB:
66             return angle::Format::CLRGBFormatToID(format.image_channel_data_type);
67         case CL_RGBA:
68             return angle::Format::CLRGBAFormatToID(format.image_channel_data_type);
69         case CL_BGRA:
70             return angle::Format::CLBGRAFormatToID(format.image_channel_data_type);
71         case CL_sRGBA:
72             return angle::Format::CLsRGBAFormatToID(format.image_channel_data_type);
73         case CL_DEPTH:
74             return angle::Format::CLDEPTHFormatToID(format.image_channel_data_type);
75         case CL_DEPTH_STENCIL:
76             return angle::Format::CLDEPTHSTENCILFormatToID(format.image_channel_data_type);
77         default:
78             return angle::FormatID::NONE;
79     }
80 }
81 
82 }  // namespace
83 
CLMemoryVk(const cl::Memory & memory)84 CLMemoryVk::CLMemoryVk(const cl::Memory &memory)
85     : CLMemoryImpl(memory),
86       mContext(&memory.getContext().getImpl<CLContextVk>()),
87       mRenderer(mContext->getRenderer()),
88       mMappedMemory(nullptr),
89       mMapCount(0),
90       mParent(nullptr)
91 {}
92 
~CLMemoryVk()93 CLMemoryVk::~CLMemoryVk()
94 {
95     mContext->mAssociatedObjects->mMemories.erase(mMemory.getNative());
96 }
97 
getVkUsageFlags()98 VkBufferUsageFlags CLMemoryVk::getVkUsageFlags()
99 {
100     return cl_vk::GetBufferUsageFlags(mMemory.getFlags());
101 }
102 
getVkMemPropertyFlags()103 VkMemoryPropertyFlags CLMemoryVk::getVkMemPropertyFlags()
104 {
105     return cl_vk::GetMemoryPropertyFlags(mMemory.getFlags());
106 }
107 
map(uint8_t * & ptrOut,size_t offset)108 angle::Result CLMemoryVk::map(uint8_t *&ptrOut, size_t offset)
109 {
110     if (!isMapped())
111     {
112         ANGLE_TRY(mapImpl());
113     }
114     ptrOut = mMappedMemory + offset;
115     return angle::Result::Continue;
116 }
117 
copyTo(void * dst,size_t srcOffset,size_t size)118 angle::Result CLMemoryVk::copyTo(void *dst, size_t srcOffset, size_t size)
119 {
120     uint8_t *src = nullptr;
121     ANGLE_TRY(map(src, srcOffset));
122     std::memcpy(dst, src, size);
123     unmap();
124     return angle::Result::Continue;
125 }
126 
copyTo(CLMemoryVk * dst,size_t srcOffset,size_t dstOffset,size_t size)127 angle::Result CLMemoryVk::copyTo(CLMemoryVk *dst, size_t srcOffset, size_t dstOffset, size_t size)
128 {
129     uint8_t *dstPtr = nullptr;
130     ANGLE_TRY(dst->map(dstPtr, dstOffset));
131     ANGLE_TRY(copyTo(dstPtr, srcOffset, size));
132     dst->unmap();
133     return angle::Result::Continue;
134 }
135 
copyFrom(const void * src,size_t srcOffset,size_t size)136 angle::Result CLMemoryVk::copyFrom(const void *src, size_t srcOffset, size_t size)
137 {
138     uint8_t *dst = nullptr;
139     ANGLE_TRY(map(dst, srcOffset));
140     std::memcpy(dst, src, size);
141     unmap();
142     return angle::Result::Continue;
143 }
144 
145 // Create a sub-buffer from the given buffer object
createSubBuffer(const cl::Buffer & buffer,cl::MemFlags flags,size_t size,CLMemoryImpl::Ptr * subBufferOut)146 angle::Result CLMemoryVk::createSubBuffer(const cl::Buffer &buffer,
147                                           cl::MemFlags flags,
148                                           size_t size,
149                                           CLMemoryImpl::Ptr *subBufferOut)
150 {
151     ASSERT(buffer.isSubBuffer());
152 
153     CLBufferVk *bufferVk = new CLBufferVk(buffer);
154     if (!bufferVk)
155     {
156         ANGLE_CL_RETURN_ERROR(CL_OUT_OF_HOST_MEMORY);
157     }
158     ANGLE_TRY(bufferVk->create(nullptr));
159     *subBufferOut = CLMemoryImpl::Ptr(bufferVk);
160 
161     return angle::Result::Continue;
162 }
163 
CLBufferVk(const cl::Buffer & buffer)164 CLBufferVk::CLBufferVk(const cl::Buffer &buffer) : CLMemoryVk(buffer)
165 {
166     if (buffer.isSubBuffer())
167     {
168         mParent = &buffer.getParent()->getImpl<CLBufferVk>();
169     }
170     mDefaultBufferCreateInfo             = {};
171     mDefaultBufferCreateInfo.sType       = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
172     mDefaultBufferCreateInfo.size        = buffer.getSize();
173     mDefaultBufferCreateInfo.usage       = getVkUsageFlags();
174     mDefaultBufferCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
175 }
176 
~CLBufferVk()177 CLBufferVk::~CLBufferVk()
178 {
179     if (isMapped())
180     {
181         unmap();
182     }
183     mBuffer.destroy(mRenderer);
184 }
185 
getBuffer()186 vk::BufferHelper &CLBufferVk::getBuffer()
187 {
188     if (isSubBuffer())
189     {
190         return getParent()->getBuffer();
191     }
192     return mBuffer;
193 }
194 
create(void * hostPtr)195 angle::Result CLBufferVk::create(void *hostPtr)
196 {
197     if (!isSubBuffer())
198     {
199         VkBufferCreateInfo createInfo  = mDefaultBufferCreateInfo;
200         createInfo.size                = getSize();
201         VkMemoryPropertyFlags memFlags = getVkMemPropertyFlags();
202         if (IsError(mBuffer.init(mContext, createInfo, memFlags)))
203         {
204             ANGLE_CL_RETURN_ERROR(CL_OUT_OF_RESOURCES);
205         }
206         if (mMemory.getFlags().intersects(CL_MEM_USE_HOST_PTR | CL_MEM_COPY_HOST_PTR))
207         {
208             ASSERT(hostPtr);
209             ANGLE_CL_IMPL_TRY_ERROR(setDataImpl(static_cast<uint8_t *>(hostPtr), getSize(), 0),
210                                     CL_OUT_OF_RESOURCES);
211         }
212     }
213     return angle::Result::Continue;
214 }
215 
mapImpl()216 angle::Result CLBufferVk::mapImpl()
217 {
218     ASSERT(!isMapped());
219 
220     if (isSubBuffer())
221     {
222         ANGLE_TRY(mParent->map(mMappedMemory, getOffset()));
223         return angle::Result::Continue;
224     }
225     ANGLE_TRY(mBuffer.map(mContext, &mMappedMemory));
226     return angle::Result::Continue;
227 }
228 
unmapImpl()229 void CLBufferVk::unmapImpl()
230 {
231     if (!isSubBuffer())
232     {
233         mBuffer.unmap(mRenderer);
234     }
235     mMappedMemory = nullptr;
236 }
237 
setRect(const void * data,const cl::BufferRect & srcRect,const cl::BufferRect & rect)238 angle::Result CLBufferVk::setRect(const void *data,
239                                   const cl::BufferRect &srcRect,
240                                   const cl::BufferRect &rect)
241 {
242     ASSERT(srcRect.valid() && rect.valid());
243     ASSERT(srcRect.mSize == rect.mSize);
244 
245     uint8_t *mapPtr = nullptr;
246     ANGLE_TRY(map(mapPtr));
247     const uint8_t *srcData = reinterpret_cast<const uint8_t *>(data);
248     for (size_t slice = 0; slice < rect.mSize.depth; slice++)
249     {
250         for (size_t row = 0; row < rect.mSize.height; row++)
251         {
252             const uint8_t *src = srcData + srcRect.getRowOffset(slice, row);
253             uint8_t *dst       = mapPtr + rect.getRowOffset(slice, row);
254 
255             memcpy(dst, src, srcRect.mSize.width * srcRect.mElementSize);
256         }
257     }
258 
259     return angle::Result::Continue;
260 }
261 
getRect(const cl::BufferRect & srcRect,const cl::BufferRect & outRect,void * outData)262 angle::Result CLBufferVk::getRect(const cl::BufferRect &srcRect,
263                                   const cl::BufferRect &outRect,
264                                   void *outData)
265 {
266     ASSERT(srcRect.valid() && outRect.valid());
267     ASSERT(srcRect.mSize == outRect.mSize);
268 
269     uint8_t *mapPtr = nullptr;
270     ANGLE_TRY(map(mapPtr));
271     uint8_t *dstData = reinterpret_cast<uint8_t *>(outData);
272     for (size_t slice = 0; slice < srcRect.mSize.depth; slice++)
273     {
274         for (size_t row = 0; row < srcRect.mSize.height; row++)
275         {
276             const uint8_t *src = mapPtr + srcRect.getRowOffset(slice, row);
277             uint8_t *dst       = dstData + outRect.getRowOffset(slice, row);
278 
279             memcpy(dst, src, srcRect.mSize.width * srcRect.mElementSize);
280         }
281     }
282 
283     return angle::Result::Continue;
284 }
285 
286 // offset is for mapped pointer
setDataImpl(const uint8_t * data,size_t size,size_t offset)287 angle::Result CLBufferVk::setDataImpl(const uint8_t *data, size_t size, size_t offset)
288 {
289     // buffer cannot be in use state
290     ASSERT(mBuffer.valid());
291     ASSERT(!isCurrentlyInUse());
292     ASSERT(size + offset <= getSize());
293     ASSERT(data != nullptr);
294 
295     // Assuming host visible buffers for now
296     // TODO: http://anglebug.com/42267019
297     if (!mBuffer.isHostVisible())
298     {
299         UNIMPLEMENTED();
300         ANGLE_CL_RETURN_ERROR(CL_OUT_OF_RESOURCES);
301     }
302 
303     uint8_t *mapPointer = nullptr;
304     ANGLE_TRY(mBuffer.mapWithOffset(mContext, &mapPointer, offset));
305     ASSERT(mapPointer != nullptr);
306 
307     std::memcpy(mapPointer, data, size);
308     mBuffer.unmap(mRenderer);
309 
310     return angle::Result::Continue;
311 }
312 
isCurrentlyInUse() const313 bool CLBufferVk::isCurrentlyInUse() const
314 {
315     return !mRenderer->hasResourceUseFinished(mBuffer.getResourceUse());
316 }
317 
getVkImageUsageFlags()318 VkImageUsageFlags CLImageVk::getVkImageUsageFlags()
319 {
320     VkImageUsageFlags usageFlags =
321         VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
322 
323     if (mMemory.getFlags().intersects(CL_MEM_WRITE_ONLY))
324     {
325         usageFlags |= VK_IMAGE_USAGE_STORAGE_BIT;
326     }
327     else if (mMemory.getFlags().intersects(CL_MEM_READ_ONLY))
328     {
329         usageFlags |= VK_IMAGE_USAGE_SAMPLED_BIT;
330     }
331     else
332     {
333         usageFlags |= VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_STORAGE_BIT;
334     }
335 
336     return usageFlags;
337 }
338 
getVkImageType(const cl::ImageDescriptor & desc)339 VkImageType CLImageVk::getVkImageType(const cl::ImageDescriptor &desc)
340 {
341     VkImageType imageType = VK_IMAGE_TYPE_MAX_ENUM;
342 
343     switch (desc.type)
344     {
345         case cl::MemObjectType::Image1D_Buffer:
346         case cl::MemObjectType::Image1D:
347         case cl::MemObjectType::Image1D_Array:
348             return VK_IMAGE_TYPE_1D;
349         case cl::MemObjectType::Image2D:
350         case cl::MemObjectType::Image2D_Array:
351             return VK_IMAGE_TYPE_2D;
352         case cl::MemObjectType::Image3D:
353             return VK_IMAGE_TYPE_3D;
354         default:
355             UNREACHABLE();
356     }
357 
358     return imageType;
359 }
360 
createStagingBuffer(size_t size)361 angle::Result CLImageVk::createStagingBuffer(size_t size)
362 {
363     const VkBufferCreateInfo createInfo = {VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
364                                            nullptr,
365                                            0,
366                                            size,
367                                            getVkUsageFlags(),
368                                            VK_SHARING_MODE_EXCLUSIVE,
369                                            0,
370                                            nullptr};
371     if (IsError(mStagingBuffer.init(mContext, createInfo, getVkMemPropertyFlags())))
372     {
373         ANGLE_CL_RETURN_ERROR(CL_OUT_OF_RESOURCES);
374     }
375 
376     mStagingBufferInitialized = true;
377     return angle::Result::Continue;
378 }
379 
copyStagingFrom(void * ptr,size_t offset,size_t size)380 angle::Result CLImageVk::copyStagingFrom(void *ptr, size_t offset, size_t size)
381 {
382     uint8_t *ptrOut;
383     uint8_t *ptrIn = static_cast<uint8_t *>(ptr);
384     ANGLE_TRY(getStagingBuffer().map(mContext, &ptrOut));
385     std::memcpy(ptrOut, ptrIn + offset, size);
386     ANGLE_TRY(getStagingBuffer().flush(mRenderer));
387     getStagingBuffer().unmap(mContext->getRenderer());
388     return angle::Result::Continue;
389 }
390 
copyStagingTo(void * ptr,size_t offset,size_t size)391 angle::Result CLImageVk::copyStagingTo(void *ptr, size_t offset, size_t size)
392 {
393     uint8_t *ptrOut;
394     ANGLE_TRY(getStagingBuffer().map(mContext, &ptrOut));
395     ANGLE_TRY(getStagingBuffer().invalidate(mRenderer));
396     std::memcpy(ptr, ptrOut + offset, size);
397     getStagingBuffer().unmap(mContext->getRenderer());
398     return angle::Result::Continue;
399 }
400 
copyStagingToFromWithPitch(void * hostPtr,const cl::Coordinate & region,const size_t rowPitch,const size_t slicePitch,StagingBufferCopyDirection copyStagingTo)401 angle::Result CLImageVk::copyStagingToFromWithPitch(void *hostPtr,
402                                                     const cl::Coordinate &region,
403                                                     const size_t rowPitch,
404                                                     const size_t slicePitch,
405                                                     StagingBufferCopyDirection copyStagingTo)
406 {
407     uint8_t *ptrInBase  = nullptr;
408     uint8_t *ptrOutBase = nullptr;
409     cl::BufferBox stagingBufferBox{{}, {region.x, region.y, region.z}, 0, 0, getElementSize()};
410 
411     if (copyStagingTo == StagingBufferCopyDirection::ToHost)
412     {
413         ptrOutBase = static_cast<uint8_t *>(hostPtr);
414         ANGLE_TRY(getStagingBuffer().map(mContext, &ptrInBase));
415     }
416     else
417     {
418         ptrInBase = static_cast<uint8_t *>(hostPtr);
419         ANGLE_TRY(getStagingBuffer().map(mContext, &ptrOutBase));
420     }
421     for (size_t slice = 0; slice < region.z; slice++)
422     {
423         for (size_t row = 0; row < region.y; row++)
424         {
425             size_t stagingBufferOffset = stagingBufferBox.getRowOffset(slice, row);
426             size_t hostPtrOffset       = (slice * slicePitch + row * rowPitch);
427             uint8_t *dst               = (copyStagingTo == StagingBufferCopyDirection::ToHost)
428                                              ? ptrOutBase + hostPtrOffset
429                                              : ptrOutBase + stagingBufferOffset;
430             uint8_t *src               = (copyStagingTo == StagingBufferCopyDirection::ToHost)
431                                              ? ptrInBase + stagingBufferOffset
432                                              : ptrInBase + hostPtrOffset;
433             memcpy(dst, src, region.x * getElementSize());
434         }
435     }
436     getStagingBuffer().unmap(mContext->getRenderer());
437     return angle::Result::Continue;
438 }
439 
CLImageVk(const cl::Image & image)440 CLImageVk::CLImageVk(const cl::Image &image)
441     : CLMemoryVk(image),
442       mExtent(cl::GetExtentFromDescriptor(image.getDescriptor())),
443       mAngleFormat(CLImageFormatToAngleFormat(image.getFormat())),
444       mStagingBufferInitialized(false),
445       mImageViewType(cl_vk::GetImageViewType(image.getDescriptor().type))
446 {
447     if (image.getParent())
448     {
449         mParent = &image.getParent()->getImpl<CLMemoryVk>();
450     }
451 }
452 
~CLImageVk()453 CLImageVk::~CLImageVk()
454 {
455     if (isMapped())
456     {
457         unmap();
458     }
459 
460     if (mBufferViews.isInitialized())
461     {
462         mBufferViews.release(mContext->getRenderer());
463     }
464 
465     mImage.destroy(mRenderer);
466     mImageView.destroy(mContext->getDevice());
467     if (isStagingBufferInitialized())
468     {
469         mStagingBuffer.destroy(mRenderer);
470     }
471 }
472 
createFromBuffer()473 angle::Result CLImageVk::createFromBuffer()
474 {
475     ASSERT(mParent);
476     ASSERT(IsBufferType(getParentType()));
477 
478     // initialize the buffer views
479     mBufferViews.init(mContext->getRenderer(), 0, getSize());
480 
481     return angle::Result::Continue;
482 }
483 
create(void * hostPtr)484 angle::Result CLImageVk::create(void *hostPtr)
485 {
486     if (mParent)
487     {
488         if (getType() == cl::MemObjectType::Image1D_Buffer)
489         {
490             return createFromBuffer();
491         }
492         else
493         {
494             UNIMPLEMENTED();
495             ANGLE_CL_RETURN_ERROR(CL_OUT_OF_RESOURCES);
496         }
497     }
498 
499     ANGLE_CL_IMPL_TRY_ERROR(
500         mImage.initStaging(mContext, false, mRenderer->getMemoryProperties(),
501                            getVkImageType(getDescriptor()), cl_vk::GetExtent(mExtent), mAngleFormat,
502                            mAngleFormat, VK_SAMPLE_COUNT_1_BIT, getVkImageUsageFlags(), 1,
503                            (uint32_t)getArraySize()),
504         CL_OUT_OF_RESOURCES);
505 
506     if (mMemory.getFlags().intersects(CL_MEM_USE_HOST_PTR | CL_MEM_COPY_HOST_PTR))
507     {
508         ASSERT(hostPtr);
509         ANGLE_CL_IMPL_TRY_ERROR(createStagingBuffer(getSize()), CL_OUT_OF_RESOURCES);
510         if (getDescriptor().rowPitch == 0 && getDescriptor().slicePitch == 0)
511         {
512             ANGLE_CL_IMPL_TRY_ERROR(copyStagingFrom(hostPtr, 0, getSize()), CL_OUT_OF_RESOURCES);
513         }
514         else
515         {
516             ANGLE_TRY(copyStagingToFromWithPitch(
517                 hostPtr, {mExtent.width, mExtent.height, mExtent.depth}, getDescriptor().rowPitch,
518                 getDescriptor().slicePitch, StagingBufferCopyDirection::ToStagingBuffer));
519         }
520         VkBufferImageCopy copyRegion{};
521         copyRegion.bufferOffset      = 0;
522         copyRegion.bufferRowLength   = 0;
523         copyRegion.bufferImageHeight = 0;
524         copyRegion.imageExtent =
525             cl_vk::GetExtent(getExtentForCopy({mExtent.width, mExtent.height, mExtent.depth}));
526         copyRegion.imageOffset      = cl_vk::GetOffset(getOffsetForCopy(cl::kMemOffsetsZero));
527         copyRegion.imageSubresource = getSubresourceLayersForCopy(
528             cl::kMemOffsetsZero, {mExtent.width, mExtent.height, mExtent.depth}, getType(),
529             ImageCopyWith::Buffer);
530 
531         ANGLE_CL_IMPL_TRY_ERROR(mImage.copyToBufferOneOff(mContext, &mStagingBuffer, copyRegion),
532                                 CL_OUT_OF_RESOURCES);
533     }
534 
535     ANGLE_TRY(initImageViewImpl());
536     return angle::Result::Continue;
537 }
538 
initImageViewImpl()539 angle::Result CLImageVk::initImageViewImpl()
540 {
541     VkImageViewCreateInfo viewInfo = {};
542     viewInfo.sType                 = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
543     viewInfo.flags                 = 0;
544     viewInfo.image                 = getImage().getImage().getHandle();
545     viewInfo.format                = getImage().getActualVkFormat(mContext->getRenderer());
546     viewInfo.viewType              = mImageViewType;
547 
548     viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
549     // We don't support mip map levels and should have been validated
550     ASSERT(getDescriptor().numMipLevels == 0);
551     viewInfo.subresourceRange.baseMipLevel   = getDescriptor().numMipLevels;
552     viewInfo.subresourceRange.levelCount     = 1;
553     viewInfo.subresourceRange.baseArrayLayer = 0;
554     viewInfo.subresourceRange.layerCount     = static_cast<uint32_t>(getArraySize());
555 
556     // no swizzle support for now
557     viewInfo.components.r = VK_COMPONENT_SWIZZLE_IDENTITY;
558     viewInfo.components.g = VK_COMPONENT_SWIZZLE_IDENTITY;
559     viewInfo.components.b = VK_COMPONENT_SWIZZLE_IDENTITY;
560     viewInfo.components.a = VK_COMPONENT_SWIZZLE_IDENTITY;
561 
562     VkImageViewUsageCreateInfo imageViewUsageCreateInfo = {};
563     imageViewUsageCreateInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_USAGE_CREATE_INFO;
564     imageViewUsageCreateInfo.usage = getVkImageUsageFlags();
565 
566     viewInfo.pNext = &imageViewUsageCreateInfo;
567 
568     ANGLE_VK_TRY(mContext, mImageView.init(mContext->getDevice(), viewInfo));
569     return angle::Result::Continue;
570 }
571 
isCurrentlyInUse() const572 bool CLImageVk::isCurrentlyInUse() const
573 {
574     return !mRenderer->hasResourceUseFinished(mImage.getResourceUse());
575 }
576 
containsHostMemExtension()577 bool CLImageVk::containsHostMemExtension()
578 {
579     const vk::ExtensionNameList &enabledDeviceExtensions = mRenderer->getEnabledDeviceExtensions();
580     return std::find(enabledDeviceExtensions.begin(), enabledDeviceExtensions.end(),
581                      "VK_EXT_external_memory_host") != enabledDeviceExtensions.end();
582 }
583 
packPixels(const void * fillColor,PixelColor * packedColor)584 void CLImageVk::packPixels(const void *fillColor, PixelColor *packedColor)
585 {
586     size_t channelCount = cl::GetChannelCount(getFormat().image_channel_order);
587 
588     switch (getFormat().image_channel_data_type)
589     {
590         case CL_UNORM_INT8:
591         {
592             float *srcVector = static_cast<float *>(const_cast<void *>(fillColor));
593             if (getFormat().image_channel_order == CL_BGRA)
594             {
595                 packedColor->u8[0] =
596                     static_cast<unsigned char>(NormalizeFloatValue(srcVector[2], 255.f));
597                 packedColor->u8[1] =
598                     static_cast<unsigned char>(NormalizeFloatValue(srcVector[1], 255.f));
599                 packedColor->u8[2] =
600                     static_cast<unsigned char>(NormalizeFloatValue(srcVector[0], 255.f));
601                 packedColor->u8[3] =
602                     static_cast<unsigned char>(NormalizeFloatValue(srcVector[3], 255.f));
603             }
604             else
605             {
606                 for (unsigned int i = 0; i < channelCount; i++)
607                     packedColor->u8[i] =
608                         static_cast<unsigned char>(NormalizeFloatValue(srcVector[i], 255.f));
609             }
610             break;
611         }
612         case CL_SIGNED_INT8:
613         {
614             int *srcVector = static_cast<int *>(const_cast<void *>(fillColor));
615             for (unsigned int i = 0; i < channelCount; i++)
616                 packedColor->s8[i] = static_cast<char>(std::clamp(srcVector[i], -128, 127));
617             break;
618         }
619         case CL_UNSIGNED_INT8:
620         {
621             unsigned int *srcVector = static_cast<unsigned int *>(const_cast<void *>(fillColor));
622             for (unsigned int i = 0; i < channelCount; i++)
623                 packedColor->u8[i] = static_cast<unsigned char>(
624                     std::clamp(static_cast<unsigned int>(srcVector[i]),
625                                static_cast<unsigned int>(0), static_cast<unsigned int>(255)));
626             break;
627         }
628         case CL_UNORM_INT16:
629         {
630             float *srcVector = static_cast<float *>(const_cast<void *>(fillColor));
631             for (unsigned int i = 0; i < channelCount; i++)
632                 packedColor->u16[i] =
633                     static_cast<unsigned short>(NormalizeFloatValue(srcVector[i], 65535.f));
634             break;
635         }
636         case CL_SIGNED_INT16:
637         {
638             int *srcVector = static_cast<int *>(const_cast<void *>(fillColor));
639             for (unsigned int i = 0; i < channelCount; i++)
640                 packedColor->s16[i] = static_cast<short>(std::clamp(srcVector[i], -32768, 32767));
641             break;
642         }
643         case CL_UNSIGNED_INT16:
644         {
645             unsigned int *srcVector = static_cast<unsigned int *>(const_cast<void *>(fillColor));
646             for (unsigned int i = 0; i < channelCount; i++)
647                 packedColor->u16[i] = static_cast<unsigned short>(
648                     std::clamp(static_cast<unsigned int>(srcVector[i]),
649                                static_cast<unsigned int>(0), static_cast<unsigned int>(65535)));
650             break;
651         }
652         case CL_HALF_FLOAT:
653         {
654             float *srcVector = static_cast<float *>(const_cast<void *>(fillColor));
655             for (unsigned int i = 0; i < channelCount; i++)
656                 packedColor->fp16[i] = cl_half_from_float(srcVector[i], CL_HALF_RTE);
657             break;
658         }
659         case CL_SIGNED_INT32:
660         {
661             int *srcVector = static_cast<int *>(const_cast<void *>(fillColor));
662             for (unsigned int i = 0; i < channelCount; i++)
663                 packedColor->s32[i] = static_cast<int>(srcVector[i]);
664             break;
665         }
666         case CL_UNSIGNED_INT32:
667         {
668             unsigned int *srcVector = static_cast<unsigned int *>(const_cast<void *>(fillColor));
669             for (unsigned int i = 0; i < channelCount; i++)
670                 packedColor->u32[i] = static_cast<unsigned int>(srcVector[i]);
671             break;
672         }
673         case CL_FLOAT:
674         {
675             float *srcVector = static_cast<float *>(const_cast<void *>(fillColor));
676             for (unsigned int i = 0; i < channelCount; i++)
677                 packedColor->fp32[i] = srcVector[i];
678             break;
679         }
680         default:
681             UNIMPLEMENTED();
682             break;
683     }
684 }
685 
fillImageWithColor(const cl::MemOffsets & origin,const cl::Coordinate & region,uint8_t * imagePtr,PixelColor * packedColor)686 void CLImageVk::fillImageWithColor(const cl::MemOffsets &origin,
687                                    const cl::Coordinate &region,
688                                    uint8_t *imagePtr,
689                                    PixelColor *packedColor)
690 {
691     size_t elementSize = getElementSize();
692     cl::BufferBox stagingBufferBox{
693         {}, {mExtent.width, mExtent.height, mExtent.depth}, 0, 0, elementSize};
694     uint8_t *ptrBase = imagePtr + (origin.z * stagingBufferBox.getSlicePitch()) +
695                        (origin.y * stagingBufferBox.getRowPitch()) + (origin.x * elementSize);
696     for (size_t slice = 0; slice < region.z; slice++)
697     {
698         for (size_t row = 0; row < region.y; row++)
699         {
700             size_t stagingBufferOffset = stagingBufferBox.getRowOffset(slice, row);
701             uint8_t *pixelPtr          = ptrBase + stagingBufferOffset;
702             for (size_t x = 0; x < region.x; x++)
703             {
704                 memcpy(pixelPtr, packedColor, elementSize);
705                 pixelPtr += elementSize;
706             }
707         }
708     }
709 }
710 
getExtentForCopy(const cl::Coordinate & region)711 cl::Extents CLImageVk::getExtentForCopy(const cl::Coordinate &region)
712 {
713     cl::Extents extent = {};
714     extent.width       = region.x;
715     extent.height      = region.y;
716     extent.depth       = region.z;
717     switch (getDescriptor().type)
718     {
719         case cl::MemObjectType::Image1D_Array:
720 
721             extent.height = 1;
722             extent.depth  = 1;
723             break;
724         case cl::MemObjectType::Image2D_Array:
725             extent.depth = 1;
726             break;
727         default:
728             break;
729     }
730     return extent;
731 }
732 
getOffsetForCopy(const cl::MemOffsets & origin)733 cl::Offset CLImageVk::getOffsetForCopy(const cl::MemOffsets &origin)
734 {
735     cl::Offset offset = {};
736     offset.x          = origin.x;
737     offset.y          = origin.y;
738     offset.z          = origin.z;
739     switch (getDescriptor().type)
740     {
741         case cl::MemObjectType::Image1D_Array:
742             offset.y = 0;
743             offset.z = 0;
744             break;
745         case cl::MemObjectType::Image2D_Array:
746             offset.z = 0;
747             break;
748         default:
749             break;
750     }
751     return offset;
752 }
753 
getSubresourceLayersForCopy(const cl::MemOffsets & origin,const cl::Coordinate & region,cl::MemObjectType copyToType,ImageCopyWith imageCopy)754 VkImageSubresourceLayers CLImageVk::getSubresourceLayersForCopy(const cl::MemOffsets &origin,
755                                                                 const cl::Coordinate &region,
756                                                                 cl::MemObjectType copyToType,
757                                                                 ImageCopyWith imageCopy)
758 {
759     VkImageSubresourceLayers subresource = {};
760     subresource.aspectMask               = VK_IMAGE_ASPECT_COLOR_BIT;
761     subresource.mipLevel                 = 0;
762     switch (getDescriptor().type)
763     {
764         case cl::MemObjectType::Image1D_Array:
765             subresource.baseArrayLayer = static_cast<uint32_t>(origin.y);
766             if (imageCopy == ImageCopyWith::Image)
767             {
768                 subresource.layerCount = static_cast<uint32_t>(region.y);
769             }
770             else
771             {
772                 subresource.layerCount = static_cast<uint32_t>(getArraySize());
773             }
774             break;
775         case cl::MemObjectType::Image2D_Array:
776             subresource.baseArrayLayer = static_cast<uint32_t>(origin.z);
777             if (copyToType == cl::MemObjectType::Image2D ||
778                 copyToType == cl::MemObjectType::Image3D)
779             {
780                 subresource.layerCount = 1;
781             }
782             else if (imageCopy == ImageCopyWith::Image)
783             {
784                 subresource.layerCount = static_cast<uint32_t>(region.z);
785             }
786             else
787             {
788                 subresource.layerCount = static_cast<uint32_t>(getArraySize());
789             }
790             break;
791         default:
792             subresource.baseArrayLayer = 0;
793             subresource.layerCount     = 1;
794             break;
795     }
796     return subresource;
797 }
798 
mapImpl()799 angle::Result CLImageVk::mapImpl()
800 {
801     ASSERT(!isMapped());
802 
803     if (mParent)
804     {
805         ANGLE_TRY(mParent->map(mMappedMemory, getOffset()));
806         return angle::Result::Continue;
807     }
808 
809     ASSERT(isStagingBufferInitialized());
810     ANGLE_TRY(getStagingBuffer().map(mContext, &mMappedMemory));
811 
812     return angle::Result::Continue;
813 }
unmapImpl()814 void CLImageVk::unmapImpl()
815 {
816     if (!mParent)
817     {
818         getStagingBuffer().unmap(mContext->getRenderer());
819     }
820     mMappedMemory = nullptr;
821 }
822 
getRowPitch() const823 size_t CLImageVk::getRowPitch() const
824 {
825     return getFrontendObject().getRowSize();
826 }
827 
getSlicePitch() const828 size_t CLImageVk::getSlicePitch() const
829 {
830     return getFrontendObject().getSliceSize();
831 }
832 
833 template <>
getParent() const834 CLBufferVk *CLImageVk::getParent<CLBufferVk>() const
835 {
836     if (mParent)
837     {
838         ASSERT(cl::IsBufferType(getParentType()));
839         return static_cast<CLBufferVk *>(mParent);
840     }
841     return nullptr;
842 }
843 
844 template <>
getParent() const845 CLImageVk *CLImageVk::getParent<CLImageVk>() const
846 {
847     if (mParent)
848     {
849         ASSERT(cl::IsImageType(getParentType()));
850         return static_cast<CLImageVk *>(mParent);
851     }
852     return nullptr;
853 }
854 
getParentType() const855 cl::MemObjectType CLImageVk::getParentType() const
856 {
857     if (mParent)
858     {
859         return mParent->getType();
860     }
861     return cl::MemObjectType::InvalidEnum;
862 }
863 
getBufferView(const vk::BufferView ** viewOut)864 angle::Result CLImageVk::getBufferView(const vk::BufferView **viewOut)
865 {
866     if (!mBufferViews.isInitialized())
867     {
868         ANGLE_CL_RETURN_ERROR(CL_OUT_OF_RESOURCES);
869     }
870 
871     CLBufferVk *parent = getParent<CLBufferVk>();
872 
873     return mBufferViews.getView(
874         mContext, parent->getBuffer(), parent->getOffset(),
875         mContext->getRenderer()->getFormat(CLImageFormatToAngleFormat(getFormat())), viewOut);
876 }
877 
878 }  // namespace rx
879