1 // 2 // Copyright 2024 The ANGLE Project Authors. All rights reserved. 3 // Use of this source code is governed by a BSD-style license that can be 4 // found in the LICENSE file. 5 // 6 7 #ifndef LIBANGLE_RENDERER_WGPU_WGPU_HELPERS_H_ 8 #define LIBANGLE_RENDERER_WGPU_WGPU_HELPERS_H_ 9 10 #include <dawn/webgpu_cpp.h> 11 #include <stdint.h> 12 #include <algorithm> 13 14 #include "libANGLE/Error.h" 15 #include "libANGLE/ImageIndex.h" 16 #include "libANGLE/angletypes.h" 17 #include "libANGLE/renderer/wgpu/ContextWgpu.h" 18 #include "libANGLE/renderer/wgpu/wgpu_utils.h" 19 20 namespace rx 21 { 22 23 class ContextWgpu; 24 25 namespace webgpu 26 { 27 28 // WebGPU requires copy buffers bytesPerRow to be aligned to 256. 29 // https://www.w3.org/TR/webgpu/#abstract-opdef-validating-gputexelcopybufferinfo 30 static const GLuint kCopyBufferAlignment = 256; 31 32 enum class UpdateSource 33 { 34 Clear, 35 Texture, 36 }; 37 38 struct ClearUpdate 39 { 40 ClearValues clearValues; 41 bool hasDepth; 42 bool hasStencil; 43 }; 44 45 struct SubresourceUpdate 46 { SubresourceUpdateSubresourceUpdate47 SubresourceUpdate() {} ~SubresourceUpdateSubresourceUpdate48 ~SubresourceUpdate() {} 49 SubresourceUpdateSubresourceUpdate50 SubresourceUpdate(UpdateSource targetUpdateSource, 51 gl::LevelIndex newTargetLevel, 52 wgpu::TexelCopyBufferInfo targetBuffer) 53 { 54 updateSource = targetUpdateSource; 55 textureData = targetBuffer; 56 targetLevel = newTargetLevel; 57 } 58 SubresourceUpdateSubresourceUpdate59 SubresourceUpdate(UpdateSource targetUpdateSource, 60 gl::LevelIndex newTargetLevel, 61 ClearValues clearValues, 62 bool hasDepth, 63 bool hasStencil) 64 { 65 updateSource = targetUpdateSource; 66 targetLevel = newTargetLevel; 67 clearData.clearValues = clearValues; 68 clearData.hasDepth = hasDepth; 69 clearData.hasStencil = hasStencil; 70 } 71 72 UpdateSource updateSource; 73 ClearUpdate clearData; 74 wgpu::TexelCopyBufferInfo textureData; 75 76 gl::LevelIndex targetLevel; 77 }; 78 79 wgpu::TextureDimension toWgpuTextureDimension(gl::TextureType glTextureType); 80 81 class ImageHelper 82 { 83 public: 84 ImageHelper(); 85 ~ImageHelper(); 86 87 angle::Result initImage(angle::FormatID intendedFormatID, 88 angle::FormatID actualFormatID, 89 wgpu::Device &device, 90 gl::LevelIndex firstAllocatedLevel, 91 wgpu::TextureDescriptor textureDescriptor); 92 angle::Result initExternal(angle::FormatID intendedFormatID, 93 angle::FormatID actualFormatID, 94 wgpu::Texture externalTexture); 95 96 angle::Result flushStagedUpdates(ContextWgpu *contextWgpu); 97 angle::Result flushSingleLevelUpdates(ContextWgpu *contextWgpu, 98 gl::LevelIndex levelGL, 99 ClearValuesArray *deferredClears, 100 uint32_t deferredClearIndex); 101 102 wgpu::TextureDescriptor createTextureDescriptor(wgpu::TextureUsage usage, 103 wgpu::TextureDimension dimension, 104 wgpu::Extent3D size, 105 wgpu::TextureFormat format, 106 std::uint32_t mipLevelCount, 107 std::uint32_t sampleCount); 108 109 angle::Result stageTextureUpload(ContextWgpu *contextWgpu, 110 const webgpu::Format &webgpuFormat, 111 GLenum type, 112 const gl::Extents &glExtents, 113 GLuint inputRowPitch, 114 GLuint inputDepthPitch, 115 uint32_t outputRowPitch, 116 uint32_t outputDepthPitch, 117 uint32_t allocationSize, 118 const gl::ImageIndex &index, 119 const uint8_t *pixels); 120 121 void stageClear(gl::LevelIndex targetLevel, 122 ClearValues clearValues, 123 bool hasDepth, 124 bool hasStencil); 125 126 void removeStagedUpdates(gl::LevelIndex levelToRemove); 127 128 void resetImage(); 129 130 static angle::Result getReadPixelsParams(rx::ContextWgpu *contextWgpu, 131 const gl::PixelPackState &packState, 132 gl::Buffer *packBuffer, 133 GLenum format, 134 GLenum type, 135 const gl::Rectangle &area, 136 const gl::Rectangle &clippedArea, 137 rx::PackPixelsParams *paramsOut, 138 GLuint *skipBytesOut); 139 140 angle::Result readPixels(rx::ContextWgpu *contextWgpu, 141 const gl::Rectangle &area, 142 const rx::PackPixelsParams &packPixelsParams, 143 void *pixels); 144 145 angle::Result createTextureView(gl::LevelIndex targetLevel, 146 uint32_t layerIndex, 147 wgpu::TextureView &textureViewOut); 148 LevelIndex toWgpuLevel(gl::LevelIndex levelIndexGl) const; 149 gl::LevelIndex toGlLevel(LevelIndex levelIndexWgpu) const; 150 bool isTextureLevelInAllocatedImage(gl::LevelIndex textureLevel); getTexture()151 wgpu::Texture &getTexture() { return mTexture; } toWgpuTextureFormat()152 wgpu::TextureFormat toWgpuTextureFormat() const { return mTextureDescriptor.format; } getIntendedFormatID()153 angle::FormatID getIntendedFormatID() { return mIntendedFormatID; } getActualFormatID()154 angle::FormatID getActualFormatID() { return mActualFormatID; } getTextureDescriptor()155 const wgpu::TextureDescriptor &getTextureDescriptor() const { return mTextureDescriptor; } getFirstAllocatedLevel()156 gl::LevelIndex getFirstAllocatedLevel() { return mFirstAllocatedLevel; } 157 gl::LevelIndex getLastAllocatedLevel(); getLevelCount()158 uint32_t getLevelCount() { return mTextureDescriptor.mipLevelCount; } getSize()159 wgpu::Extent3D getSize() { return mTextureDescriptor.size; } isInitialized()160 bool isInitialized() { return mInitialized; } 161 162 private: 163 void appendSubresourceUpdate(gl::LevelIndex level, SubresourceUpdate &&update); 164 std::vector<SubresourceUpdate> *getLevelUpdates(gl::LevelIndex level); 165 166 wgpu::Texture mTexture; 167 wgpu::TextureDescriptor mTextureDescriptor = {}; 168 bool mInitialized = false; 169 170 gl::LevelIndex mFirstAllocatedLevel = gl::LevelIndex(0); 171 angle::FormatID mIntendedFormatID; 172 angle::FormatID mActualFormatID; 173 174 std::vector<std::vector<SubresourceUpdate>> mSubresourceQueue; 175 }; 176 struct BufferMapState 177 { 178 wgpu::MapMode mode; 179 size_t offset; 180 size_t size; 181 }; 182 183 enum class MapAtCreation 184 { 185 No, 186 Yes, 187 }; 188 189 struct BufferReadback; 190 191 class BufferHelper : public angle::NonCopyable 192 { 193 public: 194 BufferHelper(); 195 ~BufferHelper(); 196 valid()197 bool valid() const { return mBuffer.operator bool(); } 198 void reset(); 199 200 angle::Result initBuffer(wgpu::Device device, 201 size_t size, 202 wgpu::BufferUsage usage, 203 MapAtCreation mappedAtCreation); 204 205 angle::Result mapImmediate(ContextWgpu *context, 206 wgpu::MapMode mode, 207 size_t offset, 208 size_t size); 209 angle::Result unmap(); 210 211 uint8_t *getMapWritePointer(size_t offset, size_t size) const; 212 const uint8_t *getMapReadPointer(size_t offset, size_t size) const; 213 214 const std::optional<BufferMapState> &getMappedState() const; 215 216 bool canMapForRead() const; 217 bool canMapForWrite() const; 218 219 wgpu::Buffer &getBuffer(); 220 uint64_t requestedSize() const; 221 uint64_t actualSize() const; 222 223 // Helper to copy data to a staging buffer and map it. Staging data is cleaned up by the 224 // BufferReadback RAII object. 225 angle::Result readDataImmediate(ContextWgpu *context, 226 size_t offset, 227 size_t size, 228 webgpu::RenderPassClosureReason reason, 229 BufferReadback *result); 230 231 private: 232 wgpu::Buffer mBuffer; 233 size_t mRequestedSize = 0; 234 235 std::optional<BufferMapState> mMappedState; 236 }; 237 238 struct BufferReadback 239 { 240 BufferHelper buffer; 241 const uint8_t *data = nullptr; 242 }; 243 244 } // namespace webgpu 245 } // namespace rx 246 #endif // LIBANGLE_RENDERER_WGPU_WGPU_HELPERS_H_ 247