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(©Texture, ©Buffer, ©Size);
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