xref: /aosp_15_r20/external/angle/src/libANGLE/renderer/wgpu/wgpu_helpers.cpp (revision 8975f5c5ed3d1c378011245431ada316dfb6f244)
1 //
2 // Copyright 2024 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 
7 #include "libANGLE/renderer/wgpu/wgpu_helpers.h"
8 #include "libANGLE/formatutils.h"
9 
10 #include "libANGLE/renderer/wgpu/ContextWgpu.h"
11 #include "libANGLE/renderer/wgpu/DisplayWgpu.h"
12 #include "libANGLE/renderer/wgpu/FramebufferWgpu.h"
13 #include "wgpu_helpers.h"
14 
15 namespace rx
16 {
17 namespace webgpu
18 {
19 namespace
20 {
TextureDescriptorFromTexture(const wgpu::Texture & texture)21 wgpu::TextureDescriptor TextureDescriptorFromTexture(const wgpu::Texture &texture)
22 {
23     wgpu::TextureDescriptor descriptor = {};
24     descriptor.usage                   = texture.GetUsage();
25     descriptor.dimension               = texture.GetDimension();
26     descriptor.size   = {texture.GetWidth(), texture.GetHeight(), texture.GetDepthOrArrayLayers()};
27     descriptor.format = texture.GetFormat();
28     descriptor.mipLevelCount   = texture.GetMipLevelCount();
29     descriptor.sampleCount     = texture.GetSampleCount();
30     descriptor.viewFormatCount = 0;
31     return descriptor;
32 }
33 
GetSafeBufferMapOffset(size_t offset)34 size_t GetSafeBufferMapOffset(size_t offset)
35 {
36     static_assert(gl::isPow2(kBufferMapOffsetAlignment));
37     return roundDownPow2(offset, kBufferMapOffsetAlignment);
38 }
39 
GetSafeBufferMapSize(size_t offset,size_t size)40 size_t GetSafeBufferMapSize(size_t offset, size_t size)
41 {
42     // The offset is rounded down for alignment and the size is rounded up. The safe size must cover
43     // both of these offsets.
44     size_t offsetChange = offset % kBufferMapOffsetAlignment;
45     static_assert(gl::isPow2(kBufferMapSizeAlignment));
46     return roundUpPow2(size + offsetChange, kBufferMapSizeAlignment);
47 }
48 
AdjustMapPointerForOffset(uint8_t * mapPtr,size_t offset)49 uint8_t *AdjustMapPointerForOffset(uint8_t *mapPtr, size_t offset)
50 {
51     // Fix up a map pointer that has been adjusted for alignment
52     size_t offsetChange = offset % kBufferMapOffsetAlignment;
53     return mapPtr + offsetChange;
54 }
55 
AdjustMapPointerForOffset(const uint8_t * mapPtr,size_t offset)56 const uint8_t *AdjustMapPointerForOffset(const uint8_t *mapPtr, size_t offset)
57 {
58     return AdjustMapPointerForOffset(const_cast<uint8_t *>(mapPtr), offset);
59 }
60 
61 }  // namespace
62 
ImageHelper()63 ImageHelper::ImageHelper() {}
64 
~ImageHelper()65 ImageHelper::~ImageHelper() {}
66 
initImage(angle::FormatID intendedFormatID,angle::FormatID actualFormatID,wgpu::Device & device,gl::LevelIndex firstAllocatedLevel,wgpu::TextureDescriptor textureDescriptor)67 angle::Result ImageHelper::initImage(angle::FormatID intendedFormatID,
68                                      angle::FormatID actualFormatID,
69                                      wgpu::Device &device,
70                                      gl::LevelIndex firstAllocatedLevel,
71                                      wgpu::TextureDescriptor textureDescriptor)
72 {
73     mIntendedFormatID    = intendedFormatID;
74     mActualFormatID      = actualFormatID;
75     mTextureDescriptor   = textureDescriptor;
76     mFirstAllocatedLevel = firstAllocatedLevel;
77     mTexture             = device.CreateTexture(&mTextureDescriptor);
78     mInitialized         = true;
79 
80     return angle::Result::Continue;
81 }
82 
initExternal(angle::FormatID intendedFormatID,angle::FormatID actualFormatID,wgpu::Texture externalTexture)83 angle::Result ImageHelper::initExternal(angle::FormatID intendedFormatID,
84                                         angle::FormatID actualFormatID,
85                                         wgpu::Texture externalTexture)
86 {
87     mIntendedFormatID    = intendedFormatID;
88     mActualFormatID      = actualFormatID;
89     mTextureDescriptor   = TextureDescriptorFromTexture(externalTexture);
90     mFirstAllocatedLevel = gl::LevelIndex(0);
91     mTexture             = externalTexture;
92     mInitialized         = true;
93 
94     return angle::Result::Continue;
95 }
96 
flushStagedUpdates(ContextWgpu * contextWgpu)97 angle::Result ImageHelper::flushStagedUpdates(ContextWgpu *contextWgpu)
98 {
99     if (mSubresourceQueue.empty())
100     {
101         return angle::Result::Continue;
102     }
103     for (gl::LevelIndex currentMipLevel = mFirstAllocatedLevel;
104          currentMipLevel < mFirstAllocatedLevel + getLevelCount(); ++currentMipLevel)
105     {
106         ANGLE_TRY(flushSingleLevelUpdates(contextWgpu, currentMipLevel, nullptr, 0));
107     }
108     return angle::Result::Continue;
109 }
110 
flushSingleLevelUpdates(ContextWgpu * contextWgpu,gl::LevelIndex levelGL,ClearValuesArray * deferredClears,uint32_t deferredClearIndex)111 angle::Result ImageHelper::flushSingleLevelUpdates(ContextWgpu *contextWgpu,
112                                                    gl::LevelIndex levelGL,
113                                                    ClearValuesArray *deferredClears,
114                                                    uint32_t deferredClearIndex)
115 {
116     std::vector<SubresourceUpdate> *currentLevelQueue = getLevelUpdates(levelGL);
117     if (!currentLevelQueue || currentLevelQueue->empty())
118     {
119         return angle::Result::Continue;
120     }
121     wgpu::Device device          = contextWgpu->getDevice();
122     wgpu::Queue queue            = contextWgpu->getQueue();
123     wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
124     wgpu::ImageCopyTexture dst;
125     dst.texture = mTexture;
126     std::vector<wgpu::RenderPassColorAttachment> colorAttachments;
127     wgpu::TextureView textureView;
128     ANGLE_TRY(createTextureView(levelGL, 0, textureView));
129     bool updateDepth      = false;
130     bool updateStencil    = false;
131     float depthValue      = 1;
132     uint32_t stencilValue = 0;
133     for (const SubresourceUpdate &srcUpdate : *currentLevelQueue)
134     {
135         if (!isTextureLevelInAllocatedImage(srcUpdate.targetLevel))
136         {
137             continue;
138         }
139         switch (srcUpdate.updateSource)
140         {
141             case UpdateSource::Texture:
142                 dst.mipLevel = toWgpuLevel(srcUpdate.targetLevel).get();
143                 encoder.CopyBufferToTexture(&srcUpdate.textureData, &dst, &mTextureDescriptor.size);
144                 break;
145             case UpdateSource::Clear:
146                 if (deferredClears)
147                 {
148                     if (deferredClearIndex == kUnpackedDepthIndex)
149                     {
150                         if (srcUpdate.clearData.hasStencil)
151                         {
152                             deferredClears->store(kUnpackedStencilIndex,
153                                                   srcUpdate.clearData.clearValues);
154                         }
155                         if (!srcUpdate.clearData.hasDepth)
156                         {
157                             break;
158                         }
159                     }
160                     deferredClears->store(deferredClearIndex, srcUpdate.clearData.clearValues);
161                 }
162                 else
163                 {
164                     colorAttachments.push_back(CreateNewClearColorAttachment(
165                         srcUpdate.clearData.clearValues.clearColor,
166                         srcUpdate.clearData.clearValues.depthSlice, textureView));
167                     if (srcUpdate.clearData.hasDepth)
168                     {
169                         updateDepth = true;
170                         depthValue  = srcUpdate.clearData.clearValues.depthValue;
171                     }
172                     if (srcUpdate.clearData.hasStencil)
173                     {
174                         updateStencil = true;
175                         stencilValue  = srcUpdate.clearData.clearValues.stencilValue;
176                     }
177                 }
178                 break;
179         }
180     }
181     FramebufferWgpu *frameBuffer =
182         GetImplAs<FramebufferWgpu>(contextWgpu->getState().getDrawFramebuffer());
183 
184     if (!colorAttachments.empty())
185     {
186         frameBuffer->addNewColorAttachments(colorAttachments);
187     }
188     if (updateDepth || updateStencil)
189     {
190         frameBuffer->updateDepthStencilAttachment(CreateNewDepthStencilAttachment(
191             depthValue, stencilValue, textureView, updateDepth, updateStencil));
192     }
193     wgpu::CommandBuffer commandBuffer = encoder.Finish();
194     queue.Submit(1, &commandBuffer);
195     encoder = nullptr;
196     currentLevelQueue->clear();
197 
198     return angle::Result::Continue;
199 }
200 
createTextureDescriptor(wgpu::TextureUsage usage,wgpu::TextureDimension dimension,wgpu::Extent3D size,wgpu::TextureFormat format,std::uint32_t mipLevelCount,std::uint32_t sampleCount)201 wgpu::TextureDescriptor ImageHelper::createTextureDescriptor(wgpu::TextureUsage usage,
202                                                              wgpu::TextureDimension dimension,
203                                                              wgpu::Extent3D size,
204                                                              wgpu::TextureFormat format,
205                                                              std::uint32_t mipLevelCount,
206                                                              std::uint32_t sampleCount)
207 {
208     wgpu::TextureDescriptor textureDescriptor = {};
209     textureDescriptor.usage                   = usage;
210     textureDescriptor.dimension               = dimension;
211     textureDescriptor.size                    = size;
212     textureDescriptor.format                  = format;
213     textureDescriptor.mipLevelCount           = mipLevelCount;
214     textureDescriptor.sampleCount             = sampleCount;
215     textureDescriptor.viewFormatCount         = 0;
216     return textureDescriptor;
217 }
218 
stageTextureUpload(ContextWgpu * contextWgpu,const webgpu::Format & webgpuFormat,GLenum type,const gl::Extents & glExtents,GLuint inputRowPitch,GLuint inputDepthPitch,uint32_t outputRowPitch,uint32_t outputDepthPitch,uint32_t allocationSize,const gl::ImageIndex & index,const uint8_t * pixels)219 angle::Result ImageHelper::stageTextureUpload(ContextWgpu *contextWgpu,
220                                               const webgpu::Format &webgpuFormat,
221                                               GLenum type,
222                                               const gl::Extents &glExtents,
223                                               GLuint inputRowPitch,
224                                               GLuint inputDepthPitch,
225                                               uint32_t outputRowPitch,
226                                               uint32_t outputDepthPitch,
227                                               uint32_t allocationSize,
228                                               const gl::ImageIndex &index,
229                                               const uint8_t *pixels)
230 {
231     if (pixels == nullptr)
232     {
233         return angle::Result::Continue;
234     }
235     wgpu::Device device = contextWgpu->getDevice();
236     wgpu::Queue queue   = contextWgpu->getQueue();
237     gl::LevelIndex levelGL(index.getLevelIndex());
238     BufferHelper bufferHelper;
239     wgpu::BufferUsage usage = wgpu::BufferUsage::CopySrc | wgpu::BufferUsage::CopyDst;
240     ANGLE_TRY(bufferHelper.initBuffer(device, allocationSize, usage, MapAtCreation::Yes));
241     LoadImageFunctionInfo loadFunctionInfo = webgpuFormat.getTextureLoadFunction(type);
242     uint8_t *data                          = bufferHelper.getMapWritePointer(0, allocationSize);
243     loadFunctionInfo.loadFunction(contextWgpu->getImageLoadContext(), glExtents.width,
244                                   glExtents.height, glExtents.depth, pixels, inputRowPitch,
245                                   inputDepthPitch, data, outputRowPitch, outputDepthPitch);
246     ANGLE_TRY(bufferHelper.unmap());
247 
248     wgpu::TextureDataLayout textureDataLayout = {};
249     textureDataLayout.bytesPerRow             = outputRowPitch;
250     textureDataLayout.rowsPerImage            = outputDepthPitch;
251     wgpu::ImageCopyBuffer imageCopyBuffer;
252     imageCopyBuffer.layout = textureDataLayout;
253     imageCopyBuffer.buffer = bufferHelper.getBuffer();
254     appendSubresourceUpdate(levelGL,
255                             SubresourceUpdate(UpdateSource::Texture, levelGL, imageCopyBuffer));
256     return angle::Result::Continue;
257 }
258 
stageClear(gl::LevelIndex targetLevel,ClearValues clearValues,bool hasDepth,bool hasStencil)259 void ImageHelper::stageClear(gl::LevelIndex targetLevel,
260                              ClearValues clearValues,
261                              bool hasDepth,
262                              bool hasStencil)
263 {
264     appendSubresourceUpdate(targetLevel, SubresourceUpdate(UpdateSource::Clear, targetLevel,
265                                                            clearValues, hasDepth, hasStencil));
266 }
267 
removeStagedUpdates(gl::LevelIndex levelToRemove)268 void ImageHelper::removeStagedUpdates(gl::LevelIndex levelToRemove)
269 {
270     std::vector<SubresourceUpdate> *updateToClear = getLevelUpdates(levelToRemove);
271     if (updateToClear)
272     {
273         updateToClear->clear();
274     }
275 }
276 
resetImage()277 void ImageHelper::resetImage()
278 {
279     mTexture.Destroy();
280     mTextureDescriptor   = {};
281     mInitialized         = false;
282     mFirstAllocatedLevel = gl::LevelIndex(0);
283 }
284 // static
getReadPixelsParams(rx::ContextWgpu * contextWgpu,const gl::PixelPackState & packState,gl::Buffer * packBuffer,GLenum format,GLenum type,const gl::Rectangle & area,const gl::Rectangle & clippedArea,rx::PackPixelsParams * paramsOut,GLuint * skipBytesOut)285 angle::Result ImageHelper::getReadPixelsParams(rx::ContextWgpu *contextWgpu,
286                                                const gl::PixelPackState &packState,
287                                                gl::Buffer *packBuffer,
288                                                GLenum format,
289                                                GLenum type,
290                                                const gl::Rectangle &area,
291                                                const gl::Rectangle &clippedArea,
292                                                rx::PackPixelsParams *paramsOut,
293                                                GLuint *skipBytesOut)
294 {
295     const gl::InternalFormat &sizedFormatInfo = gl::GetInternalFormatInfo(format, type);
296 
297     GLuint outputPitch = 0;
298     ANGLE_CHECK_GL_MATH(contextWgpu,
299                         sizedFormatInfo.computeRowPitch(type, area.width, packState.alignment,
300                                                         packState.rowLength, &outputPitch));
301     ANGLE_CHECK_GL_MATH(contextWgpu, sizedFormatInfo.computeSkipBytes(
302                                          type, outputPitch, 0, packState, false, skipBytesOut));
303 
304     ANGLE_TRY(GetPackPixelsParams(sizedFormatInfo, outputPitch, packState, packBuffer, area,
305                                   clippedArea, paramsOut, skipBytesOut));
306     return angle::Result::Continue;
307 }
308 
readPixels(rx::ContextWgpu * contextWgpu,const gl::Rectangle & area,const rx::PackPixelsParams & packPixelsParams,void * pixels)309 angle::Result ImageHelper::readPixels(rx::ContextWgpu *contextWgpu,
310                                       const gl::Rectangle &area,
311                                       const rx::PackPixelsParams &packPixelsParams,
312                                       void *pixels)
313 {
314     if (mActualFormatID == angle::FormatID::NONE)
315     {
316         // Unimplemented texture format
317         UNIMPLEMENTED();
318         return angle::Result::Stop;
319     }
320 
321     wgpu::Device device          = contextWgpu->getDisplay()->getDevice();
322     wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
323     wgpu::Queue queue            = contextWgpu->getDisplay()->getQueue();
324 
325     const angle::Format &actualFormat = angle::Format::Get(mActualFormatID);
326     uint32_t textureBytesPerRow =
327         roundUp(actualFormat.pixelBytes * area.width, kCopyBufferAlignment);
328     wgpu::TextureDataLayout textureDataLayout;
329     textureDataLayout.bytesPerRow  = textureBytesPerRow;
330     textureDataLayout.rowsPerImage = area.height;
331 
332     size_t allocationSize = textureBytesPerRow * area.height;
333 
334     BufferHelper bufferHelper;
335     ANGLE_TRY(bufferHelper.initBuffer(device, allocationSize,
336                                       wgpu::BufferUsage::MapRead | wgpu::BufferUsage::CopyDst,
337                                       MapAtCreation::No));
338     wgpu::ImageCopyBuffer copyBuffer;
339     copyBuffer.buffer = bufferHelper.getBuffer();
340     copyBuffer.layout = textureDataLayout;
341 
342     wgpu::ImageCopyTexture copyTexture;
343     wgpu::Origin3D textureOrigin;
344     textureOrigin.x      = area.x;
345     textureOrigin.y      = area.y;
346     copyTexture.origin   = textureOrigin;
347     copyTexture.texture  = mTexture;
348     copyTexture.mipLevel = toWgpuLevel(mFirstAllocatedLevel).get();
349 
350     wgpu::Extent3D copySize;
351     copySize.width  = area.width;
352     copySize.height = area.height;
353     encoder.CopyTextureToBuffer(&copyTexture, &copyBuffer, &copySize);
354 
355     wgpu::CommandBuffer commandBuffer = encoder.Finish();
356     queue.Submit(1, &commandBuffer);
357     encoder = nullptr;
358 
359     ANGLE_TRY(bufferHelper.mapImmediate(contextWgpu, wgpu::MapMode::Read, 0, allocationSize));
360     const uint8_t *readPixelBuffer = bufferHelper.getMapReadPointer(0, allocationSize);
361     PackPixels(packPixelsParams, actualFormat, textureBytesPerRow, readPixelBuffer,
362                static_cast<uint8_t *>(pixels));
363     return angle::Result::Continue;
364 }
365 
createTextureView(gl::LevelIndex targetLevel,uint32_t layerIndex,wgpu::TextureView & textureViewOut)366 angle::Result ImageHelper::createTextureView(gl::LevelIndex targetLevel,
367                                              uint32_t layerIndex,
368                                              wgpu::TextureView &textureViewOut)
369 {
370     if (!isTextureLevelInAllocatedImage(targetLevel))
371     {
372         return angle::Result::Stop;
373     }
374     wgpu::TextureViewDescriptor textureViewDesc;
375     textureViewDesc.aspect          = wgpu::TextureAspect::All;
376     textureViewDesc.baseArrayLayer  = layerIndex;
377     textureViewDesc.arrayLayerCount = 1;
378     textureViewDesc.baseMipLevel    = toWgpuLevel(targetLevel).get();
379     textureViewDesc.mipLevelCount   = 1;
380     switch (mTextureDescriptor.dimension)
381     {
382         case wgpu::TextureDimension::Undefined:
383             textureViewDesc.dimension = wgpu::TextureViewDimension::Undefined;
384             break;
385         case wgpu::TextureDimension::e1D:
386             textureViewDesc.dimension = wgpu::TextureViewDimension::e1D;
387             break;
388         case wgpu::TextureDimension::e2D:
389             textureViewDesc.dimension = wgpu::TextureViewDimension::e2D;
390             break;
391         case wgpu::TextureDimension::e3D:
392             textureViewDesc.dimension = wgpu::TextureViewDimension::e3D;
393             break;
394     }
395     textureViewDesc.format = mTextureDescriptor.format;
396     textureViewOut         = mTexture.CreateView(&textureViewDesc);
397     return angle::Result::Continue;
398 }
399 
getLastAllocatedLevel()400 gl::LevelIndex ImageHelper::getLastAllocatedLevel()
401 {
402     return mFirstAllocatedLevel + mTextureDescriptor.mipLevelCount - 1;
403 }
404 
toWgpuLevel(gl::LevelIndex levelIndexGl) const405 LevelIndex ImageHelper::toWgpuLevel(gl::LevelIndex levelIndexGl) const
406 {
407     return gl_wgpu::getLevelIndex(levelIndexGl, mFirstAllocatedLevel);
408 }
409 
toGlLevel(LevelIndex levelIndexWgpu) const410 gl::LevelIndex ImageHelper::toGlLevel(LevelIndex levelIndexWgpu) const
411 {
412     return wgpu_gl::getLevelIndex(levelIndexWgpu, mFirstAllocatedLevel);
413 }
414 
isTextureLevelInAllocatedImage(gl::LevelIndex textureLevel)415 bool ImageHelper::isTextureLevelInAllocatedImage(gl::LevelIndex textureLevel)
416 {
417     if (!mInitialized || textureLevel < mFirstAllocatedLevel)
418     {
419         return false;
420     }
421     LevelIndex wgpuTextureLevel = toWgpuLevel(textureLevel);
422     return wgpuTextureLevel < LevelIndex(mTextureDescriptor.mipLevelCount);
423 }
424 
appendSubresourceUpdate(gl::LevelIndex level,SubresourceUpdate && update)425 void ImageHelper::appendSubresourceUpdate(gl::LevelIndex level, SubresourceUpdate &&update)
426 {
427     if (mSubresourceQueue.size() <= static_cast<size_t>(level.get()))
428     {
429         mSubresourceQueue.resize(level.get() + 1);
430     }
431     mSubresourceQueue[level.get()].emplace_back(std::move(update));
432 }
433 
getLevelUpdates(gl::LevelIndex level)434 std::vector<SubresourceUpdate> *ImageHelper::getLevelUpdates(gl::LevelIndex level)
435 {
436     return static_cast<size_t>(level.get()) < mSubresourceQueue.size()
437                ? &mSubresourceQueue[level.get()]
438                : nullptr;
439 }
440 
BufferHelper()441 BufferHelper::BufferHelper() {}
442 
~BufferHelper()443 BufferHelper::~BufferHelper() {}
444 
reset()445 void BufferHelper::reset()
446 {
447     mBuffer = nullptr;
448     mMappedState.reset();
449 }
450 
initBuffer(wgpu::Device device,size_t size,wgpu::BufferUsage usage,MapAtCreation mappedAtCreation)451 angle::Result BufferHelper::initBuffer(wgpu::Device device,
452                                        size_t size,
453                                        wgpu::BufferUsage usage,
454                                        MapAtCreation mappedAtCreation)
455 {
456     wgpu::BufferDescriptor descriptor;
457     descriptor.size             = roundUp(size, kBufferSizeAlignment);
458     descriptor.usage            = usage;
459     descriptor.mappedAtCreation = mappedAtCreation == MapAtCreation::Yes;
460 
461     mBuffer = device.CreateBuffer(&descriptor);
462 
463     if (mappedAtCreation == MapAtCreation::Yes)
464     {
465         mMappedState = {wgpu::MapMode::Read | wgpu::MapMode::Write, 0, size};
466     }
467     else
468     {
469         mMappedState.reset();
470     }
471 
472     mRequestedSize = size;
473 
474     return angle::Result::Continue;
475 }
476 
mapImmediate(ContextWgpu * context,wgpu::MapMode mode,size_t offset,size_t size)477 angle::Result BufferHelper::mapImmediate(ContextWgpu *context,
478                                          wgpu::MapMode mode,
479                                          size_t offset,
480                                          size_t size)
481 {
482     ASSERT(!mMappedState.has_value());
483 
484     WGPUBufferMapAsyncStatus mapResult = WGPUBufferMapAsyncStatus_Unknown;
485 
486     wgpu::BufferMapCallbackInfo callbackInfo;
487     callbackInfo.mode     = wgpu::CallbackMode::WaitAnyOnly;
488     callbackInfo.callback = [](WGPUBufferMapAsyncStatus status, void *userdata) {
489         *static_cast<WGPUBufferMapAsyncStatus *>(userdata) = status;
490     };
491     callbackInfo.userdata = &mapResult;
492 
493     wgpu::FutureWaitInfo waitInfo;
494     waitInfo.future = mBuffer.MapAsync(mode, GetSafeBufferMapOffset(offset),
495                                        GetSafeBufferMapSize(offset, size), callbackInfo);
496 
497     wgpu::Instance instance = context->getDisplay()->getInstance();
498     ANGLE_WGPU_TRY(context, instance.WaitAny(1, &waitInfo, -1));
499     ANGLE_WGPU_TRY(context, mapResult);
500 
501     ASSERT(waitInfo.completed);
502 
503     mMappedState = {mode, offset, size};
504 
505     return angle::Result::Continue;
506 }
507 
unmap()508 angle::Result BufferHelper::unmap()
509 {
510     ASSERT(mMappedState.has_value());
511     mBuffer.Unmap();
512     mMappedState.reset();
513     return angle::Result::Continue;
514 }
515 
getMapWritePointer(size_t offset,size_t size) const516 uint8_t *BufferHelper::getMapWritePointer(size_t offset, size_t size) const
517 {
518     ASSERT(mBuffer.GetMapState() == wgpu::BufferMapState::Mapped);
519     ASSERT(mMappedState.has_value());
520     ASSERT(mMappedState->offset <= offset);
521     ASSERT(mMappedState->offset + mMappedState->size >= offset + size);
522 
523     void *mapPtr =
524         mBuffer.GetMappedRange(GetSafeBufferMapOffset(offset), GetSafeBufferMapSize(offset, size));
525     ASSERT(mapPtr);
526 
527     return AdjustMapPointerForOffset(static_cast<uint8_t *>(mapPtr), offset);
528 }
529 
getMapReadPointer(size_t offset,size_t size) const530 const uint8_t *BufferHelper::getMapReadPointer(size_t offset, size_t size) const
531 {
532     ASSERT(mBuffer.GetMapState() == wgpu::BufferMapState::Mapped);
533     ASSERT(mMappedState.has_value());
534     ASSERT(mMappedState->offset <= offset);
535     ASSERT(mMappedState->offset + mMappedState->size >= offset + size);
536 
537     // GetConstMappedRange is used for reads whereas GetMappedRange is only used for writes.
538     const void *mapPtr = mBuffer.GetConstMappedRange(GetSafeBufferMapOffset(offset),
539                                                      GetSafeBufferMapSize(offset, size));
540     ASSERT(mapPtr);
541 
542     return AdjustMapPointerForOffset(static_cast<const uint8_t *>(mapPtr), offset);
543 }
544 
getMappedState() const545 const std::optional<BufferMapState> &BufferHelper::getMappedState() const
546 {
547     return mMappedState;
548 }
549 
canMapForRead() const550 bool BufferHelper::canMapForRead() const
551 {
552     return (mMappedState.has_value() && (mMappedState->mode & wgpu::MapMode::Read)) ||
553            (mBuffer && (mBuffer.GetUsage() & wgpu::BufferUsage::MapRead));
554 }
555 
canMapForWrite() const556 bool BufferHelper::canMapForWrite() const
557 {
558     return (mMappedState.has_value() && (mMappedState->mode & wgpu::MapMode::Write)) ||
559            (mBuffer && (mBuffer.GetUsage() & wgpu::BufferUsage::MapWrite));
560 }
561 
getBuffer()562 wgpu::Buffer &BufferHelper::getBuffer()
563 {
564     return mBuffer;
565 }
566 
requestedSize() const567 uint64_t BufferHelper::requestedSize() const
568 {
569     return mRequestedSize;
570 }
571 
actualSize() const572 uint64_t BufferHelper::actualSize() const
573 {
574     return mBuffer ? mBuffer.GetSize() : 0;
575 }
576 
577 }  // namespace webgpu
578 }  // namespace rx
579