Cogs.Core
BuffersWebGPU.cpp
1#include "BuffersWebGPU.h"
2
3#include "FormatsWebGPU.h"
4#include "GraphicsDeviceWebGPU.h"
5
6#include "Foundation/Logging/Logger.h"
7
8namespace {
9 Cogs::Logging::Log logger = Cogs::Logging::getLogger("BuffersWebGPU");
10}
11
12namespace Cogs{
13
14 void BufferWebGPU::CreateInstance(GraphicsDeviceWebGPU *graphicsDevice)
15 {
16 WGPUBufferDescriptor desc = {};
17 desc.label = nullptr;
18 if(accessMode&AccessMode::Read){
19 desc.usage |= WGPUBufferUsage_MapRead;
20 desc.usage |= WGPUBufferUsage_CopyDst;
21 }
22 else{
23 desc.usage |= WGPUBufferUsage_CopyDst;
24 }
25
26 if((bindFlags&BindFlags::VertexBuffer) != 0)
27 desc.usage |= WGPUBufferUsage_Vertex;
28 if((bindFlags&BindFlags::IndexBuffer) != 0)
29 desc.usage |= WGPUBufferUsage_Index;
30 if((bindFlags&BindFlags::ConstantBuffer) != 0)
31 desc.usage |= WGPUBufferUsage_Uniform;
32 if((bindFlags&BindFlags::ShaderResource) != 0)
33 desc.usage |= WGPUBufferUsage_Storage;
34 if((bindFlags&BindFlags::RawBuffer) != 0)
35 desc.usage |= WGPUBufferUsage_Storage;
36 if((bindFlags&BindFlags::StructuredBuffer) != 0)
37 desc.usage |= WGPUBufferUsage_Storage;
39 desc.usage |= WGPUBufferUsage_Storage;
40
41 desc.size = size;
42 desc.mappedAtCreation = false;
43
44 buffer = wgpuDeviceCreateBuffer(graphicsDevice->device, &desc);
45 if(!is_read_buffer){
46 alias.push_back(buffer);
47 }
48 }
49 void BufferWebGPU::NextInstance(GraphicsDeviceWebGPU *graphicsDevice)
50 {
51 uint32_t idx = alias_idx;
52 alias_idx++;
53 if(idx >= alias.size()){
54 CreateInstance(graphicsDevice);
55 assert(idx+1 == alias.size());
56 }
57 else{
58 buffer = alias[idx];
59 }
60 }
61 void BufferWebGPU::ResetInstance()
62 {
63 // TODO: this is an oppertunity to free unused aliases and save memory
64 alias_idx = 0;
65 }
66
67 void BuffersWebGPU::initialize(GraphicsDeviceWebGPU *device)
68 {
69 graphicsDevice = device;
70 }
71 void BuffersWebGPU::resetInstances()
72 {
73 for(BufferWebGPU &buffer : buffers){
74 buffer.ResetInstance();
75 }
76 }
77
78 VertexBufferHandle BuffersWebGPU::loadVertexBuffer(const void* vertexData, const size_t count, const VertexFormat& vertexFormat)
79 {
80 const uint32_t stride = getSize(vertexFormat);
81 const size_t size = count * stride;
82 auto handle = loadBuffer(vertexData, size, Usage::Dynamic, AccessMode::None, BindFlags::VertexBuffer);
83 return handle;
84 }
85
86 VertexBufferHandle BuffersWebGPU::loadVertexBuffer(const void* vertexData, const size_t count, VertexFormatHandle vertexFormatHandle)
87 {
88 return loadVertexBuffer(vertexData, count, *VertexFormats::getVertexFormat(vertexFormatHandle));
89 }
90
92 {
93 buffers.removeResource(handle);
94 }
95
96 IndexBufferHandle BuffersWebGPU::loadIndexBuffer(const void* indexData, const size_t count, const size_t indexSize)
97 {
98 const size_t size = count * indexSize;
99 auto handle = loadBuffer(indexData, size, Usage::Dynamic, AccessMode::None, BindFlags::IndexBuffer);
100 return handle;
101 }
102
104 {
105 buffers.removeResource(handle);
106 }
107
108 InputLayoutHandle BuffersWebGPU::loadInputLayout(const VertexFormatHandle* vertexFormats, const size_t count, EffectHandle effectHandle)
109 {
110 size_t attribute_count = 0;
111 for(size_t i=0; i<count; i++){
112 const VertexFormat *vtx_format = getVertexFormat(vertexFormats[i]);
113 for(size_t j=0; j<vtx_format->elements.size(); j++){
114 const VertexElement &element = vtx_format->elements[j];
115 if(element.format == DataFormat::MAT4X4_FLOAT){
116 attribute_count += 4;
117 }
118 else{
119 attribute_count += 1;
120 }
121 }
122 }
123
124 InputLayoutWebGPU input_layout = {};
125 input_layout.vertex_attributes.resize(attribute_count);
126 input_layout.vertex_buffer_layout.resize(count);
127
128 size_t attribute_offset = 0;
129 for(size_t i=0; i<count; i++){
130 const VertexFormat *vtx_format = getVertexFormat(vertexFormats[i]);
131 WGPUVertexBufferLayout &vtx_layout = input_layout.vertex_buffer_layout[i];
132 vtx_layout.arrayStride = getSize(*vtx_format);
133 if(vtx_format->elements[0].inputType == InputType::VertexData){
134 vtx_layout.stepMode = WGPUVertexStepMode_Vertex;
135 }
136 else if(vtx_format->elements[0].inputType == InputType::InstanceData){
137 vtx_layout.stepMode = WGPUVertexStepMode_Instance;
138 }
139 else{
140 // vtx_layout.stepMode = WGPUVertexStepMode_VertexBufferNotUsed;
141 assert(false);
142 }
143 vtx_layout.attributeCount = 0;
144 vtx_layout.attributes = vtx_format->elements.size() ? &input_layout.vertex_attributes[attribute_offset] : nullptr;
145 for(size_t j=0; j<vtx_format->elements.size(); j++){
146 const VertexElement &element = vtx_format->elements[j];
147 if(vtx_layout.stepMode == WGPUVertexStepMode_Vertex){
148 assert(element.inputType == InputType::VertexData);
149 assert(element.instanceStep == 0);
150 }
151 else if(vtx_layout.stepMode == WGPUVertexStepMode_Instance){
152 assert(element.inputType == InputType::InstanceData);
153 assert(element.instanceStep == 1);
154 }
155 else{
156 assert(false);
157 }
158 EffectWebGPU& effect = graphicsDevice->effects.effects[effectHandle];
159
160 uint32_t attribute_location = std::numeric_limits<uint32_t>::max();
161 SemanticSlotBinding semantic = {};
162 semantic.format = WGPUVertexFormat_Undefined;
163 for (size_t s = 0; s < effect.num_attribs; s++) {
164 const SemanticSlotBinding& sem = effect.semanticSlotBindings[s];
165 if (sem.semantic == size_t(element.semantic) && sem.slot == element.semanticIndex) {
166 attribute_location = sem.binding;
167 semantic = sem;
168 break;
169 }
170 }
171 if (attribute_location == std::numeric_limits<uint32_t>::max()) {
172 LOG_WARNING(logger, "Vertex attribute semantic %d, slot %d not used in shader", (int)element.semantic, element.semanticIndex);
173 }
174 if(element.format == DataFormat::MAT4X4_FLOAT){
175 for(int k=0; k<4; k++){
176 WGPUVertexAttribute &att = input_layout.vertex_attributes[attribute_offset++];
177 att.format = WGPUVertexFormat_Float32x4;
178 att.offset = element.offset + sizeof(float)*4*k;
179 att.shaderLocation = attribute_location+k;
180 vtx_layout.attributeCount++;
181 }
182 }
183 else{
184 WGPUVertexAttribute &att = input_layout.vertex_attributes[attribute_offset++];
185 att.format = VertexFormatsWebGPU[(size_t)element.format];
186 if (semantic.format != VertexFormatsWebGPU[(size_t)element.format]) {
187 LOG_WARNING(logger, "Inconsisten vertex attribute format");
188 }
189 assert(att.format != WGPUVertexFormat_Undefined); // Vertex format not supported
190 att.offset = element.offset;
191 att.shaderLocation = attribute_location;
192 vtx_layout.attributeCount++;
193 }
194 }
195 }
196 assert(attribute_offset == input_layout.vertex_attributes.size());
197 return inputLayouts.addResource(std::move(input_layout));
198 }
199
201 {
202 inputLayouts.removeResource(inputLayoutHandle);
203 }
204
205 BufferHandle BuffersWebGPU::loadBuffer(const void* data, const size_t size, Usage::EUsage /*usage*/, uint32_t accessMode, uint32_t bindFlags, uint32_t /*stride*/)
206 {
207 assert((bindFlags&BindFlags::StreamOutBuffer) == 0);
208 assert((accessMode&AccessMode::ReadWrite) != AccessMode::ReadWrite); // Not available for WebGPU
209
210 BufferWebGPU buffer = {};
211 buffer.size = size;
212 buffer.accessMode = accessMode;
213 buffer.bindFlags = bindFlags;
214
215 if(accessMode&AccessMode::Read){
216 buffer.is_read_buffer = true;
217 assert(bindFlags == 0);
218 // Round up
219 size_t granularity = 256;
220 if(buffer.size%granularity != 0)
221 buffer.size += granularity-buffer.size%granularity;
222 }
223 else{
224 // Round up
225 size_t granularity = 16;
226 if (buffer.size % granularity != 0)
227 buffer.size += granularity - buffer.size % granularity;
228 }
229
230 buffer.CreateInstance(graphicsDevice);
231 if(data){
232 wgpuQueueWriteBuffer(graphicsDevice->queue, buffer.buffer, 0, data, buffer.size);
233 }
234
235 return this->buffers.addResource(std::move(buffer));
236 }
237
239 {
240 if(!buffers[handle].is_read_buffer){
241 wgpuBufferRelease(buffers[handle].buffer);
242 }
243 else{
244 for(WGPUBuffer &buffer: buffers[handle].alias){
245 wgpuBufferRelease(buffer);
246 }
247 }
248 buffers.removeResource(handle);
249 }
250
252 {
253 return static_cast<void*>(buffers[handle].buffer);
254 }
255
256}
virtual IndexBufferHandle loadIndexBuffer(const void *, const size_t, const size_t) override
Loads a new index buffer and populates it with the given indexData.
virtual VertexBufferHandle loadVertexBuffer(const void *, const size_t, const VertexFormat &vertexFormat) override
Loads a new vertex buffer and populates it with the given data.
virtual void releaseVertexBuffer(VertexBufferHandle vertexBufferHandle) override
Release the vertex buffer with the given handle.
virtual InputLayoutHandle loadInputLayout(const VertexFormatHandle *vertexFormats, const size_t count, EffectHandle effectHandle) override
Loads a new input layout to map vertex flow between vertex buffers with the given vertexFormats to ef...
virtual BufferHandle loadBuffer(const void *, const size_t, Usage::EUsage, uint32_t, uint32_t, uint32_t=0) override
Loads a new buffer using the given data to populate the buffer.
virtual void * getNativeHandle(BufferHandle bufferHandle) override
Get the device-specific handle (D3D buffer pointer, OpenGL buffer ID etc) associated with the given b...
virtual void releaseBuffer(BufferHandle bufferHandle) override
Releases the buffer with the given bufferHandle.
virtual void releaseInputLayout(InputLayoutHandle inputLayoutHandle) override
Releases the input layout with the given inputLayoutHandle.
virtual void releaseIndexBuffer(IndexBufferHandle indexBufferHandle) override
Releases the index buffer with the given handle.
Log implementation class.
Definition: LogManager.h:139
constexpr Log getLogger(const char(&name)[LEN]) noexcept
Definition: LogManager.h:180
Contains all Cogs related functionality.
Definition: FieldSetter.h:23
@ InstanceData
Per instance data.
@ VertexData
Per vertex data.
@ Read
The buffer can be mapped and read from by the CPU after creation.
Definition: Flags.h:48
@ None
The buffer can not be either read from or written to by the CPU after creation.
Definition: Flags.h:46
@ ConstantBuffer
The buffer can be bound as input to effects as a constant buffer.
Definition: Flags.h:72
@ StructuredBufferWithCounter
The buffer can be bound as a structured buffer and read or written from shaders, with an additional a...
Definition: Flags.h:82
@ StreamOutBuffer
The buffer can be bound as stream output to receive transform feedback results.
Definition: Flags.h:74
@ VertexBuffer
The buffer can be bound as input to the vertex shader stage as a vertex buffer.
Definition: Flags.h:68
@ RawBuffer
The buffer can be bound as a byte address buffer and read or written from shaders.
Definition: Flags.h:78
@ IndexBuffer
The buffer can be bound as input to the vertex shader stage as an index buffer.
Definition: Flags.h:70
@ ShaderResource
The buffer can be bound as a shader resource and read from shaders.
Definition: Flags.h:76
@ StructuredBuffer
The buffer can be bound as a structured buffer and read or written from shaders.
Definition: Flags.h:80
EUsage
Usage enumeration.
Definition: Flags.h:24
@ Dynamic
Buffer will be loaded and modified with some frequency.
Definition: Flags.h:30
Vertex element structure used to describe a single data element in a vertex for the input assembler.
Definition: VertexFormat.h:38
InputType inputType
Input type of the element, vertex or instance data.
Definition: VertexFormat.h:43
DataFormat format
Format of the element.
Definition: VertexFormat.h:40
uint16_t offset
Offset in bytes from the vertex position in memory.
Definition: VertexFormat.h:39
uint16_t semanticIndex
Index for the semantic mapping.
Definition: VertexFormat.h:42
ElementSemantic semantic
Semantic mapping of the element (position, normal, etc...).
Definition: VertexFormat.h:41
uint16_t instanceStep
Instance step factor.
Definition: VertexFormat.h:44
Vertex format structure used to describe a single vertex for the input assembler.
Definition: VertexFormat.h:60
std::vector< VertexElement > elements
Vector containing all vertex elements of this format.
Definition: VertexFormat.h:62