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 // BufferWgpu.cpp:
7 // Implements the class methods for BufferWgpu.
8 //
9
10 #include "libANGLE/renderer/wgpu/BufferWgpu.h"
11
12 #include "common/debug.h"
13 #include "common/utilities.h"
14 #include "libANGLE/Context.h"
15 #include "libANGLE/angletypes.h"
16 #include "libANGLE/renderer/wgpu/ContextWgpu.h"
17 #include "libANGLE/renderer/wgpu/wgpu_utils.h"
18
19 namespace rx
20 {
21 namespace
22 {
23 // Based on a buffer binding target, compute the default wgpu usage flags. More can be added if the
24 // buffer is used in new ways.
GetDefaultWGPUBufferUsageForBinding(gl::BufferBinding binding)25 wgpu::BufferUsage GetDefaultWGPUBufferUsageForBinding(gl::BufferBinding binding)
26 {
27 switch (binding)
28 {
29 case gl::BufferBinding::Array:
30 case gl::BufferBinding::ElementArray:
31 return wgpu::BufferUsage::Vertex | wgpu::BufferUsage::Index |
32 wgpu::BufferUsage::CopySrc | wgpu::BufferUsage::CopyDst;
33
34 case gl::BufferBinding::Uniform:
35 return wgpu::BufferUsage::Uniform | wgpu::BufferUsage::CopySrc |
36 wgpu::BufferUsage::CopyDst;
37
38 case gl::BufferBinding::PixelPack:
39 return wgpu::BufferUsage::MapRead | wgpu::BufferUsage::CopyDst;
40
41 case gl::BufferBinding::PixelUnpack:
42 return wgpu::BufferUsage::MapWrite | wgpu::BufferUsage::CopySrc;
43
44 case gl::BufferBinding::CopyRead:
45 case gl::BufferBinding::CopyWrite:
46 case gl::BufferBinding::ShaderStorage:
47 case gl::BufferBinding::Texture:
48 case gl::BufferBinding::TransformFeedback:
49 case gl::BufferBinding::DispatchIndirect:
50 case gl::BufferBinding::DrawIndirect:
51 case gl::BufferBinding::AtomicCounter:
52 UNIMPLEMENTED();
53 return wgpu::BufferUsage::None;
54
55 default:
56 UNREACHABLE();
57 return wgpu::BufferUsage::None;
58 }
59 }
60
61 } // namespace
62
BufferWgpu(const gl::BufferState & state)63 BufferWgpu::BufferWgpu(const gl::BufferState &state) : BufferImpl(state) {}
64
~BufferWgpu()65 BufferWgpu::~BufferWgpu() {}
66
setData(const gl::Context * context,gl::BufferBinding target,const void * data,size_t size,gl::BufferUsage usage)67 angle::Result BufferWgpu::setData(const gl::Context *context,
68 gl::BufferBinding target,
69 const void *data,
70 size_t size,
71 gl::BufferUsage usage)
72 {
73 ContextWgpu *contextWgpu = webgpu::GetImpl(context);
74 wgpu::Device device = webgpu::GetDevice(context);
75
76 bool hasData = data && size > 0;
77
78 // Allocate a new buffer if the current one is invalid, the size is different, or the current
79 // buffer cannot be mapped for writing when data needs to be uploaded.
80 if (!mBuffer.valid() || mBuffer.size() != size || (hasData && !mBuffer.canMapForWrite()))
81 {
82 // Allocate a new buffer
83 ANGLE_TRY(mBuffer.initBuffer(device, size, GetDefaultWGPUBufferUsageForBinding(target),
84 webgpu::MapAtCreation::Yes));
85 }
86
87 if (hasData)
88 {
89 ASSERT(mBuffer.canMapForWrite());
90
91 if (!mBuffer.getMappedState().has_value())
92 {
93 ANGLE_TRY(mBuffer.mapImmediate(contextWgpu, wgpu::MapMode::Write, 0, size));
94 }
95
96 uint8_t *mappedData = mBuffer.getMapWritePointer(0, size);
97 memcpy(mappedData, data, size);
98 }
99
100 return angle::Result::Continue;
101 }
102
setSubData(const gl::Context * context,gl::BufferBinding target,const void * data,size_t size,size_t offset)103 angle::Result BufferWgpu::setSubData(const gl::Context *context,
104 gl::BufferBinding target,
105 const void *data,
106 size_t size,
107 size_t offset)
108 {
109 ContextWgpu *contextWgpu = webgpu::GetImpl(context);
110 wgpu::Device device = webgpu::GetDevice(context);
111
112 ASSERT(mBuffer.valid());
113 if (mBuffer.canMapForWrite())
114 {
115 if (!mBuffer.getMappedState().has_value())
116 {
117 ANGLE_TRY(mBuffer.mapImmediate(contextWgpu, wgpu::MapMode::Write, offset, size));
118 }
119
120 uint8_t *mappedData = mBuffer.getMapWritePointer(offset, size);
121 memcpy(mappedData, data, size);
122 }
123 else
124 {
125 // TODO: Upload into a staging buffer and copy to the destination buffer so that the copy
126 // happens at the right point in time for command buffer recording.
127 wgpu::Queue &queue = contextWgpu->getQueue();
128 queue.WriteBuffer(mBuffer.getBuffer(), offset, data, size);
129 }
130
131 return angle::Result::Continue;
132 }
133
copySubData(const gl::Context * context,BufferImpl * source,GLintptr sourceOffset,GLintptr destOffset,GLsizeiptr size)134 angle::Result BufferWgpu::copySubData(const gl::Context *context,
135 BufferImpl *source,
136 GLintptr sourceOffset,
137 GLintptr destOffset,
138 GLsizeiptr size)
139 {
140 return angle::Result::Continue;
141 }
142
map(const gl::Context * context,GLenum access,void ** mapPtr)143 angle::Result BufferWgpu::map(const gl::Context *context, GLenum access, void **mapPtr)
144 {
145 return angle::Result::Continue;
146 }
147
mapRange(const gl::Context * context,size_t offset,size_t length,GLbitfield access,void ** mapPtr)148 angle::Result BufferWgpu::mapRange(const gl::Context *context,
149 size_t offset,
150 size_t length,
151 GLbitfield access,
152 void **mapPtr)
153 {
154 return angle::Result::Continue;
155 }
156
unmap(const gl::Context * context,GLboolean * result)157 angle::Result BufferWgpu::unmap(const gl::Context *context, GLboolean *result)
158 {
159 *result = GL_TRUE;
160 return angle::Result::Continue;
161 }
162
getIndexRange(const gl::Context * context,gl::DrawElementsType type,size_t offset,size_t count,bool primitiveRestartEnabled,gl::IndexRange * outRange)163 angle::Result BufferWgpu::getIndexRange(const gl::Context *context,
164 gl::DrawElementsType type,
165 size_t offset,
166 size_t count,
167 bool primitiveRestartEnabled,
168 gl::IndexRange *outRange)
169 {
170 return angle::Result::Continue;
171 }
172
173 } // namespace rx
174