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