3#if !defined(__EMSCRIPTEN__)
13 wgpu::PopErrorScopeStatus
status = wgpu::PopErrorScopeStatus::Error;
14 wgpu::ErrorType
type = wgpu::ErrorType::NoError;
22 explicit UploadScopes(
const wgpu::Device&
device) : device_(
device) {
23 for (
auto& result : results_) result =
std::make_shared<UploadError>();
25 {wgpu::ErrorFilter::Validation, wgpu::ErrorFilter::OutOfMemory, wgpu::ErrorFilter::Internal}) {
26 device_.PushErrorScope(
filter);
33 WGPUPopErrorScopeCallbackInfo
callback{};
34 callback.mode = WGPUCallbackMode_AllowSpontaneous;
35 callback.callback = [](WGPUPopErrorScopeStatus, WGPUErrorType, WGPUStringView,
void*,
void*) {};
36 (void)wgpuDevicePopErrorScope(device_.Get(),
callback);
40 [[nodiscard]] Result<void> finish(
const wgpu::Instance& instance) {
41 std::array<wgpu::Future, 3> futures{};
42 for (
size_t i = 0; i < futures.size(); ++i) {
43 futures[i] = device_.PopErrorScope(
44 wgpu::CallbackMode::WaitAnyOnly,
45 [result = results_[i]](wgpu::PopErrorScopeStatus
status, wgpu::ErrorType
type,
46 wgpu::StringView
message)
noexcept {
50 const auto length = message.length == WGPU_STRLEN ? std::strlen(message.data) : message.length;
51 std::memcpy(result->message.data(), message.data, std::min(length, result->message.size() - 1));
56 const auto deadline = std::chrono::steady_clock::now() + std::chrono::seconds(30);
57 for (
auto future : futures) {
58 const auto remaining =
deadline - std::chrono::steady_clock::now();
60 std::max<int64_t>(0, std::chrono::duration_cast<std::chrono::nanoseconds>(remaining).
count());
61 if (instance.WaitAny(
future, uint64_t(timeout)) != wgpu::WaitStatus::Success)
63 "WebGPU mip upload error scope could not be observed",
64 {}, {},
"graphics.texture.mips"));
66 for (
const auto& result : results_)
67 if (result->
status != wgpu::PopErrorScopeStatus::
Success || result->
type != wgpu::ErrorType::NoError)
70 {},
"graphics.texture.mips"));
76 unsigned pending_ = 0;
77 std::array<std::shared_ptr<UploadError>, 3> results_;
82 std::span<const uint8_t> rgba) {
90 uint64_t expected = 0;
93 expected += uint64_t(
w) *
h * 4;
95 if (
w == 1 &&
h == 1)
break;
96 w = std::max(
w / 2, 1u);
97 h = std::max(
h / 2, 1u);
99 if (levels !=
count || expected != rgba.size() || expected > UINT32_MAX)
102 ownedTextures.reserve(ownedTextures.size() + 1);
103 ownedGpuTextures.reserve(ownedGpuTextures.size() + 1);
104 auto tex = std::make_unique<Texture>();
105 auto gpu = std::make_unique<GpuTexture>();
106 gpu->width = int(
width);
107 gpu->height = int(
height);
108 gpu->mipLevels = levels;
110 UploadScopes scopes(
device);
112 descriptor.dimension = wgpu::TextureDimension::e2D;
114 descriptor.format = wgpu::TextureFormat::RGBA8Unorm;
117 descriptor.usage = wgpu::TextureUsage::TextureBinding | wgpu::TextureUsage::CopyDst;
120 auto checked = scopes.finish(instance);
128 wgpu::TexelCopyTextureInfo destination{};
129 destination.texture = gpu->texture;
130 destination.mipLevel =
level;
131 wgpu::TexelCopyBufferLayout
layout{};
134 wgpu::Extent3D extent{
w,
h, 1};
135 const size_t bytes = size_t(
w) *
h * 4;
138 w = std::max(
w / 2, 1u);
139 h = std::max(
h / 2, 1u);
141 gpu->view = gpu->texture.CreateView();
142 gpu->sampler = makeSampler(gpu->samplerState, levels);
143 auto checked = scopes.finish(instance);
145 if (!gpu->view || !gpu->sampler)
147 tex->width = tex->pixelWidth = int(
width);
148 tex->height = tex->pixelHeight = int(
height);
149 tex->mipmapCount = int(levels);
150 tex->sampler = gpu->samplerState;
151 tex->gpuHandle = gpu.get();
152 auto* result = tex.get();
153 ownedTextures.push_back(std::move(tex));
154 ownedGpuTextures.push_back(std::move(gpu));
156 }
catch (
const std::exception&
error) {
162 std::span<const uint16_t> rgbaHalf) {
169 const uint64_t texels = uint64_t(
width) *
height * layers;
172 layers >
limits.maxTextureArrayLayers || texels > SIZE_MAX / 4u || rgbaHalf.size() != texels * 4u)
175 ownedTextures.reserve(ownedTextures.size() + 1u);
176 ownedGpuTextures.reserve(ownedGpuTextures.size() + 1u);
177 auto tex = std::make_unique<Texture>();
178 auto gpu = std::make_unique<GpuTexture>();
179 gpu->width = int(
width);
180 gpu->height = int(
height);
183 UploadScopes scopes(
device);
185 descriptor.dimension = wgpu::TextureDimension::e2D;
187 descriptor.format = wgpu::TextureFormat::RGBA16Float;
190 descriptor.usage = wgpu::TextureUsage::TextureBinding | wgpu::TextureUsage::CopyDst;
192 wgpu::TexelCopyTextureInfo destination{};
193 destination.texture = gpu->texture;
194 wgpu::TexelCopyBufferLayout
layout{};
197 const wgpu::Extent3D extent{
width,
height, layers};
198 queue.WriteTexture(&destination, rgbaHalf.data(), rgbaHalf.size_bytes(), &
layout, &extent);
199 wgpu::TextureViewDescriptor
view{};
200 view.format = wgpu::TextureFormat::RGBA16Float;
201 view.dimension = wgpu::TextureViewDimension::e2DArray;
202 view.mipLevelCount = 1;
203 view.arrayLayerCount = layers;
204 gpu->view = gpu->texture.CreateView(&
view);
205 gpu->sampler = makeSampler(gpu->samplerState, 1);
206 auto checked = scopes.finish(instance);
208 if (!gpu->texture || !gpu->view || !gpu->sampler)
210 tex->width = tex->pixelWidth = int(
width);
211 tex->height = tex->pixelHeight = int(
height);
212 tex->layers = int(layers);
213 tex->sampler = gpu->samplerState;
214 tex->gpuHandle = gpu.get();
215 auto* result = tex.get();
216 ownedTextures.push_back(std::move(tex));
217 ownedGpuTextures.push_back(std::move(gpu));
219 }
catch (
const std::exception&
error) {
225 std::span<const uint8_t> rgba) {
235 depth >
limits.maxTextureDimension3D || texels > SIZE_MAX / 4u || rgba.size() != texels * 4u)
238 ownedTextures.reserve(ownedTextures.size() + 1u);
239 ownedGpuTextures.reserve(ownedGpuTextures.size() + 1u);
240 auto tex = std::make_unique<Texture>();
241 auto gpu = std::make_unique<GpuTexture>();
242 gpu->width = int(
width);
243 gpu->height = int(
height);
244 gpu->isVolume =
true;
246 gpu->samplerState.repeatU = gpu->samplerState.repeatV = gpu->samplerState.repeatW =
true;
247 UploadScopes scopes(
device);
249 descriptor.dimension = wgpu::TextureDimension::e3D;
251 descriptor.format = wgpu::TextureFormat::RGBA8Unorm;
254 descriptor.usage = wgpu::TextureUsage::TextureBinding | wgpu::TextureUsage::CopyDst;
256 wgpu::TexelCopyTextureInfo destination{};
257 destination.texture = gpu->texture;
258 wgpu::TexelCopyBufferLayout
layout{};
262 queue.WriteTexture(&destination, rgba.data(), rgba.size(), &
layout, &extent);
263 wgpu::TextureViewDescriptor
view{};
264 view.format = wgpu::TextureFormat::RGBA8Unorm;
265 view.dimension = wgpu::TextureViewDimension::e3D;
266 view.mipLevelCount = 1;
267 view.arrayLayerCount = 1;
268 gpu->view = gpu->texture.CreateView(&
view);
269 gpu->sampler = makeSampler(gpu->samplerState, 1);
270 auto checked = scopes.finish(instance);
272 if (!gpu->texture || !gpu->view || !gpu->sampler)
274 tex->width = tex->pixelWidth = int(
width);
275 tex->height = tex->pixelHeight = int(
height);
276 tex->depth = int(
depth);
277 tex->sampler = gpu->samplerState;
278 tex->gpuHandle = gpu.get();
279 auto* result = tex.get();
280 ownedTextures.push_back(std::move(tex));
281 ownedGpuTextures.push_back(std::move(gpu));
283 }
catch (
const std::exception&
error) {
wgpu::PopErrorScopeStatus status
const AssetImportLimits & limits
static Diagnostic error(DiagnosticCode code, std::string message, std::string path={}, DiagnosticDetails details={}, std::string source={})
Construct an error diagnostic with the standard error severity.
Move-only operation result carrying either a value or Status.
static Result success(T value)
Construct a successful result owning value.
static Result failure(Status status)
Construct a failed result from a structured status.
uint32_t maxTextureDimension2D() const
Maximum 2D texture dimension the device guarantees.
Result< Texture * > newTextureArrayRgba16f(uint32_t width, uint32_t height, uint32_t layers, std::span< const uint16_t > rgbaHalf) override
Upload a sampled 2D array of tightly packed linear RGBA16F texels.
Result< Texture * > newTexture3DRgba8(uint32_t width, uint32_t height, uint32_t depth, std::span< const uint8_t > rgba) override
Upload one tightly packed linear RGBA8 3D sampled texture.
Result< Texture * > newTextureMipChain(uint32_t width, uint32_t height, uint32_t levels, std::span< const uint8_t > rgba) override
Upload complete explicit linear RGBA8 mips without regenerating pixels.
eve::Diagnostic Diagnostic
DiagnosticCode
Stable machine-readable diagnostic codes.
static TextureSampler linear()
Linear.
static TextureSampler linearMipmap()
Trilinear (linear + linear mips). Caller should create the texture with generateMipmaps.
std::future< vkb::Instance > future