/* * 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 # include #else # include #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 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 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 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, uint32_t _frameNum); 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; m_frameNum = 0; } uint64_t m_begin; uint64_t m_end; uint32_t m_pending; uint32_t m_frameNum; // TODO: implement (currently stays 0) }; 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