| // |
| // Copyright 2024 The ANGLE Project Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| // |
| // BufferWgpu.cpp: |
| // Implements the class methods for BufferWgpu. |
| // |
| |
| #include "libANGLE/renderer/wgpu/BufferWgpu.h" |
| |
| #include "common/debug.h" |
| #include "common/mathutil.h" |
| #include "common/utilities.h" |
| #include "libANGLE/Context.h" |
| #include "libANGLE/angletypes.h" |
| #include "libANGLE/renderer/wgpu/ContextWgpu.h" |
| #include "libANGLE/renderer/wgpu/wgpu_utils.h" |
| |
| namespace rx |
| { |
| namespace |
| { |
| // Based on a buffer binding target, compute the default wgpu usage flags. More can be added if the |
| // buffer is used in new ways. |
| wgpu::BufferUsage GetDefaultWGPUBufferUsageForBinding(gl::BufferBinding binding) |
| { |
| switch (binding) |
| { |
| case gl::BufferBinding::Array: |
| case gl::BufferBinding::ElementArray: |
| return wgpu::BufferUsage::Vertex | wgpu::BufferUsage::Index | |
| wgpu::BufferUsage::CopySrc | wgpu::BufferUsage::CopyDst; |
| |
| case gl::BufferBinding::Uniform: |
| return wgpu::BufferUsage::Uniform | wgpu::BufferUsage::CopySrc | |
| wgpu::BufferUsage::CopyDst; |
| |
| case gl::BufferBinding::PixelPack: |
| return wgpu::BufferUsage::MapRead | wgpu::BufferUsage::CopyDst; |
| |
| case gl::BufferBinding::PixelUnpack: |
| return wgpu::BufferUsage::MapWrite | wgpu::BufferUsage::CopySrc; |
| |
| case gl::BufferBinding::CopyRead: |
| case gl::BufferBinding::CopyWrite: |
| case gl::BufferBinding::ShaderStorage: |
| case gl::BufferBinding::Texture: |
| case gl::BufferBinding::TransformFeedback: |
| case gl::BufferBinding::DispatchIndirect: |
| case gl::BufferBinding::DrawIndirect: |
| case gl::BufferBinding::AtomicCounter: |
| UNIMPLEMENTED(); |
| return wgpu::BufferUsage::None; |
| |
| default: |
| UNREACHABLE(); |
| return wgpu::BufferUsage::None; |
| } |
| } |
| |
| } // namespace |
| |
| BufferWgpu::BufferWgpu(const gl::BufferState &state) : BufferImpl(state) {} |
| |
| BufferWgpu::~BufferWgpu() {} |
| |
| angle::Result BufferWgpu::setData(const gl::Context *context, |
| gl::BufferBinding target, |
| const void *data, |
| size_t size, |
| gl::BufferUsage usage) |
| { |
| ContextWgpu *contextWgpu = webgpu::GetImpl(context); |
| wgpu::Device device = webgpu::GetDevice(context); |
| |
| bool hasData = data && size > 0; |
| |
| // Allocate a new buffer if the current one is invalid, the size is different, or the current |
| // buffer cannot be mapped for writing when data needs to be uploaded. |
| if (!mBuffer.valid() || mBuffer.requestedSize() != size || |
| (hasData && !mBuffer.canMapForWrite())) |
| { |
| // Allocate a new buffer |
| ANGLE_TRY(mBuffer.initBuffer(device, size, GetDefaultWGPUBufferUsageForBinding(target), |
| webgpu::MapAtCreation::Yes)); |
| } |
| |
| if (hasData) |
| { |
| ASSERT(mBuffer.canMapForWrite()); |
| |
| if (!mBuffer.getMappedState().has_value()) |
| { |
| ANGLE_TRY(mBuffer.mapImmediate(contextWgpu, wgpu::MapMode::Write, 0, size)); |
| } |
| |
| uint8_t *mappedData = mBuffer.getMapWritePointer(0, size); |
| memcpy(mappedData, data, size); |
| } |
| |
| return angle::Result::Continue; |
| } |
| |
| angle::Result BufferWgpu::setSubData(const gl::Context *context, |
| gl::BufferBinding target, |
| const void *data, |
| size_t size, |
| size_t offset) |
| { |
| ContextWgpu *contextWgpu = webgpu::GetImpl(context); |
| wgpu::Device device = webgpu::GetDevice(context); |
| |
| ASSERT(mBuffer.valid()); |
| if (mBuffer.canMapForWrite()) |
| { |
| if (!mBuffer.getMappedState().has_value()) |
| { |
| ANGLE_TRY(mBuffer.mapImmediate(contextWgpu, wgpu::MapMode::Write, offset, size)); |
| } |
| |
| uint8_t *mappedData = mBuffer.getMapWritePointer(offset, size); |
| memcpy(mappedData, data, size); |
| } |
| else |
| { |
| // TODO: Upload into a staging buffer and copy to the destination buffer so that the copy |
| // happens at the right point in time for command buffer recording. |
| wgpu::Queue &queue = contextWgpu->getQueue(); |
| queue.WriteBuffer(mBuffer.getBuffer(), offset, data, size); |
| } |
| |
| return angle::Result::Continue; |
| } |
| |
| angle::Result BufferWgpu::copySubData(const gl::Context *context, |
| BufferImpl *source, |
| GLintptr sourceOffset, |
| GLintptr destOffset, |
| GLsizeiptr size) |
| { |
| return angle::Result::Continue; |
| } |
| |
| angle::Result BufferWgpu::map(const gl::Context *context, GLenum access, void **mapPtr) |
| { |
| return angle::Result::Continue; |
| } |
| |
| angle::Result BufferWgpu::mapRange(const gl::Context *context, |
| size_t offset, |
| size_t length, |
| GLbitfield access, |
| void **mapPtr) |
| { |
| return angle::Result::Continue; |
| } |
| |
| angle::Result BufferWgpu::unmap(const gl::Context *context, GLboolean *result) |
| { |
| *result = GL_TRUE; |
| return angle::Result::Continue; |
| } |
| |
| angle::Result BufferWgpu::getIndexRange(const gl::Context *context, |
| gl::DrawElementsType type, |
| size_t offset, |
| size_t count, |
| bool primitiveRestartEnabled, |
| gl::IndexRange *outRange) |
| { |
| ContextWgpu *contextWgpu = webgpu::GetImpl(context); |
| |
| const GLuint typeBytes = gl::GetDrawElementsTypeSize(type); |
| |
| webgpu::BufferReadback readback; |
| ANGLE_TRY(mBuffer.readDataImmediate(contextWgpu, offset, count * typeBytes, |
| webgpu::RenderPassClosureReason::IndexRangeReadback, |
| &readback)); |
| *outRange = gl::ComputeIndexRange(type, readback.data, count, primitiveRestartEnabled); |
| |
| return angle::Result::Continue; |
| } |
| |
| } // namespace rx |