• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
copyToWithPitch(void * hostPtr,size_t srcOffset,size_t size,size_t rowPitch,size_t slicePitch,cl::Coordinate region,const size_t elementSize)216 angle::Result CLBufferVk::copyToWithPitch(void *hostPtr,
217                                           size_t srcOffset,
218                                           size_t size,
219                                           size_t rowPitch,
220                                           size_t slicePitch,
221                                           cl::Coordinate region,
222                                           const size_t elementSize)
223 {
224     uint8_t *ptrInBase  = nullptr;
225     uint8_t *ptrOutBase = nullptr;
226     cl::BufferRect stagingBufferRect{
227         {static_cast<int>(0), static_cast<int>(0), static_cast<int>(0)},
228         {region.x, region.y, region.z},
229         0,
230         0,
231         elementSize};
232 
233     ptrOutBase = static_cast<uint8_t *>(hostPtr);
234     ANGLE_TRY(getBuffer().map(mContext, &ptrInBase));
235 
236     for (size_t slice = 0; slice < region.z; slice++)
237     {
238         for (size_t row = 0; row < region.y; row++)
239         {
240             size_t stagingBufferOffset = stagingBufferRect.getRowOffset(slice, row);
241             size_t hostPtrOffset       = (slice * slicePitch + row * rowPitch);
242             uint8_t *dst               = ptrOutBase + hostPtrOffset;
243             uint8_t *src               = ptrInBase + stagingBufferOffset;
244             memcpy(dst, src, region.x * elementSize);
245         }
246     }
247     getBuffer().unmap(mContext->getRenderer());
248     return angle::Result::Continue;
249 }
250 
mapImpl()251 angle::Result CLBufferVk::mapImpl()
252 {
253     ASSERT(!isMapped());
254 
255     if (isSubBuffer())
256     {
257         ANGLE_TRY(mParent->map(mMappedMemory, getOffset()));
258         return angle::Result::Continue;
259     }
260     ANGLE_TRY(mBuffer.map(mContext, &mMappedMemory));
261     return angle::Result::Continue;
262 }
263 
unmapImpl()264 void CLBufferVk::unmapImpl()
265 {
266     if (!isSubBuffer())
267     {
268         mBuffer.unmap(mRenderer);
269     }
270     mMappedMemory = nullptr;
271 }
272 
setRect(const void * data,const cl::BufferRect & srcRect,const cl::BufferRect & rect)273 angle::Result CLBufferVk::setRect(const void *data,
274                                   const cl::BufferRect &srcRect,
275                                   const cl::BufferRect &rect)
276 {
277     ASSERT(srcRect.valid() && rect.valid());
278     ASSERT(srcRect.mSize == rect.mSize);
279 
280     uint8_t *mapPtr = nullptr;
281     ANGLE_TRY(map(mapPtr));
282     const uint8_t *srcData = reinterpret_cast<const uint8_t *>(data);
283     for (size_t slice = 0; slice < rect.mSize.depth; slice++)
284     {
285         for (size_t row = 0; row < rect.mSize.height; row++)
286         {
287             const uint8_t *src = srcData + srcRect.getRowOffset(slice, row);
288             uint8_t *dst       = mapPtr + rect.getRowOffset(slice, row);
289 
290             memcpy(dst, src, srcRect.mSize.width * srcRect.mElementSize);
291         }
292     }
293 
294     return angle::Result::Continue;
295 }
296 
getRect(const cl::BufferRect & srcRect,const cl::BufferRect & outRect,void * outData)297 angle::Result CLBufferVk::getRect(const cl::BufferRect &srcRect,
298                                   const cl::BufferRect &outRect,
299                                   void *outData)
300 {
301     ASSERT(srcRect.valid() && outRect.valid());
302     ASSERT(srcRect.mSize == outRect.mSize);
303 
304     uint8_t *mapPtr = nullptr;
305     ANGLE_TRY(map(mapPtr));
306     uint8_t *dstData = reinterpret_cast<uint8_t *>(outData);
307     for (size_t slice = 0; slice < srcRect.mSize.depth; slice++)
308     {
309         for (size_t row = 0; row < srcRect.mSize.height; row++)
310         {
311             const uint8_t *src = mapPtr + srcRect.getRowOffset(slice, row);
312             uint8_t *dst       = dstData + outRect.getRowOffset(slice, row);
313 
314             memcpy(dst, src, srcRect.mSize.width * srcRect.mElementSize);
315         }
316     }
317 
318     return angle::Result::Continue;
319 }
320 
rectCopyRegions(const cl::BufferRect & bufferRect)321 std::vector<VkBufferCopy> CLBufferVk::rectCopyRegions(const cl::BufferRect &bufferRect)
322 {
323     std::vector<VkBufferCopy> copyRegions;
324     for (unsigned int slice = 0; slice < bufferRect.mSize.depth; slice++)
325     {
326         for (unsigned int row = 0; row < bufferRect.mSize.height; row++)
327         {
328             VkBufferCopy copyRegion = {};
329             copyRegion.size         = bufferRect.mSize.width * bufferRect.mElementSize;
330             copyRegion.srcOffset = copyRegion.dstOffset = bufferRect.getRowOffset(slice, row);
331             copyRegions.push_back(copyRegion);
332         }
333     }
334     return copyRegions;
335 }
336 
337 // offset is for mapped pointer
setDataImpl(const uint8_t * data,size_t size,size_t offset)338 angle::Result CLBufferVk::setDataImpl(const uint8_t *data, size_t size, size_t offset)
339 {
340     // buffer cannot be in use state
341     ASSERT(mBuffer.valid());
342     ASSERT(!isCurrentlyInUse());
343     ASSERT(size + offset <= getSize());
344     ASSERT(data != nullptr);
345 
346     // Assuming host visible buffers for now
347     // TODO: http://anglebug.com/42267019
348     if (!mBuffer.isHostVisible())
349     {
350         UNIMPLEMENTED();
351         ANGLE_CL_RETURN_ERROR(CL_OUT_OF_RESOURCES);
352     }
353 
354     uint8_t *mapPointer = nullptr;
355     ANGLE_TRY(mBuffer.mapWithOffset(mContext, &mapPointer, offset));
356     ASSERT(mapPointer != nullptr);
357 
358     std::memcpy(mapPointer, data, size);
359     mBuffer.unmap(mRenderer);
360 
361     return angle::Result::Continue;
362 }
363 
isCurrentlyInUse() const364 bool CLBufferVk::isCurrentlyInUse() const
365 {
366     return !mRenderer->hasResourceUseFinished(mBuffer.getResourceUse());
367 }
368 
getVkImageUsageFlags()369 VkImageUsageFlags CLImageVk::getVkImageUsageFlags()
370 {
371     VkImageUsageFlags usageFlags =
372         VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
373 
374     if (mMemory.getFlags().intersects(CL_MEM_WRITE_ONLY))
375     {
376         usageFlags |= VK_IMAGE_USAGE_STORAGE_BIT;
377     }
378     else if (mMemory.getFlags().intersects(CL_MEM_READ_ONLY))
379     {
380         usageFlags |= VK_IMAGE_USAGE_SAMPLED_BIT;
381     }
382     else
383     {
384         usageFlags |= VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_STORAGE_BIT;
385     }
386 
387     return usageFlags;
388 }
389 
getVkImageType(const cl::ImageDescriptor & desc)390 VkImageType CLImageVk::getVkImageType(const cl::ImageDescriptor &desc)
391 {
392     VkImageType imageType = VK_IMAGE_TYPE_MAX_ENUM;
393 
394     switch (desc.type)
395     {
396         case cl::MemObjectType::Image1D_Buffer:
397         case cl::MemObjectType::Image1D:
398         case cl::MemObjectType::Image1D_Array:
399             return VK_IMAGE_TYPE_1D;
400         case cl::MemObjectType::Image2D:
401         case cl::MemObjectType::Image2D_Array:
402             return VK_IMAGE_TYPE_2D;
403         case cl::MemObjectType::Image3D:
404             return VK_IMAGE_TYPE_3D;
405         default:
406             UNREACHABLE();
407     }
408 
409     return imageType;
410 }
411 
createStagingBuffer(size_t size)412 angle::Result CLImageVk::createStagingBuffer(size_t size)
413 {
414     const VkBufferCreateInfo createInfo = {VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
415                                            nullptr,
416                                            0,
417                                            size,
418                                            getVkUsageFlags(),
419                                            VK_SHARING_MODE_EXCLUSIVE,
420                                            0,
421                                            nullptr};
422     if (IsError(mStagingBuffer.init(mContext, createInfo, getVkMemPropertyFlags())))
423     {
424         ANGLE_CL_RETURN_ERROR(CL_OUT_OF_RESOURCES);
425     }
426 
427     mStagingBufferInitialized = true;
428     return angle::Result::Continue;
429 }
430 
copyStagingFrom(void * ptr,size_t offset,size_t size)431 angle::Result CLImageVk::copyStagingFrom(void *ptr, size_t offset, size_t size)
432 {
433     uint8_t *ptrOut;
434     uint8_t *ptrIn = static_cast<uint8_t *>(ptr);
435     ANGLE_TRY(getStagingBuffer().map(mContext, &ptrOut));
436     std::memcpy(ptrOut, ptrIn + offset, size);
437     ANGLE_TRY(getStagingBuffer().flush(mRenderer));
438     getStagingBuffer().unmap(mContext->getRenderer());
439     return angle::Result::Continue;
440 }
441 
copyStagingTo(void * ptr,size_t offset,size_t size)442 angle::Result CLImageVk::copyStagingTo(void *ptr, size_t offset, size_t size)
443 {
444     uint8_t *ptrOut;
445     ANGLE_TRY(getStagingBuffer().map(mContext, &ptrOut));
446     ANGLE_TRY(getStagingBuffer().invalidate(mRenderer));
447     std::memcpy(ptr, ptrOut + offset, size);
448     getStagingBuffer().unmap(mContext->getRenderer());
449     return angle::Result::Continue;
450 }
451 
copyStagingToFromWithPitch(void * hostPtr,const cl::Coordinate & region,const size_t rowPitch,const size_t slicePitch,StagingBufferCopyDirection copyStagingTo)452 angle::Result CLImageVk::copyStagingToFromWithPitch(void *hostPtr,
453                                                     const cl::Coordinate &region,
454                                                     const size_t rowPitch,
455                                                     const size_t slicePitch,
456                                                     StagingBufferCopyDirection copyStagingTo)
457 {
458     uint8_t *ptrInBase  = nullptr;
459     uint8_t *ptrOutBase = nullptr;
460     cl::BufferRect stagingBufferRect{{}, {region.x, region.y, region.z}, 0, 0, getElementSize()};
461 
462     if (copyStagingTo == StagingBufferCopyDirection::ToHost)
463     {
464         ptrOutBase = static_cast<uint8_t *>(hostPtr);
465         ANGLE_TRY(getStagingBuffer().map(mContext, &ptrInBase));
466     }
467     else
468     {
469         ptrInBase = static_cast<uint8_t *>(hostPtr);
470         ANGLE_TRY(getStagingBuffer().map(mContext, &ptrOutBase));
471     }
472     for (size_t slice = 0; slice < region.z; slice++)
473     {
474         for (size_t row = 0; row < region.y; row++)
475         {
476             size_t stagingBufferOffset = stagingBufferRect.getRowOffset(slice, row);
477             size_t hostPtrOffset       = (slice * slicePitch + row * rowPitch);
478             uint8_t *dst               = (copyStagingTo == StagingBufferCopyDirection::ToHost)
479                                              ? ptrOutBase + hostPtrOffset
480                                              : ptrOutBase + stagingBufferOffset;
481             uint8_t *src               = (copyStagingTo == StagingBufferCopyDirection::ToHost)
482                                              ? ptrInBase + stagingBufferOffset
483                                              : ptrInBase + hostPtrOffset;
484             memcpy(dst, src, region.x * getElementSize());
485         }
486     }
487     getStagingBuffer().unmap(mContext->getRenderer());
488     return angle::Result::Continue;
489 }
490 
CLImageVk(const cl::Image & image)491 CLImageVk::CLImageVk(const cl::Image &image)
492     : CLMemoryVk(image),
493       mExtent(cl::GetExtentFromDescriptor(image.getDescriptor())),
494       mAngleFormat(CLImageFormatToAngleFormat(image.getFormat())),
495       mStagingBufferInitialized(false),
496       mImageViewType(cl_vk::GetImageViewType(image.getDescriptor().type))
497 {
498     if (image.getParent())
499     {
500         mParent = &image.getParent()->getImpl<CLMemoryVk>();
501     }
502 }
503 
~CLImageVk()504 CLImageVk::~CLImageVk()
505 {
506     if (isMapped())
507     {
508         unmap();
509     }
510 
511     if (mBufferViews.isInitialized())
512     {
513         mBufferViews.release(mContext->getRenderer());
514     }
515 
516     mImage.destroy(mRenderer);
517     mImageView.destroy(mContext->getDevice());
518     if (isStagingBufferInitialized())
519     {
520         mStagingBuffer.destroy(mRenderer);
521     }
522 }
523 
createFromBuffer()524 angle::Result CLImageVk::createFromBuffer()
525 {
526     ASSERT(mParent);
527     ASSERT(IsBufferType(getParentType()));
528 
529     // initialize the buffer views
530     mBufferViews.init(mContext->getRenderer(), 0, getSize());
531 
532     return angle::Result::Continue;
533 }
534 
create(void * hostPtr)535 angle::Result CLImageVk::create(void *hostPtr)
536 {
537     if (mParent)
538     {
539         if (getType() == cl::MemObjectType::Image1D_Buffer)
540         {
541             return createFromBuffer();
542         }
543         else
544         {
545             UNIMPLEMENTED();
546             ANGLE_CL_RETURN_ERROR(CL_OUT_OF_RESOURCES);
547         }
548     }
549 
550     ANGLE_CL_IMPL_TRY_ERROR(
551         mImage.initStaging(mContext, false, mRenderer->getMemoryProperties(),
552                            getVkImageType(getDescriptor()), cl_vk::GetExtent(mExtent), mAngleFormat,
553                            mAngleFormat, VK_SAMPLE_COUNT_1_BIT, getVkImageUsageFlags(), 1,
554                            (uint32_t)getArraySize()),
555         CL_OUT_OF_RESOURCES);
556 
557     if (mMemory.getFlags().intersects(CL_MEM_USE_HOST_PTR | CL_MEM_COPY_HOST_PTR))
558     {
559         ASSERT(hostPtr);
560         ANGLE_CL_IMPL_TRY_ERROR(createStagingBuffer(getSize()), CL_OUT_OF_RESOURCES);
561         if (getDescriptor().rowPitch == 0 && getDescriptor().slicePitch == 0)
562         {
563             ANGLE_CL_IMPL_TRY_ERROR(copyStagingFrom(hostPtr, 0, getSize()), CL_OUT_OF_RESOURCES);
564         }
565         else
566         {
567             ANGLE_TRY(copyStagingToFromWithPitch(
568                 hostPtr, {mExtent.width, mExtent.height, mExtent.depth}, getDescriptor().rowPitch,
569                 getDescriptor().slicePitch, StagingBufferCopyDirection::ToStagingBuffer));
570         }
571         VkBufferImageCopy copyRegion{};
572         copyRegion.bufferOffset      = 0;
573         copyRegion.bufferRowLength   = 0;
574         copyRegion.bufferImageHeight = 0;
575         copyRegion.imageExtent =
576             cl_vk::GetExtent(getExtentForCopy({mExtent.width, mExtent.height, mExtent.depth}));
577         copyRegion.imageOffset      = cl_vk::GetOffset(getOffsetForCopy(cl::kMemOffsetsZero));
578         copyRegion.imageSubresource = getSubresourceLayersForCopy(
579             cl::kMemOffsetsZero, {mExtent.width, mExtent.height, mExtent.depth}, getType(),
580             ImageCopyWith::Buffer);
581 
582         ANGLE_CL_IMPL_TRY_ERROR(mImage.copyToBufferOneOff(mContext, &mStagingBuffer, copyRegion),
583                                 CL_OUT_OF_RESOURCES);
584     }
585 
586     ANGLE_TRY(initImageViewImpl());
587     return angle::Result::Continue;
588 }
589 
initImageViewImpl()590 angle::Result CLImageVk::initImageViewImpl()
591 {
592     VkImageViewCreateInfo viewInfo = {};
593     viewInfo.sType                 = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
594     viewInfo.flags                 = 0;
595     viewInfo.image                 = getImage().getImage().getHandle();
596     viewInfo.format                = getImage().getActualVkFormat(mContext->getRenderer());
597     viewInfo.viewType              = mImageViewType;
598 
599     viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
600     // We don't support mip map levels and should have been validated
601     ASSERT(getDescriptor().numMipLevels == 0);
602     viewInfo.subresourceRange.baseMipLevel   = getDescriptor().numMipLevels;
603     viewInfo.subresourceRange.levelCount     = 1;
604     viewInfo.subresourceRange.baseArrayLayer = 0;
605     viewInfo.subresourceRange.layerCount     = static_cast<uint32_t>(getArraySize());
606 
607     // no swizzle support for now
608     viewInfo.components.r = VK_COMPONENT_SWIZZLE_IDENTITY;
609     viewInfo.components.g = VK_COMPONENT_SWIZZLE_IDENTITY;
610     viewInfo.components.b = VK_COMPONENT_SWIZZLE_IDENTITY;
611     viewInfo.components.a = VK_COMPONENT_SWIZZLE_IDENTITY;
612 
613     VkImageViewUsageCreateInfo imageViewUsageCreateInfo = {};
614     imageViewUsageCreateInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_USAGE_CREATE_INFO;
615     imageViewUsageCreateInfo.usage = getVkImageUsageFlags();
616 
617     viewInfo.pNext = &imageViewUsageCreateInfo;
618 
619     ANGLE_VK_TRY(mContext, mImageView.init(mContext->getDevice(), viewInfo));
620     return angle::Result::Continue;
621 }
622 
isCurrentlyInUse() const623 bool CLImageVk::isCurrentlyInUse() const
624 {
625     return !mRenderer->hasResourceUseFinished(mImage.getResourceUse());
626 }
627 
containsHostMemExtension()628 bool CLImageVk::containsHostMemExtension()
629 {
630     const vk::ExtensionNameList &enabledDeviceExtensions = mRenderer->getEnabledDeviceExtensions();
631     return std::find(enabledDeviceExtensions.begin(), enabledDeviceExtensions.end(),
632                      "VK_EXT_external_memory_host") != enabledDeviceExtensions.end();
633 }
634 
packPixels(const void * fillColor,PixelColor * packedColor)635 void CLImageVk::packPixels(const void *fillColor, PixelColor *packedColor)
636 {
637     size_t channelCount = cl::GetChannelCount(getFormat().image_channel_order);
638 
639     switch (getFormat().image_channel_data_type)
640     {
641         case CL_UNORM_INT8:
642         {
643             float *srcVector = static_cast<float *>(const_cast<void *>(fillColor));
644             if (getFormat().image_channel_order == CL_BGRA)
645             {
646                 packedColor->u8[0] =
647                     static_cast<unsigned char>(NormalizeFloatValue(srcVector[2], 255.f));
648                 packedColor->u8[1] =
649                     static_cast<unsigned char>(NormalizeFloatValue(srcVector[1], 255.f));
650                 packedColor->u8[2] =
651                     static_cast<unsigned char>(NormalizeFloatValue(srcVector[0], 255.f));
652                 packedColor->u8[3] =
653                     static_cast<unsigned char>(NormalizeFloatValue(srcVector[3], 255.f));
654             }
655             else
656             {
657                 for (unsigned int i = 0; i < channelCount; i++)
658                     packedColor->u8[i] =
659                         static_cast<unsigned char>(NormalizeFloatValue(srcVector[i], 255.f));
660             }
661             break;
662         }
663         case CL_SIGNED_INT8:
664         {
665             int *srcVector = static_cast<int *>(const_cast<void *>(fillColor));
666             for (unsigned int i = 0; i < channelCount; i++)
667                 packedColor->s8[i] = static_cast<char>(std::clamp(srcVector[i], -128, 127));
668             break;
669         }
670         case CL_UNSIGNED_INT8:
671         {
672             unsigned int *srcVector = static_cast<unsigned int *>(const_cast<void *>(fillColor));
673             for (unsigned int i = 0; i < channelCount; i++)
674                 packedColor->u8[i] = static_cast<unsigned char>(
675                     std::clamp(static_cast<unsigned int>(srcVector[i]),
676                                static_cast<unsigned int>(0), static_cast<unsigned int>(255)));
677             break;
678         }
679         case CL_UNORM_INT16:
680         {
681             float *srcVector = static_cast<float *>(const_cast<void *>(fillColor));
682             for (unsigned int i = 0; i < channelCount; i++)
683                 packedColor->u16[i] =
684                     static_cast<unsigned short>(NormalizeFloatValue(srcVector[i], 65535.f));
685             break;
686         }
687         case CL_SIGNED_INT16:
688         {
689             int *srcVector = static_cast<int *>(const_cast<void *>(fillColor));
690             for (unsigned int i = 0; i < channelCount; i++)
691                 packedColor->s16[i] = static_cast<short>(std::clamp(srcVector[i], -32768, 32767));
692             break;
693         }
694         case CL_UNSIGNED_INT16:
695         {
696             unsigned int *srcVector = static_cast<unsigned int *>(const_cast<void *>(fillColor));
697             for (unsigned int i = 0; i < channelCount; i++)
698                 packedColor->u16[i] = static_cast<unsigned short>(
699                     std::clamp(static_cast<unsigned int>(srcVector[i]),
700                                static_cast<unsigned int>(0), static_cast<unsigned int>(65535)));
701             break;
702         }
703         case CL_HALF_FLOAT:
704         {
705             float *srcVector = static_cast<float *>(const_cast<void *>(fillColor));
706             for (unsigned int i = 0; i < channelCount; i++)
707                 packedColor->fp16[i] = cl_half_from_float(srcVector[i], CL_HALF_RTE);
708             break;
709         }
710         case CL_SIGNED_INT32:
711         {
712             int *srcVector = static_cast<int *>(const_cast<void *>(fillColor));
713             for (unsigned int i = 0; i < channelCount; i++)
714                 packedColor->s32[i] = static_cast<int>(srcVector[i]);
715             break;
716         }
717         case CL_UNSIGNED_INT32:
718         {
719             unsigned int *srcVector = static_cast<unsigned int *>(const_cast<void *>(fillColor));
720             for (unsigned int i = 0; i < channelCount; i++)
721                 packedColor->u32[i] = static_cast<unsigned int>(srcVector[i]);
722             break;
723         }
724         case CL_FLOAT:
725         {
726             float *srcVector = static_cast<float *>(const_cast<void *>(fillColor));
727             for (unsigned int i = 0; i < channelCount; i++)
728                 packedColor->fp32[i] = srcVector[i];
729             break;
730         }
731         default:
732             UNIMPLEMENTED();
733             break;
734     }
735 }
736 
fillImageWithColor(const cl::MemOffsets & origin,const cl::Coordinate & region,uint8_t * imagePtr,PixelColor * packedColor)737 void CLImageVk::fillImageWithColor(const cl::MemOffsets &origin,
738                                    const cl::Coordinate &region,
739                                    uint8_t *imagePtr,
740                                    PixelColor *packedColor)
741 {
742     size_t elementSize = getElementSize();
743     cl::BufferRect stagingBufferRect{
744         {}, {mExtent.width, mExtent.height, mExtent.depth}, 0, 0, elementSize};
745     uint8_t *ptrBase = imagePtr + (origin.z * stagingBufferRect.getSlicePitch()) +
746                        (origin.y * stagingBufferRect.getRowPitch()) + (origin.x * elementSize);
747     for (size_t slice = 0; slice < region.z; slice++)
748     {
749         for (size_t row = 0; row < region.y; row++)
750         {
751             size_t stagingBufferOffset = stagingBufferRect.getRowOffset(slice, row);
752             uint8_t *pixelPtr          = ptrBase + stagingBufferOffset;
753             for (size_t x = 0; x < region.x; x++)
754             {
755                 memcpy(pixelPtr, packedColor, elementSize);
756                 pixelPtr += elementSize;
757             }
758         }
759     }
760 }
761 
getExtentForCopy(const cl::Coordinate & region)762 cl::Extents CLImageVk::getExtentForCopy(const cl::Coordinate &region)
763 {
764     cl::Extents extent = {};
765     extent.width       = region.x;
766     extent.height      = region.y;
767     extent.depth       = region.z;
768     switch (getDescriptor().type)
769     {
770         case cl::MemObjectType::Image1D_Array:
771 
772             extent.height = 1;
773             extent.depth  = 1;
774             break;
775         case cl::MemObjectType::Image2D_Array:
776             extent.depth = 1;
777             break;
778         default:
779             break;
780     }
781     return extent;
782 }
783 
getOffsetForCopy(const cl::MemOffsets & origin)784 cl::Offset CLImageVk::getOffsetForCopy(const cl::MemOffsets &origin)
785 {
786     cl::Offset offset = {};
787     offset.x          = origin.x;
788     offset.y          = origin.y;
789     offset.z          = origin.z;
790     switch (getDescriptor().type)
791     {
792         case cl::MemObjectType::Image1D_Array:
793             offset.y = 0;
794             offset.z = 0;
795             break;
796         case cl::MemObjectType::Image2D_Array:
797             offset.z = 0;
798             break;
799         default:
800             break;
801     }
802     return offset;
803 }
804 
getSubresourceLayersForCopy(const cl::MemOffsets & origin,const cl::Coordinate & region,cl::MemObjectType copyToType,ImageCopyWith imageCopy)805 VkImageSubresourceLayers CLImageVk::getSubresourceLayersForCopy(const cl::MemOffsets &origin,
806                                                                 const cl::Coordinate &region,
807                                                                 cl::MemObjectType copyToType,
808                                                                 ImageCopyWith imageCopy)
809 {
810     VkImageSubresourceLayers subresource = {};
811     subresource.aspectMask               = VK_IMAGE_ASPECT_COLOR_BIT;
812     subresource.mipLevel                 = 0;
813     switch (getDescriptor().type)
814     {
815         case cl::MemObjectType::Image1D_Array:
816             subresource.baseArrayLayer = static_cast<uint32_t>(origin.y);
817             if (imageCopy == ImageCopyWith::Image)
818             {
819                 subresource.layerCount = static_cast<uint32_t>(region.y);
820             }
821             else
822             {
823                 subresource.layerCount = static_cast<uint32_t>(getArraySize());
824             }
825             break;
826         case cl::MemObjectType::Image2D_Array:
827             subresource.baseArrayLayer = static_cast<uint32_t>(origin.z);
828             if (copyToType == cl::MemObjectType::Image2D ||
829                 copyToType == cl::MemObjectType::Image3D)
830             {
831                 subresource.layerCount = 1;
832             }
833             else if (imageCopy == ImageCopyWith::Image)
834             {
835                 subresource.layerCount = static_cast<uint32_t>(region.z);
836             }
837             else
838             {
839                 subresource.layerCount = static_cast<uint32_t>(getArraySize());
840             }
841             break;
842         default:
843             subresource.baseArrayLayer = 0;
844             subresource.layerCount     = 1;
845             break;
846     }
847     return subresource;
848 }
849 
mapImpl()850 angle::Result CLImageVk::mapImpl()
851 {
852     ASSERT(!isMapped());
853 
854     if (mParent)
855     {
856         ANGLE_TRY(mParent->map(mMappedMemory, getOffset()));
857         return angle::Result::Continue;
858     }
859 
860     ASSERT(isStagingBufferInitialized());
861     ANGLE_TRY(getStagingBuffer().map(mContext, &mMappedMemory));
862 
863     return angle::Result::Continue;
864 }
unmapImpl()865 void CLImageVk::unmapImpl()
866 {
867     if (!mParent)
868     {
869         getStagingBuffer().unmap(mContext->getRenderer());
870     }
871     mMappedMemory = nullptr;
872 }
873 
getRowPitch() const874 size_t CLImageVk::getRowPitch() const
875 {
876     return getFrontendObject().getRowSize();
877 }
878 
getSlicePitch() const879 size_t CLImageVk::getSlicePitch() const
880 {
881     return getFrontendObject().getSliceSize();
882 }
883 
884 template <>
getParent() const885 CLBufferVk *CLImageVk::getParent<CLBufferVk>() const
886 {
887     if (mParent)
888     {
889         ASSERT(cl::IsBufferType(getParentType()));
890         return static_cast<CLBufferVk *>(mParent);
891     }
892     return nullptr;
893 }
894 
895 template <>
getParent() const896 CLImageVk *CLImageVk::getParent<CLImageVk>() const
897 {
898     if (mParent)
899     {
900         ASSERT(cl::IsImageType(getParentType()));
901         return static_cast<CLImageVk *>(mParent);
902     }
903     return nullptr;
904 }
905 
getParentType() const906 cl::MemObjectType CLImageVk::getParentType() const
907 {
908     if (mParent)
909     {
910         return mParent->getType();
911     }
912     return cl::MemObjectType::InvalidEnum;
913 }
914 
getBufferView(const vk::BufferView ** viewOut)915 angle::Result CLImageVk::getBufferView(const vk::BufferView **viewOut)
916 {
917     if (!mBufferViews.isInitialized())
918     {
919         ANGLE_CL_RETURN_ERROR(CL_OUT_OF_RESOURCES);
920     }
921 
922     CLBufferVk *parent = getParent<CLBufferVk>();
923 
924     return mBufferViews.getView(
925         mContext, parent->getBuffer(), parent->getOffset(),
926         mContext->getRenderer()->getFormat(CLImageFormatToAngleFormat(getFormat())), viewOut);
927 }
928 
929 }  // namespace rx
930