Cogs.Core
TexturesWebGPU.cpp
1#include "TexturesWebGPU.h"
2
3#include "FormatsWebGPU.h"
4#include "GraphicsDeviceWebGPU.h"
5#include "Foundation/Logging/Logger.h"
6
7#include "Foundation/StringView.h"
8
9#include <glm/gtc/color_space.hpp>
10#include <glm/detail/func_packing.inl>
11
12namespace{
13 Cogs::Logging::Log logger = Cogs::Logging::getLogger("TexturesWebGPU");
14 WGPUCompareFunction wgpu(Cogs::SamplerState::ComparisonFunction cmp)
15 {
16 switch(cmp){
17 case Cogs::SamplerState::ComparisonFunction::Never:
18 return WGPUCompareFunction_Never;
19 case Cogs::SamplerState::ComparisonFunction::Less:
20 return WGPUCompareFunction_Less;
21 case Cogs::SamplerState::ComparisonFunction::Equal:
22 return WGPUCompareFunction_Equal;
23 case Cogs::SamplerState::ComparisonFunction::LessEqual:
24 return WGPUCompareFunction_LessEqual;
25 case Cogs::SamplerState::ComparisonFunction::Greater:
26 return WGPUCompareFunction_Greater;
27 case Cogs::SamplerState::ComparisonFunction::NotEqual:
28 return WGPUCompareFunction_NotEqual;
29 case Cogs::SamplerState::ComparisonFunction::GreaterEqual:
30 return WGPUCompareFunction_GreaterEqual;
31 case Cogs::SamplerState::ComparisonFunction::Always:
32 return WGPUCompareFunction_Always;
33 case Cogs::SamplerState::ComparisonFunction::ComparisonFunction_Size:
34 break;
35 }
36 assert(false);
37 return WGPUCompareFunction_Undefined;
38 }
39
40 WGPUAddressMode wgpu(Cogs::SamplerState::AddressMode address_mode)
41 {
42 switch(address_mode){
44 return WGPUAddressMode_ClampToEdge;
46 return WGPUAddressMode_Repeat;
48 return WGPUAddressMode_MirrorRepeat;
50 LOG_WARNING_ONCE(logger, "WebGPU backend does not support SamplerState::AddressMode::Border.");
51 return WGPUAddressMode_ClampToEdge;
52 case Cogs::SamplerState::AddressMode::AddressMode_Size:
53 break;
54 }
55 assert(false);
56 return WGPUAddressMode_Repeat;
57 }
58}
59
60namespace Cogs{
61
62 void TexturesWebGPU::initialize(class GraphicsDeviceWebGPU *device)
63 {
64 graphicsDevice = device;
65 }
66
68 {
69 TextureWebGPU &texture = textures[handle];
70 wgpuTextureSetLabel(texture.texture, {name.data(), WGPU_STRLEN});
71 }
72
73 static void writeMipLevelToGPU(GraphicsDeviceWebGPU *graphicsDevice, WGPUTexture *destinationTexture, void *data, uint32_t cubeFace, uint32_t arrayLayer, uint32_t mipLevel, Cogs::TextureExtent textureExtent, size_t levelSize, uint32_t bytesPerPixel)
74 {
75 WGPUTexelCopyBufferLayout layout = {};
76 layout.offset = 0;
77 layout.bytesPerRow = bytesPerPixel * textureExtent.width;
78 layout.rowsPerImage = textureExtent.height;
79
80 WGPUTexelCopyTextureInfo destination = {};
81 destination.texture = *destinationTexture;
82 destination.aspect = WGPUTextureAspect_All;
83 destination.origin = { 0, 0, static_cast<uint32_t>(arrayLayer + cubeFace) };
84 destination.mipLevel = static_cast<uint32_t>(mipLevel);
85 WGPUExtent3D sizeExtent = { textureExtent.width, textureExtent.height, textureExtent.depth };
86 wgpuQueueWriteTexture(graphicsDevice->queue, &destination, data, levelSize, &layout, &sizeExtent);
87 }
88
89 template <typename T>
90 static void convertMiplevelDataToFloatData(float *out, T *data, size_t nPixels, uint32_t channels, bool isSigned, bool isFloat, bool isHalfFloat, bool isSRGB, bool hasAlpha)
91 {
92 float valRange = std::powf(2, 8 * sizeof(T)) - 1.0f;
93
94 memcpy(out, data, static_cast<size_t>(isFloat) * nPixels * channels * sizeof(float));
95
96 for(size_t pixel = 0; pixel < nPixels * static_cast<size_t>(!isFloat); pixel++) {
97 for(size_t channel = 0; channel < channels; channel++) {
98 T channelData = data[(pixel * channels) + channel];
99 size_t isSignBitSet = static_cast<size_t>(isSigned) & (static_cast<size_t>(channelData) >> ((sizeof(T) * 8) - 1));
100
101
102 T channelDataShifted = channelData + static_cast<T>((static_cast<size_t>(!isHalfFloat) * isSignBitSet * (static_cast<size_t>(valRange) >> 1)));
103
104 glm::vec2 halfFloatToFloatVec = glm::unpackHalf2x16(static_cast<uint32_t>(channelDataShifted));
105 float halfFloatToFloat = halfFloatToFloatVec.x;
106
107 float channelDataAsFloat = (static_cast<size_t>(!isHalfFloat) * static_cast<float>(channelDataShifted) / valRange) + (static_cast<float>(static_cast<size_t>(isHalfFloat)) * halfFloatToFloat);
108 channelDataAsFloat -= 1.0f * isSignBitSet * static_cast<size_t>(!isHalfFloat);
109
110 size_t isNotAlphaChannel = static_cast<size_t>(!hasAlpha) + (static_cast<size_t>(hasAlpha) * static_cast<size_t>((channel < (channels-1))));
111 size_t isAlphaChannel = static_cast<size_t>(hasAlpha) * static_cast<size_t>((channel == (channels-1)));
112
113 glm::vec3 channelDataVecGamma = glm::convertSRGBToLinear(glm::vec3(channelDataAsFloat, 0.0f, 0.0f));
114 float channelDataGamma = channelDataVecGamma.r;
115
116 float dataSRGBToLinear = static_cast<size_t>(isSRGB) * ((isNotAlphaChannel * channelDataGamma) + (isAlphaChannel * channelDataAsFloat));
117
118 channelDataAsFloat = (static_cast<size_t>(!isSRGB) * channelDataAsFloat) + (static_cast<size_t>(isSRGB) * dataSRGBToLinear);
119
120 out[(pixel * channels) + channel] = channelDataAsFloat;
121 }
122 }
123 }
124
125 template <typename T>
126 static void nextMiplevelFromFloatData(T *nativeTypeOut, float *data, Cogs::TextureExtent textureExtent, uint32_t channels, bool isSigned, bool isFloat, bool isHalfFloat, bool isSRGB, bool hasAlpha)
127 {
128 float valRange = std::powf(2, 8 * sizeof(T)) - 1.0f;
129
130 for (size_t y = 0; y < textureExtent.height; y++)
131 {
132 for (size_t x = 0; x < textureExtent.width; x++)
133 {
134 float *writeFloat = &data[channels * (y * textureExtent.width + x)];
135 T *write = &nativeTypeOut[channels * (y * textureExtent.width + x)];
136
137 float *s0 = &data[channels * ((2 * y + 0) * (2 * textureExtent.width) + (2 * x + 0))];
138 float *s1 = &data[channels * ((2 * y + 0) * (2 * textureExtent.width) + (2 * x + 1))];
139 float *s2 = &data[channels * ((2 * y + 1) * (2 * textureExtent.width) + (2 * x + 0))];
140 float *s3 = &data[channels * ((2 * y + 1) * (2 * textureExtent.width) + (2 * x + 1))];
141
142 for (size_t channel = 0; channel < channels; channel++) {
143 float channelDataFloat = (s0[channel] + s1[channel] + s2[channel] + s3[channel]) / 4.0f;
144
145 writeFloat[channel] = channelDataFloat;
146
147 size_t isSignBitSet = static_cast<size_t>(isSigned) & (static_cast<size_t>(channelDataFloat) >> ((sizeof(T) * 8) - 1));
148
149 float channelDataFloatShifted = channelDataFloat + 1.0f * static_cast<float>(static_cast<size_t>(!isHalfFloat)) * static_cast<float>(isSignBitSet) * static_cast<float>(static_cast<size_t>(!isFloat));
150
151 size_t isNotAlphaChannel = static_cast<size_t>(!hasAlpha) + (static_cast<size_t>(hasAlpha) * static_cast<size_t>((channel < (channels-1))));
152 size_t isAlphaChannel = static_cast<size_t>(hasAlpha) * static_cast<size_t>((channel == (channels-1)));
153
154 glm::vec3 channelDataVecGamma = glm::convertLinearToSRGB(glm::vec3(channelDataFloatShifted, 0.0f, 0.0f));
155 float channelDataGamma = channelDataVecGamma.r;
156
157 float channelDataLinearToSRGB = static_cast<size_t>(isSRGB) * ((isNotAlphaChannel * channelDataGamma) + (isAlphaChannel * channelDataFloatShifted));
158
159 channelDataFloatShifted = (static_cast<size_t>(!isSRGB) * channelDataFloatShifted) + (static_cast<size_t>(isSRGB) * channelDataLinearToSRGB);
160
161 uint16_t floatToHalfFloat = static_cast<uint16_t>(glm::packHalf2x16(glm::vec2(channelDataFloat, 0.0f)));
162
163 T channelData = static_cast<T>((static_cast<size_t>(!isFloat) * static_cast<size_t>(!isHalfFloat) * channelDataFloatShifted * valRange) + (static_cast<size_t>(isFloat) * channelDataFloat) + (static_cast<size_t>(isHalfFloat) * floatToHalfFloat));
164
165 write[channel] = channelData;
166 }
167 }
168 }
169 }
170
171 template <typename T>
172 static void generateMipmapsInternal(GraphicsDeviceWebGPU *graphicsDevice, WGPUTexture *destinationTexture, const TextureData *data, uint32_t faces, uint32_t layers, uint32_t levels, uint32_t bytesPerChannel, uint32_t channels, bool isSigned, bool isFloat, bool isHalfFloat, bool isSRGB, bool hasAlpha)
173 {
174 uint32_t bytesPerPixel = bytesPerChannel * channels;
175 size_t nPixels = data->getLevelSize(0) / bytesPerPixel;
176
177 size_t levelSize = data->getLevelSize(0);
178
179 std::vector<T> currLevelData(levelSize);
180 std::vector<T> prevLevelData(nPixels * channels);
181 std::vector<float> prevLevelDataFloat(nPixels * channels);
182
183 Cogs::TextureExtent textureExtent = {};
184
185 for (uint32_t f = 0; f < faces; ++f) { // Faces
186 for (uint32_t a = 0; a < layers; ++a) { // Array layers
187 textureExtent = data->getExtent(0);
188
189 T* tmpLevelData = reinterpret_cast<T*>(const_cast<void*>(data->getData(a, f, 0)));
190 memcpy(prevLevelData.data(), tmpLevelData, levelSize);
191
192 writeMipLevelToGPU(graphicsDevice, destinationTexture, prevLevelData.data(), f, a, 0, textureExtent, levelSize, bytesPerPixel);
193
194 convertMiplevelDataToFloatData<T>(prevLevelDataFloat.data(), prevLevelData.data(), nPixels, channels, isSigned, isFloat, isHalfFloat, isSRGB, hasAlpha);
195
196 for (uint32_t m = 1; m < levels; ++m) { // Miplevels
197 textureExtent = data->getExtent(m);
198 size_t currentLevelSize = data->getLevelSize(m);
199
200 nextMiplevelFromFloatData(currLevelData.data(), prevLevelDataFloat.data(), textureExtent, channels, isSigned, isFloat, isHalfFloat, isSRGB, hasAlpha);
201
202 writeMipLevelToGPU(graphicsDevice, destinationTexture, currLevelData.data(), f, a, m, textureExtent, currentLevelSize, bytesPerPixel);
203 }
204 }
205 }
206 }
207
209 {
210 const bool generateMips = (td.flags & TextureFlags::GenerateMipMaps) != 0;
211 WGPUDevice device = graphicsDevice->device;
212
213 TextureWebGPU texture = {};
214
215 WGPUTextureFormat format = TextureFormatsWebGPU[(size_t)td.format];
216 WGPUTextureFormat view_formats[] = {format};
217
218 uint32_t mipLevelCount = td.levels;
219
220 // Create texture
221 WGPUTextureDescriptor desc = {};
222 desc.usage = WGPUTextureUsage_CopyDst | WGPUTextureUsage_TextureBinding;
223 desc.usage |= WGPUTextureUsage_CopySrc; // TODO add to td.flags???
224 if((td.flags&TextureFlags::RenderTarget) != 0 ||
225 (td.flags&TextureFlags::DepthBuffer) != 0){
226 desc.usage = WGPUTextureUsage_RenderAttachment | WGPUTextureUsage_TextureBinding;
227 }
228 if((td.flags&TextureFlags::ReadWriteTexture) != 0){
229 desc.usage |= WGPUTextureUsage_StorageBinding;
230 }
231 if(td.target == ResourceDimensions::Texture1D ||
232 td.target == ResourceDimensions::Texture1DArray){
233 desc.dimension = WGPUTextureDimension_1D;
234 }
235 else if(td.target == ResourceDimensions::Texture3D ||
236 td.target == ResourceDimensions::Texture3DArray){
237 desc.dimension = WGPUTextureDimension_3D;
238 }
239 else{
240 desc.dimension = WGPUTextureDimension_2D;
241 }
242
243 const Cogs::FormatInfo *textureFormat = Cogs::getFormatInfo(td.format);
244 bool compressedFormat =
245 ((textureFormat->blockExtent.width != 1) ||
246 (textureFormat->blockExtent.height != 1) ||
247 (textureFormat->blockExtent.depth != 1));
248
249 if(generateMips) {
250 if(compressedFormat) {
251 LOG_WARNING_ONCE(logger, "Generating mips for compressed textures is not supported.");
252 } else {
253 size_t max = glm::max(td.width, td.height);
254 if (max != 0) {
255 mipLevelCount = 1;
256 while (max >>= 1) {
257 ++mipLevelCount;
258 }
259 }
260 }
261 }
262
263 desc.size = {td.width, td.height, td.depth*td.faces*td.layers };
264 desc.format = format;
265 desc.mipLevelCount = mipLevelCount;
266 desc.sampleCount = td.samples;
267 desc.viewFormatCount = sizeof(view_formats)/sizeof(view_formats[0]);
268 desc.viewFormats = view_formats;
269
270#ifndef EMSCRIPTEN
271 wgpuDeviceValidateTextureDescriptor(device, &desc);
272#endif
273 texture.texture = wgpuDeviceCreateTexture(device, &desc);
274
275 // Create default texture view
276 texture.view_format = desc.format;
277 texture.format = td.format;
278 if(td.target == ResourceDimensions::Texture1D ||
279 td.target == ResourceDimensions::Texture1DArray){
280 texture.view_dimension = WGPUTextureViewDimension_1D;
281 }
282 else if(td.target == ResourceDimensions::Texture2D ||
283 td.target == ResourceDimensions::Texture2DMS){
284 texture.view_dimension = WGPUTextureViewDimension_2D;
285 }
286 else if(td.target == ResourceDimensions::Texture2DArray ||
287 td.target == ResourceDimensions::Texture2DMSArray){
288 texture.view_dimension = WGPUTextureViewDimension_2DArray;
289 }
290 else if(td.target == ResourceDimensions::Texture3D ||
291 td.target == ResourceDimensions::Texture3DArray){
292 texture.view_dimension = WGPUTextureViewDimension_3D;
293 }
294 else if(td.target == ResourceDimensions::TextureCube){
295 texture.view_dimension = WGPUTextureViewDimension_Cube;
296 }
297 else if(td.target == ResourceDimensions::TextureCubeArray){
298 texture.view_dimension = WGPUTextureViewDimension_CubeArray;
299 }
300 else{
301 assert(false);
302 }
303
304 WGPUTextureViewDescriptor view_desc = {};
305 view_desc.label = {"DefaultTextureView", WGPU_STRLEN};
306 view_desc.format = format;
307 view_desc.dimension = texture.view_dimension;
308 view_desc.baseMipLevel = 0;
309 view_desc.mipLevelCount = mipLevelCount;
310 view_desc.baseArrayLayer = 0;
311 view_desc.arrayLayerCount = td.faces*td.layers;
312 view_desc.aspect = WGPUTextureAspect_All;
313 texture.texture_view = wgpuTextureCreateView(texture.texture, &view_desc);
314
315 texture.width = td.width;
316 texture.height = td.height;
317 texture.samples = td.samples;
318
319 // Upload Data
320 if(data){
321 uint32_t faces = std::min(td.faces, static_cast<uint32_t>(data->faces));
322 uint32_t layers = std::min(td.layers, static_cast<uint32_t>(data->layers));
323 uint32_t levels = mipLevelCount;
324
325 if(generateMips && !compressedFormat) {
326 uint32_t bytesPerChannel = textureFormat->blockSize / textureFormat->elements;
327 Cogs::DataFormat formatType = parseDataFormat(textureFormat->name);
328
329 switch (formatType) {
330 case(Cogs::DataFormat::R8_UNORM):
331 case(Cogs::DataFormat::R8G8_UNORM):
332 case(Cogs::DataFormat::R8G8B8_UNORM):
333 case(Cogs::DataFormat::R8G8B8A8_UNORM):
334 {
335 generateMipmapsInternal<uint8_t>(
336 graphicsDevice,
337 &texture.texture,
338 data,
339 faces,
340 layers,
341 levels,
342 bytesPerChannel,
343 textureFormat->elements, // number of channels
344 false, // isSigned
345 false, // isFloat
346 false, // isHalfFloat
347 false, // isSRGB
348 false); // hasAlpha
349 break;
350 }
351 case(Cogs::DataFormat::R8_SNORM):
352 case(Cogs::DataFormat::R8G8_SNORM):
353 case(Cogs::DataFormat::R8G8B8_SNORM):
354 case(Cogs::DataFormat::R8G8B8A8_SNORM):
355 {
356 generateMipmapsInternal<uint8_t>(
357 graphicsDevice,
358 &texture.texture,
359 data,
360 faces,
361 layers,
362 levels,
363 bytesPerChannel,
364 textureFormat->elements, // number of channels
365 true, // isSigned
366 false, // isFloat
367 false, // isHalfFloat
368 false, // isSRGB
369 false); // hasAlpha
370 break;
371 }
372 case(Cogs::DataFormat::R16_UNORM):
373 case(Cogs::DataFormat::R16G16_UNORM):
374 case(Cogs::DataFormat::R16G16B16_UNORM):
375 case(Cogs::DataFormat::R16G16B16A16_UNORM):
376 {
377 generateMipmapsInternal<uint16_t>(
378 graphicsDevice,
379 &texture.texture,
380 data,
381 faces,
382 layers,
383 levels,
384 bytesPerChannel,
385 textureFormat->elements, // number of channels
386 false, // isSigned
387 false, // isFloat
388 false, // isHalfFloat
389 false, // isSRGB
390 false); // hasAlpha
391 break;
392 }
393 case(Cogs::DataFormat::R16_SNORM):
394 case(Cogs::DataFormat::R16G16_SNORM):
395 case(Cogs::DataFormat::R16G16B16_SNORM):
396 case(Cogs::DataFormat::R16G16B16A16_SNORM):
397 {
398 generateMipmapsInternal<uint16_t>(
399 graphicsDevice,
400 &texture.texture,
401 data,
402 faces,
403 layers,
404 levels,
405 bytesPerChannel,
406 textureFormat->elements, // number of channels
407 true, // isSigned
408 false, // isFloat
409 false, // isHalfFloat
410 false, // isSRGB
411 false); // hasAlpha
412 break;
413 }
414 case(Cogs::DataFormat::R16_FLOAT):
415 case(Cogs::DataFormat::R16G16_FLOAT):
416 case(Cogs::DataFormat::R16G16B16_FLOAT):
417 case(Cogs::DataFormat::R16G16B16A16_FLOAT):
418 {
419 generateMipmapsInternal<uint16_t>(
420 graphicsDevice,
421 &texture.texture,
422 data,
423 faces,
424 layers,
425 levels,
426 bytesPerChannel,
427 textureFormat->elements, // number of channels
428 false, // isSigned
429 false, // isFloat
430 true, // isHalfFloat
431 false, // isSRGB
432 false); // hasAlpha
433 break;
434 }
435 case(Cogs::DataFormat::R32_FLOAT):
436 case(Cogs::DataFormat::R32G32_FLOAT):
437 case(Cogs::DataFormat::R32G32B32_FLOAT):
438 case(Cogs::DataFormat::R32G32B32A32_FLOAT):
439 {
440 generateMipmapsInternal<float>(
441 graphicsDevice,
442 &texture.texture,
443 data,
444 faces,
445 layers,
446 levels,
447 bytesPerChannel,
448 textureFormat->elements, // number of channels
449 false, // isSigned
450 true, // isFloat
451 false, // isHalfFloat
452 false, // isSRGB
453 false); // hasAlpha
454 break;
455 }
456 case(Cogs::DataFormat::R8G8B8_UNORM_SRGB):
457 {
458 generateMipmapsInternal<uint8_t>(
459 graphicsDevice,
460 &texture.texture,
461 data,
462 faces,
463 layers,
464 levels,
465 bytesPerChannel,
466 textureFormat->elements, // number of channels
467 false, // isSigned
468 false, // isFloat
469 false, // isHalfFloat
470 true, // isSRGB
471 false); // hasAlpha
472 break;
473 }
474 case(Cogs::DataFormat::R8G8B8A8_UNORM_SRGB):
475 {
476 generateMipmapsInternal<uint8_t>(
477 graphicsDevice,
478 &texture.texture,
479 data,
480 faces,
481 layers,
482 levels,
483 bytesPerChannel,
484 textureFormat->elements, // number of channels
485 false, // isSigned
486 false, // isFloat
487 false, // isHalfFloat
488 true, // isSRGB
489 true); // hasAlpha
490 break;
491 }
492 default: {
493 break;
494 }
495 }
496 } else {
497 for (size_t f = 0; f < faces; ++f) { // Faces
498 for (size_t a = 0; a < layers; ++a) { // Array layer
499 for (size_t m = 0; m < mipLevelCount; ++m) { // Array layer
500 Cogs::TextureExtent extent = data->getExtent(m);
501 const void* ptr = data->getData(a, f, m);
502 const size_t ptr_size = data->getLevelSize(m);
503
504 if ((extent.width % data->blockExtent.width) != 0) {
505 extent.width = (extent.width / data->blockExtent.width + 1) * data->blockExtent.width;
506 }
507 if ((extent.height % data->blockExtent.height) != 0) {
508 extent.height = (extent.height / data->blockExtent.height + 1) * data->blockExtent.height;
509 }
510
511 WGPUTexelCopyTextureInfo dst = {};
512 dst.texture = texture.texture;
513 dst.mipLevel = (uint32_t)m;
514 dst.origin = { 0, 0, (uint32_t)(a + f) };
515 dst.aspect = WGPUTextureAspect_All;
516
517 WGPUTexelCopyBufferLayout layout = {};
518 layout.offset = 0;
519 layout.bytesPerRow = (uint32_t)data->getPitch(m);
520 layout.rowsPerImage = extent.height;
521 WGPUExtent3D size = { extent.width, extent.height, extent.depth };
522 wgpuQueueWriteTexture(graphicsDevice->queue, &dst, ptr, ptr_size, &layout, &size);
523 }
524 }
525 }
526 }
527 }
528
529 return textures.addResource(std::move(texture));
530 }
531
532
533 void TexturesWebGPU::releaseTexture(TextureHandle handle)
534 {
535 if(!HandleIsValid(handle)) return;
536
537 TextureWebGPU &texture = textures[handle];
538 wgpuTextureDestroy(texture.texture);
539 wgpuTextureRelease(texture.texture);
540
541 textures.removeResource(handle);
542 }
543
544 TextureViewHandle TexturesWebGPU::createTextureView(TextureViewDescription &view)
545 {
546 const TextureWebGPU &texture = textures[view.texture];
547
548 TextureViewWebGPU texture_view = {};
549
550 WGPUTextureViewDescriptor desc = {};
551 desc.format = texture.view_format;
552 desc.dimension = texture.view_dimension;
553 if(view.numLayers == 1){
554 switch(desc.dimension){
555 case WGPUTextureViewDimension_2DArray:
556 desc.dimension = WGPUTextureViewDimension_2D;
557 break;
558 case WGPUTextureViewDimension_CubeArray:
559 desc.dimension = WGPUTextureViewDimension_Cube;
560 break;
561 default:
562 break;
563 }
564 }
565 desc.baseMipLevel = view.levelIndex;
566 desc.mipLevelCount = view.numLevels;
567 desc.baseArrayLayer = view.layerIndex;
568 desc.arrayLayerCount = view.numLayers;
569 desc.aspect = WGPUTextureAspect_All;
570 texture_view.texture_view = wgpuTextureCreateView(texture.texture, &desc);
571
572 return textureViews.addResource(std::move(texture_view));
573 }
574
575 void TexturesWebGPU::releaseTextureView(const TextureViewHandle &handle)
576 {
577 if(!HandleIsValid(handle)) return;
578
579 TextureViewWebGPU &texture_view = textureViews[handle];
580 wgpuTextureViewRelease(texture_view.texture_view);
581
582 textureViews.removeResource(handle);
583 }
584
585 SamplerStateHandle TexturesWebGPU::loadSamplerState(const SamplerState &state)
586 {
587 WGPUDevice device = graphicsDevice->device;
588
589 SamplerStateWebGPU sampler = {};
590
591 WGPUSamplerDescriptor desc = {};
592 desc.addressModeU = wgpu(state.addressModeS);
593 desc.addressModeV = wgpu(state.addressModeT);
594 desc.addressModeW = wgpu(state.addressModeW);
595 switch(state.filter){
596 case SamplerState::FilterMode::MinMagMipPoint:
597 desc.magFilter = WGPUFilterMode_Nearest;
598 desc.minFilter = WGPUFilterMode_Nearest;
599 desc.mipmapFilter = WGPUMipmapFilterMode_Nearest;
600 desc.compare = WGPUCompareFunction_Undefined;
601 break;
602 case SamplerState::FilterMode::MinMagMipLinear:
603 desc.magFilter = WGPUFilterMode_Linear;
604 desc.minFilter = WGPUFilterMode_Linear;
605 desc.mipmapFilter = WGPUMipmapFilterMode_Linear;
606 desc.compare = WGPUCompareFunction_Undefined;
607 break;
608 case SamplerState::FilterMode::ComparisonMinMagMipPoint:
609 desc.magFilter = WGPUFilterMode_Nearest;
610 desc.minFilter = WGPUFilterMode_Nearest;
611 desc.mipmapFilter = WGPUMipmapFilterMode_Nearest;
612 desc.compare = wgpu(state.comparisonFunction);
613 break;
614 case SamplerState::FilterMode::ComparisonMinMagMipLinear:
615 desc.magFilter = WGPUFilterMode_Linear;
616 desc.minFilter = WGPUFilterMode_Linear;
617 desc.mipmapFilter = WGPUMipmapFilterMode_Linear;
618 desc.compare = wgpu(state.comparisonFunction);
619 break;
620 default:
621 assert(false);
622 break;
623 }
624 desc.lodMinClamp = 0;
625 desc.lodMaxClamp = 32;
626 if(state.maxAnisotropy < 1.0f)
627 desc.maxAnisotropy = 1;
628 else
629 desc.maxAnisotropy = (uint16_t)state.maxAnisotropy;
630 if ((desc.minFilter == WGPUFilterMode_Nearest || desc.magFilter == WGPUFilterMode_Nearest) && desc.maxAnisotropy > 1) {
631 LOG_WARNING(logger, "Sampler with nearest filter must set maxAnisotropy = 1");
632 desc.maxAnisotropy = 1;
633 }
634 sampler.sampler = wgpuDeviceCreateSampler(device, &desc);
635
636 return samplerStates.addResource(std::move(sampler));
637 }
638
639 void TexturesWebGPU::releaseSamplerState(SamplerStateHandle handle)
640 {
641 if(!HandleIsValid(handle)) return;
642
643 SamplerStateWebGPU &sampler = samplerStates[handle];
644 wgpuSamplerRelease(sampler.sampler);
645
646 samplerStates.removeResource(handle);
647 }
648
649 void TexturesWebGPU::generateMipmaps(TextureHandle /*handle*/)
650 {
651 // TODO
652 }
653
654 void TexturesWebGPU::releaseResources()
655 {
656 // TODO
657 }
658
659}
Log implementation class.
Definition: LogManager.h:140
Provides a weakly referenced view over the contents of a string.
Definition: StringView.h:24
virtual void annotate(TextureHandle handle, const StringView &name) override
Associate a name with an object for use in graphics debugging.
virtual TextureHandle loadTexture(const TextureDescription &desc, const TextureData *data) override
Load a texture from the given description.
constexpr Log getLogger(const char(&name)[LEN]) noexcept
Definition: LogManager.h:181
Contains all Cogs related functionality.
Definition: FieldSetter.h:23
uint16_t elements
Number of channels in a data item.
Definition: DataFormat.h:259
uint8_t blockSize
Bytesize of one block of data.
Definition: DataFormat.h:257
TextureExtent blockExtent
Number of data items in a block.
Definition: DataFormat.h:258
const char * name
Name as a color format (using RGBA as channels).
Definition: DataFormat.h:260
Encapsulates state for texture sampling in a state object.
Definition: SamplerState.h:12
ComparisonFunction comparisonFunction
Specifies the comparison function to use when applying a comparison sampler.
Definition: SamplerState.h:73
unsigned int maxAnisotropy
Specifies the maximum number of anisotropic samples to use when sampling a texture.
Definition: SamplerState.h:76
AddressMode addressModeW
Specifies the addressing mode along the W axis in texture coordinate space.
Definition: SamplerState.h:67
ComparisonFunction
Comparison functions applied when sampling depth buffers using comparison filters.
Definition: SamplerState.h:48
AddressMode addressModeS
Specifies the addressing mode along the S axis in texture coordinate space.
Definition: SamplerState.h:63
AddressMode
Addressing modes to use when sampling textures.
Definition: SamplerState.h:15
@ Clamp
Texture coordinates are clamped to the [0, 1] range.
Definition: SamplerState.h:17
@ Border
Texture color is set to the border color when outside [0, 1] range.
Definition: SamplerState.h:23
@ Wrap
Texture coordinates automatically wrap around to [0, 1] range.
Definition: SamplerState.h:19
@ Mirror
Texture coordinates are mirrored when outside [0, 1] range.
Definition: SamplerState.h:21
FilterMode filter
Specifies the filter to use for texture sampling.
Definition: SamplerState.h:70
AddressMode addressModeT
Specifies the addressing mode along the T axis in texture coordinate space.
Definition: SamplerState.h:65
@ DepthBuffer
The texture can be used as a depth target and have depth buffer values written into.
Definition: Flags.h:122
@ RenderTarget
The texture can be used as a render target and drawn into.
Definition: Flags.h:120
@ GenerateMipMaps
The texture supports automatic mipmap generation performed by the graphics device.
Definition: Flags.h:124
@ ReadWriteTexture
The texture can be used as a read/write texture. Can be used to output data from compute shaders.
Definition: Flags.h:128
Describes how to fetch data from a texture in shaders.
Definition: ITextures.h:13
uint32_t layerIndex
Index of the first layer (if array) to fetch from.
Definition: ITextures.h:17
uint32_t numLayers
Number of array layers available.
Definition: ITextures.h:19
uint32_t numLevels
Number of mipmap levels available.
Definition: ITextures.h:23
uint32_t levelIndex
First mipmap level to fetch data from.
Definition: ITextures.h:21
TextureHandle texture
Texture.
Definition: ITextures.h:15