bgfx/src/renderer_webgpu.h
Бранимир Караџић 4581f14cd4 Happy New Year!
2022-01-15 11:59:06 -08:00

569 lines
12 KiB
C++

/*
* Copyright 2011-2019 Branimir Karadzic. All rights reserved.
* License: https://github.com/bkaradzic/bgfx/blob/master/LICENSE
*/
#ifndef BGFX_RENDERER_WEBGPU_H_HEADER_GUARD
#define BGFX_RENDERER_WEBGPU_H_HEADER_GUARD
#include "bgfx_p.h"
#if BGFX_CONFIG_RENDERER_WEBGPU
#if !BX_PLATFORM_EMSCRIPTEN
# include <dawn/webgpu_cpp.h>
# include <dawn/dawn_wsi.h>
#else
# include <webgpu/webgpu_cpp.h>
#endif // !BX_PLATFORM_EMSCRIPTEN
#define BGFX_WEBGPU_PROFILER_BEGIN(_view, _abgr) \
BX_MACRO_BLOCK_BEGIN \
BGFX_PROFILER_BEGIN(s_viewName[view], _abgr); \
BX_MACRO_BLOCK_END
#define BGFX_WEBGPU_PROFILER_BEGIN_LITERAL(_name, _abgr) \
BX_MACRO_BLOCK_BEGIN \
BGFX_PROFILER_BEGIN_LITERAL("" # _name, _abgr); \
BX_MACRO_BLOCK_END
#define BGFX_WEBGPU_PROFILER_END() \
BX_MACRO_BLOCK_BEGIN \
BGFX_PROFILER_END(); \
BX_MACRO_BLOCK_END
#define WEBGPU_NUM_UNIFORM_BUFFERS 8
namespace bgfx { namespace webgpu
{
template <typename Ty>
class StateCacheT
{
public:
void add(uint64_t _id, Ty _item)
{
invalidate(_id);
m_hashMap.insert(stl::make_pair(_id, _item));
}
Ty find(uint64_t _id)
{
typename HashMap::iterator it = m_hashMap.find(_id);
if(it != m_hashMap.end())
{
return it->second;
}
return NULL;
}
void invalidate(uint64_t _id)
{
typename HashMap::iterator it = m_hashMap.find(_id);
if(it != m_hashMap.end())
{
release(it->second);
m_hashMap.erase(it);
}
}
void invalidate()
{
for(typename HashMap::iterator it = m_hashMap.begin(), itEnd = m_hashMap.end(); it != itEnd; ++it)
{
release(it->second);
}
m_hashMap.clear();
}
uint32_t getCount() const
{
return uint32_t(m_hashMap.size());
}
private:
typedef stl::unordered_map<uint64_t, Ty> HashMap;
HashMap m_hashMap;
};
struct BufferWgpu
{
void create(uint32_t _size, void* _data, uint16_t _flags, uint16_t _stride = 0, bool _vertex = false);
void update(uint32_t _offset, uint32_t _size, void* _data, bool _discard = false);
void destroy()
{
m_ptr.Destroy();
if(NULL != m_dynamic)
{
BX_DELETE(g_allocator, m_dynamic);
m_dynamic = NULL;
}
}
uint32_t m_size;
uint16_t m_flags = BGFX_BUFFER_NONE;
bool m_vertex;
String m_label;
wgpu::Buffer m_ptr;
uint8_t* m_dynamic = NULL;
};
struct IndexBufferWgpu : public BufferWgpu
{
void create(uint32_t _size, void* _data, uint16_t _flags);
wgpu::IndexFormat m_format;
};
struct VertexBufferWgpu : public BufferWgpu
{
void create(uint32_t _size, void* _data, VertexLayoutHandle _declHandle, uint16_t _flags);
VertexLayoutHandle m_layoutHandle;
};
struct BindInfo
{
uint32_t m_index = UINT32_MAX;
uint32_t m_binding = UINT32_MAX;
UniformHandle m_uniform = BGFX_INVALID_HANDLE;
};
struct ShaderWgpu
{
void create(ShaderHandle _handle, const Memory* _mem);
void destroy()
{
if (NULL != m_constantBuffer)
{
UniformBuffer::destroy(m_constantBuffer);
m_constantBuffer = NULL;
}
m_module = NULL;
}
const char* name() const { return getName(m_handle); }
ShaderHandle m_handle;
String m_label;
wgpu::ShaderStage m_stage;
wgpu::ShaderModule m_module;
uint32_t* m_code = NULL;
size_t m_codeSize = 0;
UniformBuffer* m_constantBuffer = NULL;
PredefinedUniform m_predefined[PredefinedUniform::Count];
uint16_t m_attrMask[Attrib::Count];
uint8_t m_attrRemap[Attrib::Count];
uint32_t m_hash = 0;
uint16_t m_numUniforms = 0;
uint16_t m_size = 0;
uint16_t m_gpuSize = 0;
uint8_t m_numPredefined = 0;
uint8_t m_numAttrs = 0;
BindInfo m_bindInfo[BGFX_CONFIG_MAX_TEXTURE_SAMPLERS];
wgpu::BindGroupLayoutEntry m_samplers[BGFX_CONFIG_MAX_TEXTURE_SAMPLERS];
wgpu::BindGroupLayoutEntry m_textures[BGFX_CONFIG_MAX_TEXTURE_SAMPLERS];
uint8_t m_numSamplers = 0;
wgpu::BindGroupLayoutEntry m_buffers[BGFX_CONFIG_MAX_TEXTURE_SAMPLERS];
uint32_t m_numBuffers = 0;
};
struct PipelineStateWgpu;
struct ProgramWgpu
{
void create(const ShaderWgpu* _vsh, const ShaderWgpu* _fsh);
void destroy();
const ShaderWgpu* m_vsh = NULL;
const ShaderWgpu* m_fsh = NULL;
PredefinedUniform m_predefined[PredefinedUniform::Count * 2];
uint8_t m_numPredefined;
PipelineStateWgpu* m_computePS = NULL;
wgpu::BindGroupLayout m_bindGroupLayout;
uint16_t m_gpuSize = 0;
uint32_t m_numUniforms;
uint32_t m_bindGroupLayoutHash;
BindInfo m_bindInfo[BGFX_CONFIG_MAX_TEXTURE_SAMPLERS];
wgpu::BindGroupLayoutEntry m_samplers[BGFX_CONFIG_MAX_TEXTURE_SAMPLERS];
wgpu::BindGroupLayoutEntry m_textures[BGFX_CONFIG_MAX_TEXTURE_SAMPLERS];
uint32_t m_numSamplers = 0;
wgpu::BindGroupLayoutEntry m_buffers[BGFX_CONFIG_MAX_TEXTURE_SAMPLERS];
uint32_t m_numBuffers = 0;
};
constexpr size_t kMaxVertexInputs = 16;
constexpr size_t kMaxVertexAttributes = 16;
constexpr size_t kMaxColorAttachments = BGFX_CONFIG_MAX_FRAME_BUFFER_ATTACHMENTS;
constexpr uint32_t kMinBufferOffsetAlignment = 256;
struct RenderPassDescriptor
{
RenderPassDescriptor();
wgpu::RenderPassDescriptor desc;
wgpu::RenderPassColorAttachment colorAttachments[kMaxColorAttachments];
wgpu::RenderPassDepthStencilAttachment depthStencilAttachment;
};
struct VertexStateDescriptor
{
VertexStateDescriptor();
wgpu::VertexState desc;
wgpu::VertexBufferLayoutDescriptor buffers[kMaxVertexInputs];
wgpu::VertexAttributeDescriptor attributes[kMaxVertexAttributes];
};
struct RenderPipelineDescriptor
{
RenderPipelineDescriptor();
wgpu::RenderPipelineDescriptor2 desc;
wgpu::FragmentState fragment;
wgpu::DepthStencilState depthStencil;
wgpu::ColorTargetState targets[kMaxColorAttachments];
wgpu::BlendState blends[kMaxColorAttachments];
};
struct BindingsWgpu
{
uint32_t numEntries = 0;
wgpu::BindGroupEntry m_entries[2 + BGFX_CONFIG_MAX_TEXTURE_SAMPLERS*3];
};
struct BindStateWgpu
{
void clear();
uint32_t numOffset;
wgpu::BindGroup m_bindGroup;
};
struct RenderPassStateWgpu
{
RenderPassDescriptor m_rpd;
};
struct PipelineStateWgpu
{
RenderPipelineDescriptor m_rpd;
wgpu::PipelineLayout m_layout;
wgpu::RenderPipeline m_rps;
wgpu::ComputePipeline m_cps;
};
void release(RenderPassStateWgpu* _ptr)
{
BX_DELETE(g_allocator, _ptr);
}
void release(PipelineStateWgpu* _ptr)
{
BX_DELETE(g_allocator, _ptr);
}
class StagingBufferWgpu
{
public:
void create(uint32_t _size, bool mapped);
void map();
void unmap();
void destroy();
void mapped(void* _data);
wgpu::Buffer m_buffer;
void* m_data = NULL;
uint64_t m_size = 0;
};
class ScratchBufferWgpu
{
public:
void create(uint32_t _size); // , uint32_t _maxBindGroups);
void destroy();
void begin();
uint32_t write(void* data, uint64_t _size, uint64_t _offset);
uint32_t write(void* data, uint64_t _size);
void submit();
void release();
StagingBufferWgpu* m_staging = NULL;
wgpu::Buffer m_buffer;
uint32_t m_offset;
uint32_t m_size;
uint8_t m_stagingIndex = 0;
};
class BindStateCacheWgpu
{
public:
void create(); // , uint32_t _maxBindGroups);
void destroy();
void reset();
BindStateWgpu m_bindStates[1024] = {};
uint32_t m_currentBindState;
//uint32_t m_maxBindStates;
};
struct ReadbackWgpu
{
void create(TextureHandle _texture) { m_texture = _texture; }
void destroy()
{
m_buffer.Destroy();
}
void readback(void const* data)
{
bx::memCopy(m_data, data, m_size);
m_buffer.Unmap();
m_mapped = false;
}
TextureHandle m_texture;
wgpu::Buffer m_buffer;
uint32_t m_mip = 0;
bool m_mapped = false;
void* m_data = NULL;
size_t m_size = 0;
};
struct TextureWgpu
{
enum Enum
{
Texture2D,
Texture3D,
TextureCube,
};
void create(TextureHandle _handle, const Memory* _mem, uint64_t _flags, uint8_t _skip);
void destroy()
{
m_ptr.Destroy();
}
void update(
uint8_t _side
, uint8_t _mip
, const Rect& _rect
, uint16_t _z
, uint16_t _depth
, uint16_t _pitch
, const Memory* _mem
);
TextureHandle m_handle;
String m_label;
wgpu::TextureView m_view;
wgpu::TextureView getTextureMipLevel(int _mip);
wgpu::Texture m_ptr;
wgpu::Texture m_ptrMsaa;
wgpu::TextureView m_ptrMips[14] = {};
wgpu::Sampler m_sampler;
uint64_t m_flags = 0;
uint32_t m_width = 0;
uint32_t m_height = 0;
uint32_t m_depth = 0;
uint8_t m_type;
TextureFormat::Enum m_requestedFormat;
TextureFormat::Enum m_textureFormat;
uint8_t m_numMips = 0;
uint8_t m_numLayers;
uint32_t m_numSides;
uint8_t m_sampleCount;
ReadbackWgpu m_readback;
};
struct SamplerStateWgpu
{
wgpu::Sampler m_sampler;
};
void release(SamplerStateWgpu* _ptr)
{
BX_DELETE(g_allocator, _ptr);
}
struct FrameBufferWgpu;
struct SwapChainWgpu
{
void init(wgpu::Device _device, void* _nwh, uint32_t _width, uint32_t _height);
void resize(FrameBufferWgpu& _frameBuffer, uint32_t _width, uint32_t _height, uint32_t _flags);
void flip();
wgpu::TextureView current();
#if !BX_PLATFORM_EMSCRIPTEN
DawnSwapChainImplementation m_impl;
#endif
wgpu::SwapChain m_swapChain;
wgpu::TextureView m_drawable;
wgpu::Texture m_backBufferColorMsaa;
wgpu::Texture m_backBufferDepth;
wgpu::TextureFormat m_colorFormat;
wgpu::TextureFormat m_depthFormat;
uint32_t m_maxAnisotropy = 0;
uint8_t m_sampleCount;
};
struct FrameBufferWgpu
{
void create(uint8_t _num, const Attachment* _attachment);
bool create(
uint16_t _denseIdx
, void* _nwh
, uint32_t _width
, uint32_t _height
, TextureFormat::Enum _format
, TextureFormat::Enum _depthFormat
);
void postReset();
uint16_t destroy();
SwapChainWgpu* m_swapChain = NULL;
void* m_nwh = NULL;
uint32_t m_width;
uint32_t m_height;
uint16_t m_denseIdx = UINT16_MAX;
uint32_t m_pixelFormatHash = 0;
TextureHandle m_colorHandle[BGFX_CONFIG_MAX_FRAME_BUFFER_ATTACHMENTS - 1];
TextureHandle m_depthHandle = { kInvalidHandle };
Attachment m_colorAttachment[BGFX_CONFIG_MAX_FRAME_BUFFER_ATTACHMENTS - 1];
Attachment m_depthAttachment;
uint8_t m_num = 0; // number of color handles
};
struct CommandQueueWgpu
{
void init(wgpu::Queue _queue);
void shutdown();
void beginRender();
void beginStaging();
void kick(bool _endFrame, bool _waitForFinish = false);
void finish(bool _finishAll = false);
void release(wgpu::Buffer _buffer);
void consume();
#if BGFX_CONFIG_MULTITHREADED
//bx::Semaphore m_framesSemaphore;
#endif
wgpu::Queue m_queue;
wgpu::CommandEncoder m_stagingEncoder;
wgpu::CommandEncoder m_renderEncoder;
int m_releaseWriteIndex = 0;
int m_releaseReadIndex = 0;
typedef stl::vector<wgpu::Buffer> ResourceArray;
ResourceArray m_release[BGFX_CONFIG_MAX_FRAME_LATENCY];
};
struct TimerQueryWgpu
{
TimerQueryWgpu()
: m_control(4)
{
}
void init();
void shutdown();
uint32_t begin(uint32_t _resultIdx);
void end(uint32_t _idx);
void addHandlers(wgpu::CommandBuffer& _commandBuffer);
bool get();
struct Result
{
void reset()
{
m_begin = 0;
m_end = 0;
m_pending = 0;
}
uint64_t m_begin;
uint64_t m_end;
uint32_t m_pending;
};
uint64_t m_begin;
uint64_t m_end;
uint64_t m_elapsed;
uint64_t m_frequency;
Result m_result[4 * 2];
bx::RingBufferControl m_control;
};
struct OcclusionQueryWgpu
{
OcclusionQueryWgpu()
: m_control(BX_COUNTOF(m_query))
{
}
void postReset();
void preReset();
void begin(wgpu::RenderPassEncoder& _rce, Frame* _render, OcclusionQueryHandle _handle);
void end(wgpu::RenderPassEncoder& _rce);
void resolve(Frame* _render, bool _wait = false);
void invalidate(OcclusionQueryHandle _handle);
struct Query
{
OcclusionQueryHandle m_handle;
};
wgpu::Buffer m_buffer;
Query m_query[BGFX_CONFIG_MAX_OCCLUSION_QUERIES];
bx::RingBufferControl m_control;
};
} /* namespace webgpu */ } // namespace bgfx
#endif // BGFX_CONFIG_RENDERER_WEBGPU
#endif // BGFX_RENDERER_WEBGPU_H_HEADER_GUARD