summaryrefslogtreecommitdiffstats
path: root/dom/webgpu/Texture.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'dom/webgpu/Texture.cpp')
-rw-r--r--dom/webgpu/Texture.cpp121
1 files changed, 121 insertions, 0 deletions
diff --git a/dom/webgpu/Texture.cpp b/dom/webgpu/Texture.cpp
new file mode 100644
index 0000000000..c7bc406118
--- /dev/null
+++ b/dom/webgpu/Texture.cpp
@@ -0,0 +1,121 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "Texture.h"
+
+#include "ipc/WebGPUChild.h"
+#include "mozilla/webgpu/ffi/wgpu.h"
+#include "mozilla/webgpu/CanvasContext.h"
+#include "mozilla/dom/WebGPUBinding.h"
+#include "mozilla/webgpu/WebGPUTypes.h"
+#include "TextureView.h"
+#include "Utility.h"
+
+namespace mozilla::webgpu {
+
+GPU_IMPL_CYCLE_COLLECTION(Texture, mParent)
+GPU_IMPL_JS_WRAP(Texture)
+
+static Maybe<uint8_t> GetBytesPerBlockSingleAspect(
+ dom::GPUTextureFormat aFormat) {
+ auto format = ConvertTextureFormat(aFormat);
+ uint32_t bytes = ffi::wgpu_texture_format_block_size_single_aspect(format);
+ if (bytes == 0) {
+ // The above function returns zero if the texture has multiple aspects like
+ // depth and stencil.
+ return Nothing();
+ }
+
+ return Some((uint8_t)bytes);
+}
+
+Texture::Texture(Device* const aParent, RawId aId,
+ const dom::GPUTextureDescriptor& aDesc)
+ : ChildOf(aParent),
+ mId(aId),
+ mFormat(aDesc.mFormat),
+ mBytesPerBlock(GetBytesPerBlockSingleAspect(aDesc.mFormat)),
+ mSize(ConvertExtent(aDesc.mSize)),
+ mMipLevelCount(aDesc.mMipLevelCount),
+ mSampleCount(aDesc.mSampleCount),
+ mDimension(aDesc.mDimension),
+ mUsage(aDesc.mUsage) {
+ MOZ_RELEASE_ASSERT(aId);
+}
+
+void Texture::Cleanup() {
+ if (!mParent) {
+ return;
+ }
+
+ auto bridge = mParent->GetBridge();
+ if (bridge && bridge->IsOpen()) {
+ bridge->SendTextureDrop(mId);
+ }
+
+ // After cleanup is called, no other method should ever be called on the
+ // object so we don't have to null-check mParent in other places.
+ // This serves the purpose of preventing SendTextureDrop from happening
+ // twice. TODO: Does it matter for breaking cycles too? Cleanup is called
+ // by the macros that deal with cycle colleciton.
+ mParent = nullptr;
+}
+
+Texture::~Texture() { Cleanup(); }
+
+already_AddRefed<TextureView> Texture::CreateView(
+ const dom::GPUTextureViewDescriptor& aDesc) {
+ auto bridge = mParent->GetBridge();
+
+ ffi::WGPUTextureViewDescriptor desc = {};
+
+ webgpu::StringHelper label(aDesc.mLabel);
+ desc.label = label.Get();
+
+ ffi::WGPUTextureFormat format = {ffi::WGPUTextureFormat_Sentinel};
+ if (aDesc.mFormat.WasPassed()) {
+ format = ConvertTextureFormat(aDesc.mFormat.Value());
+ desc.format = &format;
+ }
+ ffi::WGPUTextureViewDimension dimension =
+ ffi::WGPUTextureViewDimension_Sentinel;
+ if (aDesc.mDimension.WasPassed()) {
+ dimension = ffi::WGPUTextureViewDimension(aDesc.mDimension.Value());
+ desc.dimension = &dimension;
+ }
+
+ // Ideally we'd just do something like "aDesc.mMipLevelCount.ptrOr(nullptr)"
+ // but dom::Optional does not seem to have very many nice things.
+ uint32_t mipCount =
+ aDesc.mMipLevelCount.WasPassed() ? aDesc.mMipLevelCount.Value() : 0;
+ uint32_t layerCount =
+ aDesc.mArrayLayerCount.WasPassed() ? aDesc.mArrayLayerCount.Value() : 0;
+
+ desc.aspect = ffi::WGPUTextureAspect(aDesc.mAspect);
+ desc.base_mip_level = aDesc.mBaseMipLevel;
+ desc.mip_level_count = aDesc.mMipLevelCount.WasPassed() ? &mipCount : nullptr;
+ desc.base_array_layer = aDesc.mBaseArrayLayer;
+ desc.array_layer_count =
+ aDesc.mArrayLayerCount.WasPassed() ? &layerCount : nullptr;
+
+ ipc::ByteBuf bb;
+ RawId id = ffi::wgpu_client_create_texture_view(bridge->GetClient(), mId,
+ &desc, ToFFI(&bb));
+ if (bridge->CanSend()) {
+ bridge->SendTextureAction(mId, mParent->mId, std::move(bb));
+ }
+
+ RefPtr<TextureView> view = new TextureView(this, id);
+ return view.forget();
+}
+
+void Texture::Destroy() {
+ auto bridge = mParent->GetBridge();
+ if (bridge && bridge->IsOpen()) {
+ bridge->SendTextureDestroy(mId, mParent->GetId());
+ }
+}
+
+} // namespace mozilla::webgpu