blob: 77cacd08aa734cc495ec4792dcd32ac8fed4ceb7 [file] [log] [blame]
//
// Copyright 2024 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
#ifndef LIBANGLE_RENDERER_WGPU_WGPU_HELPERS_H_
#define LIBANGLE_RENDERER_WGPU_WGPU_HELPERS_H_
#include <dawn/webgpu_cpp.h>
#include <stdint.h>
#include <algorithm>
#include "libANGLE/Error.h"
#include "libANGLE/ImageIndex.h"
#include "libANGLE/angletypes.h"
#include "libANGLE/renderer/wgpu/ContextWgpu.h"
#include "libANGLE/renderer/wgpu/wgpu_utils.h"
namespace rx
{
class ContextWgpu;
namespace webgpu
{
// WebGPU requires copy buffers bytesPerRow to be aligned to 256.
// https://www.w3.org/TR/webgpu/#abstract-opdef-validating-gputexelcopybufferinfo
static const GLuint kCopyBufferAlignment = 256;
enum class UpdateSource
{
Clear,
Texture,
};
struct ClearUpdate
{
ClearValues clearValues;
bool hasDepth;
bool hasStencil;
};
struct SubresourceUpdate
{
SubresourceUpdate() {}
~SubresourceUpdate() {}
SubresourceUpdate(UpdateSource targetUpdateSource,
gl::LevelIndex newTargetLevel,
wgpu::TexelCopyBufferInfo targetBuffer)
{
updateSource = targetUpdateSource;
textureData = targetBuffer;
targetLevel = newTargetLevel;
}
SubresourceUpdate(UpdateSource targetUpdateSource,
gl::LevelIndex newTargetLevel,
ClearValues clearValues,
bool hasDepth,
bool hasStencil)
{
updateSource = targetUpdateSource;
targetLevel = newTargetLevel;
clearData.clearValues = clearValues;
clearData.hasDepth = hasDepth;
clearData.hasStencil = hasStencil;
}
UpdateSource updateSource;
ClearUpdate clearData;
wgpu::TexelCopyBufferInfo textureData;
gl::LevelIndex targetLevel;
};
wgpu::TextureDimension toWgpuTextureDimension(gl::TextureType glTextureType);
class ImageHelper
{
public:
ImageHelper();
~ImageHelper();
angle::Result initImage(angle::FormatID intendedFormatID,
angle::FormatID actualFormatID,
wgpu::Device &device,
gl::LevelIndex firstAllocatedLevel,
wgpu::TextureDescriptor textureDescriptor);
angle::Result initExternal(angle::FormatID intendedFormatID,
angle::FormatID actualFormatID,
wgpu::Texture externalTexture);
angle::Result flushStagedUpdates(ContextWgpu *contextWgpu);
angle::Result flushSingleLevelUpdates(ContextWgpu *contextWgpu,
gl::LevelIndex levelGL,
ClearValuesArray *deferredClears,
uint32_t deferredClearIndex);
wgpu::TextureDescriptor createTextureDescriptor(wgpu::TextureUsage usage,
wgpu::TextureDimension dimension,
wgpu::Extent3D size,
wgpu::TextureFormat format,
std::uint32_t mipLevelCount,
std::uint32_t sampleCount);
angle::Result stageTextureUpload(ContextWgpu *contextWgpu,
const webgpu::Format &webgpuFormat,
GLenum type,
const gl::Extents &glExtents,
GLuint inputRowPitch,
GLuint inputDepthPitch,
uint32_t outputRowPitch,
uint32_t outputDepthPitch,
uint32_t allocationSize,
const gl::ImageIndex &index,
const uint8_t *pixels);
void stageClear(gl::LevelIndex targetLevel,
ClearValues clearValues,
bool hasDepth,
bool hasStencil);
void removeStagedUpdates(gl::LevelIndex levelToRemove);
void resetImage();
static angle::Result getReadPixelsParams(rx::ContextWgpu *contextWgpu,
const gl::PixelPackState &packState,
gl::Buffer *packBuffer,
GLenum format,
GLenum type,
const gl::Rectangle &area,
const gl::Rectangle &clippedArea,
rx::PackPixelsParams *paramsOut,
GLuint *skipBytesOut);
angle::Result readPixels(rx::ContextWgpu *contextWgpu,
const gl::Rectangle &area,
const rx::PackPixelsParams &packPixelsParams,
void *pixels);
angle::Result createTextureView(gl::LevelIndex targetLevel,
uint32_t layerIndex,
wgpu::TextureView &textureViewOut);
LevelIndex toWgpuLevel(gl::LevelIndex levelIndexGl) const;
gl::LevelIndex toGlLevel(LevelIndex levelIndexWgpu) const;
bool isTextureLevelInAllocatedImage(gl::LevelIndex textureLevel);
wgpu::Texture &getTexture() { return mTexture; }
wgpu::TextureFormat toWgpuTextureFormat() const { return mTextureDescriptor.format; }
angle::FormatID getIntendedFormatID() { return mIntendedFormatID; }
angle::FormatID getActualFormatID() { return mActualFormatID; }
const wgpu::TextureDescriptor &getTextureDescriptor() const { return mTextureDescriptor; }
gl::LevelIndex getFirstAllocatedLevel() { return mFirstAllocatedLevel; }
gl::LevelIndex getLastAllocatedLevel();
uint32_t getLevelCount() { return mTextureDescriptor.mipLevelCount; }
wgpu::Extent3D getSize() { return mTextureDescriptor.size; }
bool isInitialized() { return mInitialized; }
private:
void appendSubresourceUpdate(gl::LevelIndex level, SubresourceUpdate &&update);
std::vector<SubresourceUpdate> *getLevelUpdates(gl::LevelIndex level);
wgpu::Texture mTexture;
wgpu::TextureDescriptor mTextureDescriptor = {};
bool mInitialized = false;
gl::LevelIndex mFirstAllocatedLevel = gl::LevelIndex(0);
angle::FormatID mIntendedFormatID;
angle::FormatID mActualFormatID;
std::vector<std::vector<SubresourceUpdate>> mSubresourceQueue;
};
struct BufferMapState
{
wgpu::MapMode mode;
size_t offset;
size_t size;
};
enum class MapAtCreation
{
No,
Yes,
};
struct BufferReadback;
class BufferHelper : public angle::NonCopyable
{
public:
BufferHelper();
~BufferHelper();
bool valid() const { return mBuffer.operator bool(); }
void reset();
angle::Result initBuffer(wgpu::Device device,
size_t size,
wgpu::BufferUsage usage,
MapAtCreation mappedAtCreation);
angle::Result mapImmediate(ContextWgpu *context,
wgpu::MapMode mode,
size_t offset,
size_t size);
angle::Result unmap();
uint8_t *getMapWritePointer(size_t offset, size_t size) const;
const uint8_t *getMapReadPointer(size_t offset, size_t size) const;
const std::optional<BufferMapState> &getMappedState() const;
bool canMapForRead() const;
bool canMapForWrite() const;
wgpu::Buffer &getBuffer();
uint64_t requestedSize() const;
uint64_t actualSize() const;
// Helper to copy data to a staging buffer and map it. Staging data is cleaned up by the
// BufferReadback RAII object.
angle::Result readDataImmediate(ContextWgpu *context,
size_t offset,
size_t size,
webgpu::RenderPassClosureReason reason,
BufferReadback *result);
private:
wgpu::Buffer mBuffer;
size_t mRequestedSize = 0;
std::optional<BufferMapState> mMappedState;
};
struct BufferReadback
{
BufferHelper buffer;
const uint8_t *data = nullptr;
};
} // namespace webgpu
} // namespace rx
#endif // LIBANGLE_RENDERER_WGPU_WGPU_HELPERS_H_