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
9namespace{
10 Cogs::Logging::Log logger = Cogs::Logging::getLogger("TexturesWebGPU");
11 WGPUCompareFunction wgpu(Cogs::SamplerState::ComparisonFunction cmp)
12 {
13 switch(cmp){
14 case Cogs::SamplerState::ComparisonFunction::Never:
15 return WGPUCompareFunction_Never;
16 case Cogs::SamplerState::ComparisonFunction::Less:
17 return WGPUCompareFunction_Less;
18 case Cogs::SamplerState::ComparisonFunction::Equal:
19 return WGPUCompareFunction_Equal;
20 case Cogs::SamplerState::ComparisonFunction::LessEqual:
21 return WGPUCompareFunction_LessEqual;
22 case Cogs::SamplerState::ComparisonFunction::Greater:
23 return WGPUCompareFunction_Greater;
24 case Cogs::SamplerState::ComparisonFunction::NotEqual:
25 return WGPUCompareFunction_NotEqual;
26 case Cogs::SamplerState::ComparisonFunction::GreaterEqual:
27 return WGPUCompareFunction_GreaterEqual;
28 case Cogs::SamplerState::ComparisonFunction::Always:
29 return WGPUCompareFunction_Always;
30 case Cogs::SamplerState::ComparisonFunction::ComparisonFunction_Size:
31 break;
32 }
33 assert(false);
34 return WGPUCompareFunction_Undefined;
35 }
36
37 WGPUAddressMode wgpu(Cogs::SamplerState::AddressMode address_mode)
38 {
39 switch(address_mode){
41 return WGPUAddressMode_ClampToEdge;
43 return WGPUAddressMode_Repeat;
45 return WGPUAddressMode_MirrorRepeat;
47 // assert(false); // Not supported
48 return WGPUAddressMode_ClampToEdge;
49 case Cogs::SamplerState::AddressMode::AddressMode_Size:
50 break;
51 }
52 assert(false);
53 return WGPUAddressMode_Repeat;
54 }
55}
56
57namespace Cogs{
58
59 void TexturesWebGPU::initialize(class GraphicsDeviceWebGPU *device)
60 {
61 graphicsDevice = device;
62 }
63
65 {
66 TextureWebGPU &texture = textures[handle];
67 wgpuTextureSetLabel(texture.texture, name.data());
68 }
69
71 {
72 WGPUDevice device = graphicsDevice->device;
73
74 TextureWebGPU texture = {};
75
76 WGPUTextureFormat format = TextureFormatsWebGPU[(size_t)td.format];
77 WGPUTextureFormat view_formats[] = {format};
78
79 // Create texture
80 WGPUTextureDescriptor desc = {};
81 desc.usage = WGPUTextureUsage_CopyDst | WGPUTextureUsage_TextureBinding;
82 desc.usage |= WGPUTextureUsage_CopySrc; // TODO add to td.flags???
83 if((td.flags&TextureFlags::RenderTarget) != 0 ||
84 (td.flags&TextureFlags::DepthBuffer) != 0){
85 desc.usage = WGPUTextureUsage_RenderAttachment | WGPUTextureUsage_TextureBinding;
86 }
87 if((td.flags&TextureFlags::ReadWriteTexture) != 0){
88 desc.usage |= WGPUTextureUsage_StorageBinding;
89 }
90 if(td.target == ResourceDimensions::Texture1D ||
91 td.target == ResourceDimensions::Texture1DArray){
92 desc.dimension = WGPUTextureDimension_1D;
93 }
94 else if(td.target == ResourceDimensions::Texture3D ||
95 td.target == ResourceDimensions::Texture3DArray){
96 desc.dimension = WGPUTextureDimension_3D;
97 }
98 else{
99 desc.dimension = WGPUTextureDimension_2D;
100 }
101
102 desc.size = {td.width, td.height, td.depth*td.faces*td.layers };
103 desc.format = format;
104 desc.mipLevelCount = td.levels;
105 desc.sampleCount = td.samples;
106 desc.viewFormatCount = sizeof(view_formats)/sizeof(view_formats[0]);
107 desc.viewFormats = view_formats;
108
109#ifndef EMSCRIPTEN
110 wgpuDeviceValidateTextureDescriptor(device, &desc);
111#endif
112 texture.texture = wgpuDeviceCreateTexture(device, &desc);
113
114 // Create default texture view
115 texture.view_format = desc.format;
116 if(td.target == ResourceDimensions::Texture1D ||
117 td.target == ResourceDimensions::Texture1DArray){
118 texture.view_dimension = WGPUTextureViewDimension_1D;
119 }
120 else if(td.target == ResourceDimensions::Texture2D ||
121 td.target == ResourceDimensions::Texture2DMS){
122 texture.view_dimension = WGPUTextureViewDimension_2D;
123 }
124 else if(td.target == ResourceDimensions::Texture2DArray ||
125 td.target == ResourceDimensions::Texture2DMSArray){
126 texture.view_dimension = WGPUTextureViewDimension_2DArray;
127 }
128 else if(td.target == ResourceDimensions::Texture3D ||
129 td.target == ResourceDimensions::Texture3DArray){
130 texture.view_dimension = WGPUTextureViewDimension_3D;
131 }
132 else if(td.target == ResourceDimensions::TextureCube){
133 texture.view_dimension = WGPUTextureViewDimension_Cube;
134 }
135 else if(td.target == ResourceDimensions::TextureCubeArray){
136 texture.view_dimension = WGPUTextureViewDimension_CubeArray;
137 }
138 else{
139 assert(false);
140 }
141 WGPUTextureViewDescriptor view_desc = {};
142 view_desc.label = "DefaultTextureView";
143 view_desc.format = texture.view_format;
144 view_desc.dimension = texture.view_dimension;
145 view_desc.baseMipLevel = 0;
146 view_desc.mipLevelCount = td.levels;
147 view_desc.baseArrayLayer = 0;
148 view_desc.arrayLayerCount = td.faces*td.layers;
149 view_desc.aspect = WGPUTextureAspect_All;
150 texture.texture_view = wgpuTextureCreateView(texture.texture, &view_desc);
151
152 texture.width = td.width;
153 texture.height = td.height;
154 texture.samples = td.samples;
155
156 // Upload Data
157 if(data){
158 for (size_t f = 0; f < std::min(size_t(td.faces), data->faces); ++f) { // Faces
159 for (size_t a = 0; a < std::min(size_t(td.layers), data->layers); ++a) { // Array layer
160 for (size_t j = 0; j < std::min(size_t(td.levels), data->levels); ++j) { // Mipmap
161 Cogs::TextureExtent extent = data->getExtent(j);
162 const void *ptr = data->getData(a, f, j);
163 const size_t ptr_size = data->getLevelSize(j);
164
165 if ((extent.width % data->blockExtent.width) != 0) {
166 extent.width = (extent.width / data->blockExtent.width + 1) * data->blockExtent.width;
167 }
168 if ((extent.height % data->blockExtent.height) != 0) {
169 extent.height = (extent.height / data->blockExtent.height + 1) * data->blockExtent.height;
170 }
171
172 WGPUImageCopyTexture dst = {};
173 dst.texture = texture.texture;
174 dst.mipLevel = (uint32_t)j;
175 dst.origin = {0, 0, (uint32_t)(a+f)};
176 dst.aspect = WGPUTextureAspect_All;
177
178 WGPUTextureDataLayout layout = {};
179 layout.offset = 0;
180 layout.bytesPerRow = (uint32_t)data->getPitch(j);
181 layout.rowsPerImage = extent.height;
182 WGPUExtent3D size = {extent.width, extent.height, extent.depth};
183 wgpuQueueWriteTexture(graphicsDevice->queue, &dst, ptr, ptr_size, &layout, &size);
184 }
185 }
186 }
187 }
188
189 return textures.addResource(std::move(texture));
190 }
191
192 void TexturesWebGPU::releaseTexture(TextureHandle handle)
193 {
194 if(!HandleIsValid(handle)) return;
195
196 TextureWebGPU &texture = textures[handle];
197 wgpuTextureDestroy(texture.texture);
198 wgpuTextureRelease(texture.texture);
199
200 textures.removeResource(handle);
201 }
202
203 TextureViewHandle TexturesWebGPU::createTextureView(TextureViewDescription &view)
204 {
205 const TextureWebGPU &texture = textures[view.texture];
206
207 TextureViewWebGPU texture_view = {};
208
209 WGPUTextureViewDescriptor desc = {};
210 desc.format = texture.view_format;
211 desc.dimension = texture.view_dimension;
212 if(view.numLayers == 1){
213 switch(desc.dimension){
214 case WGPUTextureViewDimension_2DArray:
215 desc.dimension = WGPUTextureViewDimension_2D;
216 break;
217 case WGPUTextureViewDimension_CubeArray:
218 desc.dimension = WGPUTextureViewDimension_Cube;
219 break;
220 default:
221 break;
222 }
223 }
224 desc.baseMipLevel = view.levelIndex;
225 desc.mipLevelCount = view.numLevels;
226 desc.baseArrayLayer = view.layerIndex;
227 desc.arrayLayerCount = view.numLayers;
228 desc.aspect = WGPUTextureAspect_All;
229 texture_view.texture_view = wgpuTextureCreateView(texture.texture, &desc);
230
231 return textureViews.addResource(std::move(texture_view));
232 }
233
234 void TexturesWebGPU::releaseTextureView(const TextureViewHandle &handle)
235 {
236 if(!HandleIsValid(handle)) return;
237
238 TextureViewWebGPU &texture_view = textureViews[handle];
239 wgpuTextureViewRelease(texture_view.texture_view);
240
241 textureViews.removeResource(handle);
242 }
243
244 SamplerStateHandle TexturesWebGPU::loadSamplerState(const SamplerState &state)
245 {
246 WGPUDevice device = graphicsDevice->device;
247
248 SamplerStateWebGPU sampler = {};
249
250 WGPUSamplerDescriptor desc = {};
251 desc.addressModeU = wgpu(state.addressModeS);
252 desc.addressModeV = wgpu(state.addressModeT);
253 desc.addressModeW = wgpu(state.addressModeW);
254 switch(state.filter){
255 case SamplerState::FilterMode::MinMagMipPoint:
256 desc.magFilter = WGPUFilterMode_Nearest;
257 desc.minFilter = WGPUFilterMode_Nearest;
258 desc.mipmapFilter = WGPUMipmapFilterMode_Nearest;
259 desc.compare = WGPUCompareFunction_Undefined;
260 break;
261 case SamplerState::FilterMode::MinMagMipLinear:
262 desc.magFilter = WGPUFilterMode_Linear;
263 desc.minFilter = WGPUFilterMode_Linear;
264 desc.mipmapFilter = WGPUMipmapFilterMode_Linear;
265 desc.compare = WGPUCompareFunction_Undefined;
266 break;
267 case SamplerState::FilterMode::ComparisonMinMagMipPoint:
268 desc.magFilter = WGPUFilterMode_Nearest;
269 desc.minFilter = WGPUFilterMode_Nearest;
270 desc.mipmapFilter = WGPUMipmapFilterMode_Nearest;
271 desc.compare = wgpu(state.comparisonFunction);
272 break;
273 case SamplerState::FilterMode::ComparisonMinMagMipLinear:
274 desc.magFilter = WGPUFilterMode_Linear;
275 desc.minFilter = WGPUFilterMode_Linear;
276 desc.mipmapFilter = WGPUMipmapFilterMode_Linear;
277 desc.compare = wgpu(state.comparisonFunction);
278 break;
279 default:
280 assert(false);
281 break;
282 }
283 desc.lodMinClamp = 0;
284 desc.lodMaxClamp = 32;
285 if(state.maxAnisotropy == 0.0f) // TODO should we enfoce this >= 1.0f?
286 desc.maxAnisotropy = 1;
287 else
288 desc.maxAnisotropy = (uint16_t)state.maxAnisotropy;
289 if ((desc.minFilter == WGPUFilterMode_Nearest || desc.magFilter == WGPUFilterMode_Nearest) && desc.maxAnisotropy > 1) {
290 LOG_WARNING(logger, "Sampler with nearest filter must set maxAnisotropy = 1");
291 desc.maxAnisotropy = 1;
292 }
293 sampler.sampler = wgpuDeviceCreateSampler(device, &desc);
294
295 return samplerStates.addResource(std::move(sampler));
296 }
297
298 void TexturesWebGPU::releaseSamplerState(SamplerStateHandle handle)
299 {
300 if(!HandleIsValid(handle)) return;
301
302 SamplerStateWebGPU &sampler = samplerStates[handle];
303 wgpuSamplerRelease(sampler.sampler);
304
305 samplerStates.removeResource(handle);
306 }
307
308 void TexturesWebGPU::generateMipmaps(TextureHandle /*handle*/)
309 {
310 // TODO
311 }
312
313 void TexturesWebGPU::releaseResources()
314 {
315 // TODO
316 }
317
318}
Log implementation class.
Definition: LogManager.h:139
Provides a weakly referenced view over the contents of a string.
Definition: StringView.h:24
constexpr const char * data() const noexcept
Get the sequence of characters referenced by the string view.
Definition: StringView.h:171
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:180
Contains all Cogs related functionality.
Definition: FieldSetter.h:23
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
@ 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