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 ®ion,
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 ®ion,
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 ®ion)
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 ®ion,
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