diff --git a/bindings/bf/bgfx.bf b/bindings/bf/bgfx.bf index 3ba599650..7e22aa25f 100644 --- a/bindings/bf/bgfx.bf +++ b/bindings/bf/bgfx.bf @@ -3906,6 +3906,20 @@ public static class bgfx [LinkName("bgfx_update_texture_cube")] public static extern void update_texture_cube(TextureHandle _handle, uint16 _layer, uint8 _side, uint8 _mip, uint16 _x, uint16 _y, uint16 _width, uint16 _height, Memory* _mem, uint16 _pitch); + /// + /// Clear a texture subresource range to zero. + /// + /// + /// + /// Texture handle. + /// First mip level. + /// Number of mip levels. + /// First array layer (or 3D depth slice base). + /// Number of layers. + /// + [LinkName("bgfx_clear_texture")] + public static extern void clear_texture(TextureHandle _handle, uint8 _mip, uint8 _numMips, uint16 _layer, uint16 _numLayers); + /// /// Read back texture content. /// diff --git a/bindings/c3/bgfx.c3 b/bindings/c3/bgfx.c3 index 0fadae4e5..00bd61818 100644 --- a/bindings/c3/bgfx.c3 +++ b/bindings/c3/bgfx.c3 @@ -2823,6 +2823,15 @@ extern fn void update_texture_3d(TextureHandle _handle, char _mip, ushort _x, us // _pitch : `Pitch of input image (bytes). When _pitch is set to UINT16_MAX, it will be calculated internally based on _width.` extern fn void update_texture_cube(TextureHandle _handle, ushort _layer, char _side, char _mip, ushort _x, ushort _y, ushort _width, ushort _height, Memory* _mem, ushort _pitch) @cname("bgfx_update_texture_cube"); +// Clear a texture subresource range to zero. +// +// _handle : `Texture handle.` +// _mip : `First mip level.` +// _numMips : `Number of mip levels.` +// _layer : `First array layer (or 3D depth slice base).` +// _numLayers : `Number of layers.` +extern fn void clear_texture(TextureHandle _handle, char _mip, char _numMips, ushort _layer, ushort _numLayers) @cname("bgfx_clear_texture"); + // Read back texture content. // // @attention Texture must be created with `BGFX_TEXTURE_READ_BACK` flag. diff --git a/bindings/cs/bgfx.cs b/bindings/cs/bgfx.cs index d3a3b9446..1428011aa 100644 --- a/bindings/cs/bgfx.cs +++ b/bindings/cs/bgfx.cs @@ -3856,6 +3856,20 @@ public static partial class bgfx [DllImport(DllName, EntryPoint="bgfx_update_texture_cube", CallingConvention = CallingConvention.Cdecl)] public static extern unsafe void update_texture_cube(TextureHandle _handle, ushort _layer, byte _side, byte _mip, ushort _x, ushort _y, ushort _width, ushort _height, Memory* _mem, ushort _pitch); + /// + /// Clear a texture subresource range to zero. + /// + /// + /// + /// Texture handle. + /// First mip level. + /// Number of mip levels. + /// First array layer (or 3D depth slice base). + /// Number of layers. + /// + [DllImport(DllName, EntryPoint="bgfx_clear_texture", CallingConvention = CallingConvention.Cdecl)] + public static extern unsafe void clear_texture(TextureHandle _handle, byte _mip, byte _numMips, ushort _layer, ushort _numLayers); + /// /// Read back texture content. /// diff --git a/bindings/d/package.d b/bindings/d/package.d index 884630724..9af53d296 100644 --- a/bindings/d/package.d +++ b/bindings/d/package.d @@ -9,7 +9,7 @@ import bindbc.common.types: c_int64, c_uint64, va_list; import bindbc.bgfx.config; static import bgfx.impl; -enum uint apiVersion = 150; +enum uint apiVersion = 151; alias ViewID = ushort; @@ -3038,6 +3038,18 @@ mixin(joinFnBinds((){ */ {q{void}, q{updateTextureCube}, q{TextureHandle handle, ushort layer, ubyte side, ubyte mip, ushort x, ushort y, ushort width, ushort height, const(Memory)* mem, ushort pitch=ushort.max}, ext: `C++, "bgfx"`}, + /** + * Clear a texture subresource range to zero. + * + Params: + handle = Texture handle. + mip = First mip level. + numMIPs = Number of mip levels. + layer = First array layer (or 3D depth slice base). + numLayers = Number of layers. + */ + {q{void}, q{clear}, q{TextureHandle handle, ubyte mip=0, ubyte numMIPs=ubyte.max, ushort layer=0, ushort numLayers=ushort.max}, ext: `C++, "bgfx"`}, + /** * Read back texture content. * diff --git a/bindings/zig/bgfx.zig b/bindings/zig/bgfx.zig index 77c8c10d1..bfdd06536 100644 --- a/bindings/zig/bgfx.zig +++ b/bindings/zig/bgfx.zig @@ -3060,6 +3060,18 @@ pub inline fn updateTextureCube(_handle: TextureHandle, _layer: u16, _side: u8, } extern fn bgfx_update_texture_cube(_handle: TextureHandle, _layer: u16, _side: u8, _mip: u8, _x: u16, _y: u16, _width: u16, _height: u16, _mem: [*c]const Memory, _pitch: u16) void; +/// Clear a texture subresource range to zero. +/// +/// Texture handle. +/// First mip level. +/// Number of mip levels. +/// First array layer (or 3D depth slice base). +/// Number of layers. +pub inline fn clearTexture(_handle: TextureHandle, _mip: u8, _numMips: u8, _layer: u16, _numLayers: u16) void { + return bgfx_clear_texture(_handle, _mip, _numMips, _layer, _numLayers); +} +extern fn bgfx_clear_texture(_handle: TextureHandle, _mip: u8, _numMips: u8, _layer: u16, _numLayers: u16) void; + /// Read back texture content. /// /// @attention Texture must be created with `BGFX_TEXTURE_READ_BACK` flag. diff --git a/docs/bgfx.rst b/docs/bgfx.rst index d80402b4f..9e82f7226 100644 --- a/docs/bgfx.rst +++ b/docs/bgfx.rst @@ -631,6 +631,7 @@ Textures .. doxygenfunction:: bgfx::updateTexture2D .. doxygenfunction:: bgfx::updateTexture3D .. doxygenfunction:: bgfx::updateTextureCube +.. doxygenfunction:: bgfx::clear .. doxygenfunction:: bgfx::readTexture .. doxygenfunction:: bgfx::getDirectAccessPtr .. doxygenfunction:: bgfx::destroy(TextureHandle _handle) diff --git a/examples/08-update/update.cpp b/examples/08-update/update.cpp index cb1dd74e1..e335790ef 100644 --- a/examples/08-update/update.cpp +++ b/examples/08-update/update.cpp @@ -232,6 +232,7 @@ bgfx::TextureHandle loadTextureWithUpdate(const char* _filePath, uint64_t _flags } static const uint16_t kTextureSide = 512; +static const uint32_t kClearCubeAfterAllocations = 1024; static const uint32_t kTexture2dSize = 256; class ExampleUpdate : public entry::AppI @@ -471,6 +472,7 @@ public: m_hit = 0; m_miss = 0; + m_lastClearHit = 0; imguiCreate(); @@ -629,6 +631,15 @@ public: if (bx::getNow() > m_updateTime) { + if (m_hit - m_lastClearHit >= kClearCubeAfterAllocations) + { + bgfx::clear(m_textureCube[0]); + bgfx::clear(m_textureCube[1]); + m_cube.reset(kTextureSide); + m_quads.clear(); + m_lastClearHit = m_hit; + } + PackCube face; uint16_t bw = bx::max(1, m_rng.gen()%(kTextureSide/4) ); @@ -1082,6 +1093,7 @@ public: uint32_t m_hit; uint32_t m_miss; + uint32_t m_lastClearHit; uint8_t m_rr; uint8_t m_gg; diff --git a/include/bgfx/bgfx.h b/include/bgfx/bgfx.h index ee59b8532..9b437384a 100644 --- a/include/bgfx/bgfx.h +++ b/include/bgfx/bgfx.h @@ -3315,6 +3315,24 @@ namespace bgfx , uint16_t _pitch = UINT16_MAX ); + /// Clear a texture subresource range to zero. + /// + /// @param[in] _handle Texture handle. + /// @param[in] _mip First mip level. + /// @param[in] _numMips Number of mip levels. + /// @param[in] _layer First array layer (or 3D depth slice base). + /// @param[in] _numLayers Number of layers. + /// + /// @attention C99's equivalent binding is `bgfx_clear_texture`. + /// + void clear( + TextureHandle _handle + , uint8_t _mip = 0 + , uint8_t _numMips = UINT8_MAX + , uint16_t _layer = 0 + , uint16_t _numLayers = UINT16_MAX + ); + /// Read back texture content. /// /// @param[in] _handle Texture handle. diff --git a/include/bgfx/c99/bgfx.h b/include/bgfx/c99/bgfx.h index f3b87c362..56dc6598e 100644 --- a/include/bgfx/c99/bgfx.h +++ b/include/bgfx/c99/bgfx.h @@ -2220,6 +2220,18 @@ BGFX_C_API void bgfx_update_texture_3d(bgfx_texture_handle_t _handle, uint8_t _m */ BGFX_C_API void bgfx_update_texture_cube(bgfx_texture_handle_t _handle, uint16_t _layer, uint8_t _side, uint8_t _mip, uint16_t _x, uint16_t _y, uint16_t _width, uint16_t _height, const bgfx_memory_t* _mem, uint16_t _pitch); +/** + * Clear a texture subresource range to zero. + * + * @param[in] _handle Texture handle. + * @param[in] _mip First mip level. + * @param[in] _numMips Number of mip levels. + * @param[in] _layer First array layer (or 3D depth slice base). + * @param[in] _numLayers Number of layers. + * + */ +BGFX_C_API void bgfx_clear_texture(bgfx_texture_handle_t _handle, uint8_t _mip, uint8_t _numMips, uint16_t _layer, uint16_t _numLayers); + /** * Read back texture content. * @@ -4063,6 +4075,7 @@ typedef enum bgfx_function_id BGFX_FUNCTION_ID_UPDATE_TEXTURE_2D, BGFX_FUNCTION_ID_UPDATE_TEXTURE_3D, BGFX_FUNCTION_ID_UPDATE_TEXTURE_CUBE, + BGFX_FUNCTION_ID_CLEAR_TEXTURE, BGFX_FUNCTION_ID_READ_TEXTURE, BGFX_FUNCTION_ID_SET_TEXTURE_NAME, BGFX_FUNCTION_ID_GET_DIRECT_ACCESS_PTR, @@ -4277,6 +4290,7 @@ struct bgfx_interface_vtbl void (*update_texture_2d)(bgfx_texture_handle_t _handle, uint16_t _layer, uint8_t _mip, uint16_t _x, uint16_t _y, uint16_t _width, uint16_t _height, const bgfx_memory_t* _mem, uint16_t _pitch); void (*update_texture_3d)(bgfx_texture_handle_t _handle, uint8_t _mip, uint16_t _x, uint16_t _y, uint16_t _z, uint16_t _width, uint16_t _height, uint16_t _depth, const bgfx_memory_t* _mem); void (*update_texture_cube)(bgfx_texture_handle_t _handle, uint16_t _layer, uint8_t _side, uint8_t _mip, uint16_t _x, uint16_t _y, uint16_t _width, uint16_t _height, const bgfx_memory_t* _mem, uint16_t _pitch); + void (*clear_texture)(bgfx_texture_handle_t _handle, uint8_t _mip, uint8_t _numMips, uint16_t _layer, uint16_t _numLayers); uint32_t (*read_texture)(bgfx_texture_handle_t _handle, void* _data, uint16_t _layer, uint8_t _mip); void (*set_texture_name)(bgfx_texture_handle_t _handle, const char* _name, int32_t _len); void* (*get_direct_access_ptr)(bgfx_texture_handle_t _handle); diff --git a/include/bgfx/defines.h b/include/bgfx/defines.h index ef65b27dc..995e9bbed 100644 --- a/include/bgfx/defines.h +++ b/include/bgfx/defines.h @@ -15,7 +15,7 @@ #ifndef BGFX_DEFINES_H_HEADER_GUARD #define BGFX_DEFINES_H_HEADER_GUARD -#define BGFX_API_VERSION UINT32_C(150) +#define BGFX_API_VERSION UINT32_C(151) /** * Color RGB/alpha/depth write. When it's not specified write will be disabled. diff --git a/scripts/bgfx.idl b/scripts/bgfx.idl index df405e623..63da2c904 100644 --- a/scripts/bgfx.idl +++ b/scripts/bgfx.idl @@ -1,7 +1,7 @@ -- vim: syntax=lua -- bgfx interface -version(150) +version(151) typedef "bool" typedef "char" @@ -2023,6 +2023,20 @@ func.updateTextureCube { section = "Textures" } --- UINT16_MAX, it will be calculated internally based on _width. { default = UINT16_MAX } +--- Clear a texture subresource range to zero. +--- +func.clear { cname = "clear_texture", section = "Textures" } + "void" + .handle "TextureHandle" --- Texture handle. + .mip "uint8_t" --- First mip level. + { default = 0 } + .numMips "uint8_t" --- Number of mip levels. + { default = UINT8_MAX } + .layer "uint16_t" --- First array layer (or 3D depth slice base). + { default = 0 } + .numLayers "uint16_t" --- Number of layers. + { default = UINT16_MAX } + --- Read back texture content. --- --- @attention Texture must be created with `BGFX_TEXTURE_READ_BACK` flag. diff --git a/src/bgfx.cpp b/src/bgfx.cpp index d624e7753..8d4bd4d96 100644 --- a/src/bgfx.cpp +++ b/src/bgfx.cpp @@ -3722,6 +3722,31 @@ namespace bgfx } break; + case CommandBuffer::ClearTexture: + { + BGFX_PROFILER_SCOPE("ClearTexture", kColorResource); + + TextureHandle handle; + _cmdbuf.read(handle); + + uint8_t mip; + _cmdbuf.read(mip); + + uint8_t numMips; + _cmdbuf.read(numMips); + + uint16_t layer; + _cmdbuf.read(layer); + + uint16_t numLayers; + _cmdbuf.read(numLayers); + + flushTextureUpdateBatch(_cmdbuf); + + m_renderCtx->clearTexture(handle, mip, numMips, layer, numLayers); + } + break; + case CommandBuffer::ReadTexture: { BGFX_PROFILER_SCOPE("ReadTexture", kColorResource); @@ -5838,6 +5863,32 @@ namespace bgfx return s_ctx->readTexture(_handle, _data, _layer, _mip); } + void clear(TextureHandle _handle, uint8_t _mip, uint8_t _numMips, uint16_t _layer, uint16_t _numLayers) + { + BGFX_CHECK_HANDLE("clearTexture", s_ctx->m_textureHandle, _handle); + + const TextureRef& ref = s_ctx->m_textureRef[_handle.idx]; + + BX_ASSERT(!ref.isDepth() + , "Texture (handle %d, '%S') has a depth/stencil format and can't be cleared; use a view depth clear instead." + , _handle.idx + , &ref.m_name + ); + BX_ASSERT(!bimg::isCompressed(bimg::TextureFormat::Enum(ref.m_format) ) + , "Texture (handle %d, '%S', %s) is compressed and can't be cleared." + , _handle.idx + , &ref.m_name + , bimg::getName(bimg::TextureFormat::Enum(ref.m_format) ) + ); + BX_ASSERT( (ref.m_flags & BGFX_TEXTURE_RT_MSAA_MASK) <= BGFX_TEXTURE_RT + , "Texture (handle %d, '%S') is multisampled and can't be cleared; use a view clear instead." + , _handle.idx + , &ref.m_name + ); + + s_ctx->clearTexture(_handle, _mip, _numMips, _layer, _numLayers); + } + FrameBufferHandle createFrameBuffer(uint16_t _width, uint16_t _height, TextureFormat::Enum _format, uint64_t _textureFlags) { _textureFlags |= _textureFlags&BGFX_TEXTURE_RT_MSAA_MASK ? 0 : BGFX_TEXTURE_RT; diff --git a/src/bgfx.idl.inl b/src/bgfx.idl.inl index 6bb0b1db0..46765222d 100644 --- a/src/bgfx.idl.inl +++ b/src/bgfx.idl.inl @@ -516,6 +516,12 @@ BGFX_C_API void bgfx_update_texture_cube(bgfx_texture_handle_t _handle, uint16_t bgfx::updateTextureCube(handle.cpp, _layer, _side, _mip, _x, _y, _width, _height, (const bgfx::Memory*)_mem, _pitch); } +BGFX_C_API void bgfx_clear_texture(bgfx_texture_handle_t _handle, uint8_t _mip, uint8_t _numMips, uint16_t _layer, uint16_t _numLayers) +{ + union { bgfx_texture_handle_t c; bgfx::TextureHandle cpp; } handle = { _handle }; + bgfx::clear(handle.cpp, _mip, _numMips, _layer, _numLayers); +} + BGFX_C_API uint32_t bgfx_read_texture(bgfx_texture_handle_t _handle, void* _data, uint16_t _layer, uint8_t _mip) { union { bgfx_texture_handle_t c; bgfx::TextureHandle cpp; } handle = { _handle }; @@ -1427,6 +1433,7 @@ BGFX_C_API bgfx_interface_vtbl_t* bgfx_get_interface(uint32_t _version) bgfx_update_texture_2d, bgfx_update_texture_3d, bgfx_update_texture_cube, + bgfx_clear_texture, bgfx_read_texture, bgfx_set_texture_name, bgfx_get_direct_access_ptr, diff --git a/src/bgfx_p.h b/src/bgfx_p.h index f7f82bfb3..d0cf4eb82 100644 --- a/src/bgfx_p.h +++ b/src/bgfx_p.h @@ -643,6 +643,21 @@ namespace bgfx release( (const Memory*)_mem); } + static constexpr uint32_t kTextureZeroInitBudget = 64<<10; + + inline constexpr uint32_t textureZeroInitTileDim(uint32_t _bpp, uint32_t _budget = kTextureZeroInitBudget) + { + uint32_t dim = 512; + + while (dim > 1 + && uint64_t(dim)*dim*_bpp/8 > _budget) + { + dim >>= 1; + } + + return dim; + } + static_assert(BGFX_STENCIL_NONE == BGFX_STENCIL_FUNC_RMASK_MASK, ""); inline constexpr uint64_t packStencil(uint32_t _fstencil, uint32_t _bstencil) @@ -1057,6 +1072,7 @@ namespace bgfx CreateProgram, CreateTexture, UpdateTexture, + ClearTexture, ResizeTexture, CreateFrameBuffer, CreateUniform, @@ -4186,6 +4202,7 @@ namespace bgfx virtual void destroyProgram(ProgramHandle _handle) = 0; virtual void* createTexture(TextureHandle _handle, const Memory* _mem, uint64_t _flags, uint8_t _skip, uint64_t _external) = 0; virtual void updateTexture(TextureHandle _handle, uint8_t _side, uint8_t _mip, const Rect& _rect, uint16_t _z, uint16_t _depth, uint16_t _pitch, const Memory* _mem) = 0; + virtual void clearTexture(TextureHandle _handle, uint8_t _mip, uint8_t _numMips, uint16_t _layer, uint16_t _numLayers) = 0; virtual void readTexture(TextureHandle _handle, void* _data, uint16_t _layer, uint8_t _mip) = 0; virtual void resizeTexture(TextureHandle _handle, uint16_t _width, uint16_t _height, uint8_t _numMips, uint16_t _numLayers) = 0; virtual void overrideInternal(TextureHandle _handle, uintptr_t _ptr, uint16_t _layerIndex) = 0; @@ -5880,6 +5897,18 @@ namespace bgfx cmdbuf.write(_mem); } + BGFX_API_FUNC(void clearTexture(TextureHandle _handle, uint8_t _mip, uint8_t _numMips, uint16_t _layer, uint16_t _numLayers) ) + { + BGFX_MUTEX_SCOPE(m_resourceApiLock); + + CommandBuffer& cmdbuf = getCommandBuffer(CommandBuffer::ClearTexture); + cmdbuf.write(_handle); + cmdbuf.write(_mip); + cmdbuf.write(_numMips); + cmdbuf.write(_layer); + cmdbuf.write(_numLayers); + } + BGFX_API_FUNC(FrameBufferHandle createFrameBuffer(uint8_t _num, const Attachment* _attachment, bool _destroyTextures) ) { BGFX_MUTEX_SCOPE(m_resourceApiLock); diff --git a/src/glimports.h b/src/glimports.h index 0647c9a00..4597afcb7 100644 --- a/src/glimports.h +++ b/src/glimports.h @@ -207,6 +207,7 @@ typedef void (GL_APIENTRYP PFNGLTEXSTORAGE2DPROC) (GLenum target, GLsi typedef void (GL_APIENTRYP PFNGLTEXSTORAGE3DPROC) (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth); typedef void (GL_APIENTRYP PFNGLTEXSUBIMAGE2DPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels); typedef void (GL_APIENTRYP PFNGLTEXSUBIMAGE3DPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void *pixels); +typedef void (GL_APIENTRYP PFNGLCLEARTEXSUBIMAGEPROC) (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void *data); typedef void (GL_APIENTRYP PFNGLTEXTUREVIEWPROC) (GLuint texture, GLenum target, GLuint origtexture, GLenum internalformat, GLuint minlevel, GLuint numlevels, GLuint minlayer, GLuint numlayers); typedef void (GL_APIENTRYP PFNGLUNIFORM1FPROC) (GLint location, GLfloat v0); typedef void (GL_APIENTRYP PFNGLUNIFORM1FVPROC) (GLint location, GLsizei count, const GLfloat *value); @@ -412,6 +413,7 @@ GL_IMPORT______(true, PFNGLTEXSTORAGE2DPROC, glTexStorage2 GL_IMPORT______(true, PFNGLTEXSTORAGE3DPROC, glTexStorage3D); GL_IMPORT______(false, PFNGLTEXSUBIMAGE2DPROC, glTexSubImage2D); GL_IMPORT______(true, PFNGLTEXSUBIMAGE3DPROC, glTexSubImage3D); +GL_IMPORT______(true, PFNGLCLEARTEXSUBIMAGEPROC, glClearTexSubImage); GL_IMPORT______(true, PFNGLTEXTUREVIEWPROC, glTextureView); GL_IMPORT______(false, PFNGLUNIFORM1IPROC, glUniform1i); GL_IMPORT______(false, PFNGLUNIFORM1IVPROC, glUniform1iv); @@ -542,6 +544,7 @@ GL_IMPORT_OES__(true, PFNGLCOMPRESSEDTEXSUBIMAGE3DPROC, glCompressedT GL_IMPORT_EXT__(true, PFNGLTEXSTORAGE2DPROC, glTexStorage2D); GL_IMPORT_EXT__(true, PFNGLTEXSTORAGE3DPROC, glTexStorage3D); +GL_IMPORT_EXT__(true, PFNGLCLEARTEXSUBIMAGEPROC, glClearTexSubImage); GL_IMPORT_EXT__(true, PFNGLTEXTUREVIEWPROC, glTextureView); GL_IMPORT______(true, PFNGLTEXIMAGE2DMULTISAMPLEPROC, glTexImage2DMultisample); @@ -638,6 +641,7 @@ GL_IMPORT______(true, PFNGLCOMPRESSEDTEXSUBIMAGE3DPROC, glCompressedT GL_IMPORT______(true, PFNGLTEXSTORAGE2DPROC, glTexStorage2D); GL_IMPORT______(true, PFNGLTEXSTORAGE3DPROC, glTexStorage3D); +GL_IMPORT______(true, PFNGLCLEARTEXSUBIMAGEPROC, glClearTexSubImage); GL_IMPORT______(true, PFNGLTEXTUREVIEWPROC, glTextureView); GL_IMPORT______(true, PFNGLTEXIMAGE2DMULTISAMPLEPROC, glTexImage2DMultisample); GL_IMPORT______(true, PFNGLTEXIMAGE3DMULTISAMPLEPROC, glTexImage3DMultisample); diff --git a/src/renderer_d3d11.cpp b/src/renderer_d3d11.cpp index 10be8e10b..8695acc4c 100644 --- a/src/renderer_d3d11.cpp +++ b/src/renderer_d3d11.cpp @@ -707,6 +707,8 @@ namespace bgfx { namespace d3d11 int WINAPI d3d11Annotation_EndEvent(); void WINAPI d3d11Annotation_SetMarker(DWORD _color, LPCWSTR _name); + struct TextureD3D11; + struct RendererContextD3D11 : public RendererContextI { RendererContextD3D11() @@ -1778,6 +1780,8 @@ namespace bgfx { namespace d3d11 m_deviceCtx->ClearState(); m_deviceCtx->Flush(); + m_zeroInitTileCache.invalidate(); + invalidateCache(); for (uint32_t ii = 0; ii < BX_COUNTOF(m_frameBuffers); ++ii) @@ -1934,6 +1938,11 @@ namespace bgfx { namespace d3d11 m_textures[_handle.idx].update(_side, _mip, _rect, _z, _depth, _pitch, _mem); } + void clearTexture(TextureHandle _handle, uint8_t _mip, uint8_t _numMips, uint16_t _layer, uint16_t _numLayers) override + { + m_textures[_handle.idx].clear(_mip, _numMips, _layer, _numLayers); + } + void readTexture(TextureHandle _handle, void* _data, uint16_t _layer, uint8_t _mip) override { const TextureD3D11& texture = m_textures[_handle.idx]; @@ -3800,6 +3809,7 @@ namespace bgfx { namespace d3d11 StateCacheT m_rasterizerStateCache; StateCacheT m_samplerStateCache; StateCacheLru m_srvUavLru; + StateCacheLru m_zeroInitTileCache; TextVideoMem m_textVideoMem; @@ -4413,6 +4423,137 @@ namespace bgfx { namespace d3d11 } } + static ID3D11Texture2D* zeroInitTile(DXGI_FORMAT _fmt, uint32_t _tileDim, uint32_t _blockW, uint32_t _blockH, uint32_t _blockSize) + { + if (IUnknown** cached = s_renderD3D11->m_zeroInitTileCache.find(uint64_t(_fmt) ) ) + { + return static_cast(*cached); + } + + const uint32_t rowPitch = (_tileDim / _blockW) * _blockSize; + const uint32_t numRows = _tileDim / _blockH; + uint8_t zeros[kTextureZeroInitBudget] = {}; + BX_ASSERT(rowPitch * numRows <= sizeof(zeros), "Zero-init tile exceeds budget."); + + D3D11_TEXTURE2D_DESC desc; + bx::memSet(&desc, 0, sizeof(desc) ); + desc.Width = _tileDim; + desc.Height = _tileDim; + desc.MipLevels = 1; + desc.ArraySize = 1; + desc.Format = _fmt; + desc.SampleDesc.Count = 1; + desc.Usage = D3D11_USAGE_DEFAULT; + desc.BindFlags = D3D11_BIND_SHADER_RESOURCE; + D3D11_SUBRESOURCE_DATA srd = { zeros, rowPitch, 0 }; + + ID3D11Texture2D* tile = NULL; + s_renderD3D11->m_device->CreateTexture2D(&desc, &srd, &tile); + + if (NULL != tile) + { + s_renderD3D11->m_zeroInitTileCache.add(uint64_t(_fmt), tile, 0); + } + + return tile; + } + + void TextureD3D11::clear(uint8_t _baseMip, uint8_t _numMips, uint16_t _baseLayer, uint16_t _numLayers) + { + const bimg::TextureFormat::Enum tf = bimg::TextureFormat::Enum(m_textureFormat); + + ID3D11Device* device = s_renderD3D11->m_device; + ID3D11DeviceContext* ctx = s_renderD3D11->m_deviceCtx; + + const DXGI_FORMAT fmt = (0 != (m_flags & BGFX_TEXTURE_SRGB) ) + ? s_textureFormat[m_textureFormat].m_fmtSrgb + : s_textureFormat[m_textureFormat].m_fmt + ; + const uint32_t numMips = m_numMips; + const uint32_t numSides = m_numLayers * (TextureD3D11::TextureCube == m_type ? 6 : 1); + const bool is3D = TextureD3D11::Texture3D == m_type; + const bool rtColor = 0 != (m_flags & BGFX_TEXTURE_RT_MASK); + + const uint32_t mipBeg = bx::min(_baseMip, numMips); + const uint32_t mipEnd = (UINT8_MAX == _numMips) ? numMips : bx::min(numMips, uint32_t(_baseMip) + _numMips); + const uint32_t sideBeg = is3D ? 0 : bx::min(_baseLayer, numSides); + const uint32_t sideEnd = is3D ? 1 : ( (UINT16_MAX == _numLayers) ? numSides : bx::min(numSides, uint32_t(_baseLayer) + _numLayers) ); + + if (rtColor && !is3D) + { + const float black[4] = { 0.0f, 0.0f, 0.0f, 0.0f }; + for (uint32_t side = sideBeg; side < sideEnd; ++side) + { + for (uint32_t mip = mipBeg; mip < mipEnd; ++mip) + { + D3D11_RENDER_TARGET_VIEW_DESC rtvd; + bx::memSet(&rtvd, 0, sizeof(rtvd) ); + rtvd.Format = fmt; + if (1 < numSides) + { + rtvd.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2DARRAY; + rtvd.Texture2DArray.MipSlice = mip; + rtvd.Texture2DArray.FirstArraySlice = side; + rtvd.Texture2DArray.ArraySize = 1; + } + else + { + rtvd.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D; + rtvd.Texture2D.MipSlice = mip; + } + + ID3D11RenderTargetView* rtv = NULL; + if (SUCCEEDED(device->CreateRenderTargetView(m_ptr, &rtvd, &rtv) ) + && NULL != rtv) + { + ctx->ClearRenderTargetView(rtv, black); + DX_RELEASE(rtv, 0); + } + } + } + return; + } + + const bimg::ImageBlockInfo& bi = bimg::getBlockInfo(tf); + const uint32_t blockW = bx::max(1, bi.blockWidth); + const uint32_t blockH = bx::max(1, bi.blockHeight); + const uint32_t blockSize = bi.blockSize; + const uint32_t tileDim = textureZeroInitTileDim(bimg::getBitsPerPixel(tf) ); + + ID3D11Texture2D* tile = zeroInitTile(fmt, tileDim, blockW, blockH, blockSize); + if (NULL == tile) + { + return; + } + + for (uint32_t side = sideBeg; side < sideEnd; ++side) + { + for (uint32_t mip = mipBeg; mip < mipEnd; ++mip) + { + const uint32_t mipW = bx::max(1, m_width >> mip); + const uint32_t mipH = bx::max(1, m_height >> mip); + const uint32_t mipD = is3D ? bx::max(1, m_depth >> mip) : 1; + const uint32_t dstSub = is3D ? mip : (mip + side * numMips); + + for (uint32_t zz = 0; zz < mipD; ++zz) + { + for (uint32_t yy = 0; yy < mipH; yy += tileDim) + { + const uint32_t bh = bx::min(tileDim, mipH - yy); + for (uint32_t xx = 0; xx < mipW; xx += tileDim) + { + const uint32_t bw = bx::min(tileDim, mipW - xx); + D3D11_BOX box; + box.left = 0; box.top = 0; box.front = 0; + box.right = bw; box.bottom = bh; box.back = 1; + ctx->CopySubresourceRegion(m_ptr, dstSub, xx, yy, zz, tile, 0, &box); + } + } + } + } + } + } + void* TextureD3D11::create(const Memory* _mem, uint64_t _flags, uint8_t _skip, uint64_t _external) { void* directAccessPtr = NULL; diff --git a/src/renderer_d3d11.h b/src/renderer_d3d11.h index d623a6992..db5b1f72c 100644 --- a/src/renderer_d3d11.h +++ b/src/renderer_d3d11.h @@ -288,6 +288,7 @@ namespace bgfx { namespace d3d11 void destroy(); void overrideInternal(uintptr_t _ptr, uint16_t _layerIndex); void update(uint8_t _side, uint8_t _mip, const Rect& _rect, uint16_t _z, uint16_t _depth, uint16_t _pitch, const Memory* _mem); + void clear(uint8_t _mip, uint8_t _numMips, uint16_t _layer, uint16_t _numLayers); void commit(uint8_t _stage, uint32_t _flags, const float _palette[][4], uint16_t _firstLayer = 0, uint16_t _numLayers = UINT16_MAX, uint8_t _firstMip = 0, uint8_t _numMips = UINT8_MAX); void resolve(uint8_t _resolve, uint32_t _layer, uint32_t _numLayers, uint32_t _mip) const; TextureHandle getHandle() const; diff --git a/src/renderer_d3d12.cpp b/src/renderer_d3d12.cpp index c6f8ea888..3e91f4f30 100644 --- a/src/renderer_d3d12.cpp +++ b/src/renderer_d3d12.cpp @@ -759,6 +759,8 @@ namespace bgfx { namespace d3d12 } #endif // BGFX_CONFIG_DEBUG_ANNOTATION && (BX_PLATFORM_WINDOWS || BX_PLATFORM_WINRT) + struct TextureD3D12; + struct RendererContextD3D12 : public RendererContextI { RendererContextD3D12() @@ -780,6 +782,7 @@ namespace bgfx { namespace d3d12 , m_directAccessSupport(false) , m_variableRateShadingSupport(false) , m_mipGen(NULL) + , m_zeroInitBuffer(NULL) { } @@ -2028,6 +2031,8 @@ namespace bgfx { namespace d3d12 m_cmd.finish(); m_batch.destroy(); + DX_RELEASE(m_zeroInitBuffer, 0); + preReset(); m_gpuTimer.shutdown(); @@ -2259,6 +2264,11 @@ namespace bgfx { namespace d3d12 m_textures[_handle.idx].update(m_commandList, _side, _mip, _rect, _z, _depth, _pitch, _mem); } + void clearTexture(TextureHandle _handle, uint8_t _mip, uint8_t _numMips, uint16_t _layer, uint16_t _numLayers) override + { + m_textures[_handle.idx].clear(m_commandList, _mip, _numMips, _layer, _numLayers); + } + void readTexture(TextureHandle _handle, void* _data, uint16_t _layer, uint8_t _mip) override { const TextureD3D12& texture = m_textures[_handle.idx]; @@ -4089,6 +4099,7 @@ namespace bgfx { namespace d3d12 bool m_variableRateShadingSupport; const MipGen* m_mipGen; + ID3D12Resource* m_zeroInitBuffer; void generateMips(ID3D12GraphicsCommandList* _commandList, TextureD3D12& _texture); }; @@ -6451,6 +6462,117 @@ namespace bgfx { namespace d3d12 m_ptr = (ID3D12Resource*)_ptr; } + void TextureD3D12::clear(ID3D12GraphicsCommandList* _commandList, uint8_t _mip, uint8_t _numMips, uint16_t _layer, uint16_t _numLayers) + { + const D3D12_RESOURCE_STATES saved = setState(_commandList, D3D12_RESOURCE_STATE_COPY_DEST); + + const bimg::TextureFormat::Enum tf = bimg::TextureFormat::Enum(m_textureFormat); + + ID3D12Resource* zeroBuffer = s_renderD3D12->m_zeroInitBuffer; + + if (NULL == zeroBuffer) + { + zeroBuffer = createCommittedResource(s_renderD3D12->m_device, HeapProperty::Upload, kTextureZeroInitBudget); + + void* ptr = NULL; + D3D12_RANGE readRange = { 0, 0 }; + + if (SUCCEEDED(zeroBuffer->Map(0, &readRange, &ptr) ) ) + { + bx::memSet(ptr, 0, kTextureZeroInitBudget); + zeroBuffer->Unmap(0, NULL); + } + + s_renderD3D12->m_zeroInitBuffer = zeroBuffer; + } + + if (NULL == zeroBuffer) + { + return; + } + + const DXGI_FORMAT fmt = s_textureFormat[m_textureFormat].m_fmt; + const uint32_t bpp = bimg::getBitsPerPixel(tf); + const uint32_t numMips = m_numMips; + const bool is3D = TextureD3D12::Texture3D == m_type; + const uint32_t numSides = m_numLayers * (TextureD3D12::TextureCube == m_type ? 6 : 1); + uint32_t tile = 512; + + while (tile > 1 + && bx::strideAlign(tile*bpp/8, D3D12_TEXTURE_DATA_PITCH_ALIGNMENT)*tile > kTextureZeroInitBudget) + { + tile >>= 1; + } + + const uint32_t mipBeg = bx::min(_mip, numMips); + const uint32_t mipEnd = (UINT8_MAX == _numMips) + ? numMips + : bx::min(numMips, uint32_t(_mip) + _numMips) + ; + const uint32_t sideBeg = is3D + ? 0 + : bx::min(_layer, numSides) + ; + const uint32_t sideEnd = is3D + ? 1 + : ( (UINT16_MAX == _numLayers) + ? numSides + : bx::min(numSides, uint32_t(_layer) + _numLayers) ) + ; + + for (uint32_t side = sideBeg; side < sideEnd; ++side) + { + for (uint32_t mip = mipBeg; mip < mipEnd; ++mip) + { + const uint32_t mipW = bx::max(1, m_width >> mip); + const uint32_t mipH = bx::max(1, m_height >> mip); + const uint32_t mipD = is3D ? bx::max(1, m_depth >> mip) : 1; + const uint32_t dstSub = is3D ? mip : (mip + side * numMips); + + for (uint32_t zz = 0; zz < mipD; ++zz) + { + for (uint32_t yy = 0; yy < mipH; yy += tile) + { + const uint32_t th = bx::min(tile, mipH - yy); + for (uint32_t xx = 0; xx < mipW; xx += tile) + { + const uint32_t tw = bx::min(tile, mipW - xx); + + D3D12_TEXTURE_COPY_LOCATION src = + { + .pResource = zeroBuffer, + .Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT, + .PlacedFootprint = + { + .Offset = 0, + .Footprint = + { + .Format = fmt, + .Width = tw, + .Height = th, + .Depth = 1, + .RowPitch = bx::strideAlign(tw * bpp / 8, D3D12_TEXTURE_DATA_PITCH_ALIGNMENT), + } + } + }; + + D3D12_TEXTURE_COPY_LOCATION dst = + { + .pResource = m_ptr, + .Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX, + .SubresourceIndex = dstSub, + }; + + _commandList->CopyTextureRegion(&dst, xx, yy, zz, &src, NULL); + } + } + } + } + } + + setState(_commandList, saved); + } + void TextureD3D12::update(ID3D12GraphicsCommandList* _commandList, uint8_t _side, uint8_t _mip, const Rect& _rect, uint16_t _z, uint16_t _depth, uint16_t _pitch, const Memory* _mem) { if (0 != (m_flags & BGFX_TEXTURE_INTERNAL_VIDEO_DECODE_DST) ) @@ -7614,7 +7736,7 @@ namespace bgfx { namespace d3d12 Rect viewScissorRect; viewScissorRect.clear(); - const uint32_t maxComputeBindings = g_caps.limits.maxComputeBindings; + const uint8_t maxComputeBindings = bx::narrowCast(g_caps.limits.maxComputeBindings); uint32_t statsNumPrimsSubmitted[BX_COUNTOF(s_primInfo)] = {}; uint32_t statsNumPrimsRendered[BX_COUNTOF(s_primInfo)] = {}; @@ -7767,6 +7889,7 @@ namespace bgfx { namespace d3d12 restoreScissor = false; const Clear& clr = renderView.m_clear; + if (BGFX_CLEAR_NONE != clr.m_flags) { Rect clearRect = rect; diff --git a/src/renderer_d3d12.h b/src/renderer_d3d12.h index d29da6e61..83deb214a 100644 --- a/src/renderer_d3d12.h +++ b/src/renderer_d3d12.h @@ -374,6 +374,7 @@ namespace bgfx { namespace d3d12 void* create(const Memory* _mem, uint64_t _flags, uint8_t _skip, uint64_t _external); void destroy(); void overrideInternal(uintptr_t _ptr); + void clear(ID3D12GraphicsCommandList* _commandList, uint8_t _mip, uint8_t _numMips, uint16_t _layer, uint16_t _numLayers); void update(ID3D12GraphicsCommandList* _commandList, uint8_t _side, uint8_t _mip, const Rect& _rect, uint16_t _z, uint16_t _depth, uint16_t _pitch, const Memory* _mem); void resolve(ID3D12GraphicsCommandList* _commandList, uint8_t _resolve, uint32_t _layer, uint32_t _numLayers, uint32_t _mip); D3D12_RESOURCE_STATES setState(ID3D12GraphicsCommandList* _commandList, D3D12_RESOURCE_STATES _state); diff --git a/src/renderer_gl.cpp b/src/renderer_gl.cpp index 5caabd79d..4c87646fd 100644 --- a/src/renderer_gl.cpp +++ b/src/renderer_gl.cpp @@ -3462,6 +3462,11 @@ namespace bgfx { namespace gl m_textures[_handle.idx].update(_side, _mip, _rect, _z, _depth, _pitch, _mem); } + void clearTexture(TextureHandle _handle, uint8_t _mip, uint8_t _numMips, uint16_t _layer, uint16_t _numLayers) override + { + m_textures[_handle.idx].clear(_mip, _numMips, _layer, _numLayers); + } + void readTexture(TextureHandle _handle, void* _data, uint16_t _layer, uint8_t _mip) override { if (m_readBackSupported) @@ -5840,6 +5845,37 @@ namespace bgfx { namespace gl return true; } + void TextureGL::clear(uint8_t _mip, uint8_t _numMips, uint16_t _layer, uint16_t _numLayers) + { + if (NULL == glClearTexSubImage) + { + return; + } + + const bool is3D = GL_TEXTURE_3D == m_target; + const uint32_t numSides = m_numLayers * (isCubeMap() ? 6 : 1); + + const uint8_t mipBeg = bx::min(_mip, m_numMips); + const uint8_t mipEnd = (UINT8_MAX == _numMips) + ? m_numMips + : bx::min(m_numMips, uint8_t(_mip + _numMips) ) + ; + + for (uint8_t lod = mipBeg; lod < mipEnd; ++lod) + { + const GLsizei mipW = GLsizei(bx::max(1, m_width >> lod) ); + const GLsizei mipH = GLsizei(bx::max(1, m_height >> lod) ); + + const GLint zoffset = is3D ? 0 : GLint(_layer); + const GLsizei depth = is3D + ? GLsizei(bx::max(1, m_depth >> lod) ) + : GLsizei( (UINT16_MAX == _numLayers) ? numSides - _layer : _numLayers) + ; + + GL_CHECK(glClearTexSubImage(m_id, lod, 0, 0, zoffset, mipW, mipH, depth, m_fmt, m_type, NULL) ); + } + } + void TextureGL::create(const Memory* _mem, uint64_t _flags, uint8_t _skip) { bimg::ImageContainer imageContainer; diff --git a/src/renderer_gl.h b/src/renderer_gl.h index b2d986554..a86d0a5ab 100644 --- a/src/renderer_gl.h +++ b/src/renderer_gl.h @@ -1433,6 +1433,7 @@ namespace bgfx { namespace gl void destroy(); void overrideInternal(uintptr_t _ptr); void update(uint8_t _side, uint8_t _mip, const Rect& _rect, uint16_t _z, uint16_t _depth, uint16_t _pitch, const Memory* _mem); + void clear(uint8_t _mip, uint8_t _numMips, uint16_t _layer, uint16_t _numLayers); void setSamplerState(uint32_t _flags, const float _rgba[4]); void commit(uint32_t _stage, uint32_t _flags, const float _palette[][4], uint8_t _firstMip, uint8_t _numMips, uint16_t _firstLayer, uint16_t _numLayers); GLuint getViewId(uint8_t _firstMip, uint8_t _numMips, uint16_t _firstLayer, uint16_t _numLayers); diff --git a/src/renderer_mtl.cpp b/src/renderer_mtl.cpp index 62da2e470..db9ced9d9 100644 --- a/src/renderer_mtl.cpp +++ b/src/renderer_mtl.cpp @@ -1384,6 +1384,11 @@ static_assert(BX_COUNTOF(s_accessNames) == Access::Count, "Invalid s_accessNames m_textures[_handle.idx].update(_side, _mip, _rect, _z, _depth, _pitch, _mem); } + void clearTexture(TextureHandle _handle, uint8_t _mip, uint8_t _numMips, uint16_t _layer, uint16_t _numLayers) override + { + m_textures[_handle.idx].clear(_mip, _numMips, _layer, _numLayers); + } + static MTL::PixelFormat getSwapChainPixelFormat(SwapChainMtl* _swapChain) { return NULL != _swapChain @@ -3656,6 +3661,55 @@ static_assert(BX_COUNTOF(s_accessNames) == Access::Count, "Invalid s_accessNames BufferMtl::create(_size, _data, _flags, stride, true); } + void TextureMtl::clear(uint8_t _baseMip, uint8_t _numMipsArg, uint16_t _baseLayer, uint16_t _numLayersArg) + { + const bimg::TextureFormat::Enum tf = bimg::TextureFormat::Enum(m_textureFormat); + if (NULL == m_ptr) + { + return; + } + + const uint32_t bpp = bimg::getBitsPerPixel(tf); + const bool is3D = MTL::TextureType3D == m_ptr->textureType(); + const bool isCube = TextureMtl::TextureCube == m_type; + const uint32_t numMips = m_numMips; + const uint32_t numSides = uint32_t(m_ptr->arrayLength() ) * (isCube ? 6 : 1); + + const uint32_t mipBeg = bx::min(_baseMip, numMips); + const uint32_t mipEnd = (UINT8_MAX == _numMipsArg) ? numMips : bx::min(numMips, uint32_t(_baseMip) + _numMipsArg); + const uint32_t sideBeg = is3D ? 0 : bx::min(_baseLayer, numSides); + const uint32_t sideEnd = is3D ? 1 : ( (UINT16_MAX == _numLayersArg) ? numSides : bx::min(numSides, uint32_t(_baseLayer) + _numLayersArg) ); + + const uint32_t tile = textureZeroInitTileDim(bpp); + const uint32_t zeroPitch = tile * bpp / 8; + uint8_t zeros[kTextureZeroInitBudget] = {}; + BX_ASSERT(zeroPitch * tile <= sizeof(zeros), "Zero-init tile exceeds budget."); + + for (uint32_t side = sideBeg; side < sideEnd; ++side) + { + for (uint32_t lod = mipBeg; lod < mipEnd; ++lod) + { + const uint32_t mipW = bx::max(1, m_width >> lod); + const uint32_t mipH = bx::max(1, m_height >> lod); + const uint32_t mipD = is3D ? bx::max(1, m_depth >> lod) : 1; + + for (uint32_t zz = 0; zz < mipD; ++zz) + { + for (uint32_t yy = 0; yy < mipH; yy += tile) + { + const uint32_t th = bx::min(tile, mipH - yy); + for (uint32_t xx = 0; xx < mipW; xx += tile) + { + const uint32_t tw = bx::min(tile, mipW - xx); + MTL::Region region(xx, yy, zz, tw, th, 1); + m_ptr->replaceRegion(region, lod, side, zeros, tw * bpp / 8, 0); + } + } + } + } + } + } + void TextureMtl::create(const Memory* _mem, uint64_t _flags, uint8_t _skip, uint64_t _external) { m_sampler = s_renderMtl->getSamplerState(uint32_t(_flags) ); @@ -5175,8 +5229,8 @@ static_assert(BX_COUNTOF(s_accessNames) == Access::Count, "Invalid s_accessNames const uint64_t primType = 0; uint8_t primIndex = uint8_t(primType>>BGFX_STATE_PT_SHIFT); PrimInfo prim = s_primInfo[primIndex]; - const uint32_t maxComputeBindings = g_caps.limits.maxComputeBindings; - const uint32_t maxTextureSamplers = g_caps.limits.maxTextureSamplers; + const uint8_t maxComputeBindings = bx::narrowCast(g_caps.limits.maxComputeBindings); + const uint8_t maxTextureSamplers = bx::narrowCast(g_caps.limits.maxTextureSamplers); MTL::RenderCommandEncoder* rce = NULL; PipelineStateMtl* currentPso = NULL; diff --git a/src/renderer_mtl.h b/src/renderer_mtl.h index f7bf806e8..c05445421 100644 --- a/src/renderer_mtl.h +++ b/src/renderer_mtl.h @@ -449,6 +449,8 @@ namespace bgfx { namespace mtl , const Memory* _mem ); + void clear(uint8_t _mip, uint8_t _numMips, uint16_t _layer, uint16_t _numLayers); + void commit( uint8_t _stage , bool _vertex diff --git a/src/renderer_noop.cpp b/src/renderer_noop.cpp index f8d305d16..290babc0d 100644 --- a/src/renderer_noop.cpp +++ b/src/renderer_noop.cpp @@ -174,6 +174,10 @@ namespace bgfx { namespace noop { } + void clearTexture(TextureHandle /*_handle*/, uint8_t /*_mip*/, uint8_t /*_numMips*/, uint16_t /*_layer*/, uint16_t /*_numLayers*/) override + { + } + void readTexture(TextureHandle /*_handle*/, void* /*_data*/, uint16_t /*_layer*/, uint8_t /*_mip*/) override { } diff --git a/src/renderer_vk.cpp b/src/renderer_vk.cpp index b2f3b0eff..98960fd8f 100644 --- a/src/renderer_vk.cpp +++ b/src/renderer_vk.cpp @@ -1220,6 +1220,8 @@ VK_IMPORT_DEVICE ); } + struct TextureVK; + struct RendererContextVK : public RendererContextI { RendererContextVK() @@ -2613,6 +2615,11 @@ VK_IMPORT_DEVICE m_textures[_handle.idx].update(m_commandBuffer, _side, _mip, _rect, _z, _depth, _pitch, _mem); } + void clearTexture(TextureHandle _handle, uint8_t _mip, uint8_t _numMips, uint16_t _layer, uint16_t _numLayers) override + { + m_textures[_handle.idx].clear(m_commandBuffer, _mip, _numMips, _layer, _numLayers); + } + void readTexture(TextureHandle _handle, void* _data, uint16_t _layer, uint8_t _mip) override { TextureVK& texture = m_textures[_handle.idx]; @@ -7389,6 +7396,44 @@ VK_DESTROY } } + void TextureVK::clear(VkCommandBuffer _commandBuffer, uint8_t _mip, uint8_t _numMips, uint16_t _layer, uint16_t _numLayers) + { + const VkImageLayout saved = m_currentImageLayout; + setState(_commandBuffer, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); + + const VkClearColorValue clearColor = { { 0.0f, 0.0f, 0.0f, 0.0f } }; + + VkImageSubresourceRange range = + { + .aspectMask = m_aspectFlags, + .baseMipLevel = _mip, + .levelCount = (UINT8_MAX == _numMips) + ? VK_REMAINING_MIP_LEVELS + : _numMips + , + .baseArrayLayer = _layer, + .layerCount = (UINT16_MAX == _numLayers) + ? VK_REMAINING_ARRAY_LAYERS + : _numLayers + , + }; + + vkCmdClearColorImage( + _commandBuffer + , m_textureImage + , VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL + , &clearColor + , 1 + , &range + ); + + if (VK_IMAGE_LAYOUT_UNDEFINED != saved + && VK_IMAGE_LAYOUT_PREINITIALIZED != saved) + { + setState(_commandBuffer, saved); + } + } + VkResult TextureVK::createView(uint32_t _layer, uint32_t _numLayers, uint32_t _mip, uint32_t _numMips, VkImageViewType _type, VkImageAspectFlags _aspectMask, bool _renderTarget, ::VkImageView* _view) const { VkResult result = VK_SUCCESS; diff --git a/src/renderer_vk.h b/src/renderer_vk.h index e418fdd80..3fc68bdca 100644 --- a/src/renderer_vk.h +++ b/src/renderer_vk.h @@ -721,6 +721,7 @@ VK_DESTROY_FUNC(DescriptorSet); void destroy(); void update(VkCommandBuffer _commandBuffer, uint8_t _side, uint8_t _mip, const Rect& _rect, uint16_t _z, uint16_t _depth, uint16_t _pitch, const Memory* _mem); + void clear(VkCommandBuffer _commandBuffer, uint8_t _mip, uint8_t _numMips, uint16_t _layer, uint16_t _numLayers); void resolve(VkCommandBuffer _commandBuffer, uint8_t _resolve, uint32_t _layer, uint32_t _numLayers, uint32_t _mip); void copyBufferToTexture(VkCommandBuffer _commandBuffer, VkBuffer _stagingBuffer, uint32_t _bufferImageCopyCount, VkBufferImageCopy* _bufferImageCopy); diff --git a/src/renderer_webgpu.cpp b/src/renderer_webgpu.cpp index 927801af1..f9f9f96c0 100644 --- a/src/renderer_webgpu.cpp +++ b/src/renderer_webgpu.cpp @@ -1701,6 +1701,11 @@ WGPU_IMPORT m_textures[_handle.idx].update(_side, _mip, _rect, _z, _depth, _pitch, _mem); } + void clearTexture(TextureHandle _handle, uint8_t _mip, uint8_t _numMips, uint16_t _layer, uint16_t _numLayers) override + { + m_textures[_handle.idx].clear(_mip, _numMips, _layer, _numLayers); + } + bool s_done; struct ReadTexture @@ -4200,6 +4205,81 @@ WGPU_IMPORT wgpuDestroy(m_textureResolve); } + void TextureWGPU::clear(uint8_t _mip, uint8_t _numMips, uint16_t _layer, uint16_t _numLayers) + { + const bimg::TextureFormat::Enum format = bimg::TextureFormat::Enum(m_textureFormat); + + if (0 != (m_flags & BGFX_TEXTURE_RT_WRITE_ONLY) ) + { + return; + } + + const bool is3D = TextureWGPU::Texture3D == m_type; + const uint32_t bpp = bimg::getBitsPerPixel(format); + const uint8_t numMips = (UINT8_MAX == _numMips) + ? uint8_t(m_numMips - _mip) + : _numMips + ; + + const uint32_t tileDim = textureZeroInitTileDim(bpp); + const uint32_t bytesPerRow = tileDim*bpp/8; + uint8_t zeros[kTextureZeroInitBudget] = {}; + BX_ASSERT(bytesPerRow*tileDim <= sizeof(zeros), "Zero-init tile exceeds budget."); + + for (uint8_t mip = _mip, mipEnd = uint8_t(_mip + numMips); mip < mipEnd; ++mip) + { + const uint32_t mipW = bx::max(1u, m_width >> mip); + const uint32_t mipH = bx::max(1u, m_height >> mip); + + const uint32_t totalSlices = is3D + ? bx::max(1u, m_depth >> mip) + : m_numSides + ; + const uint32_t numSlices = (UINT16_MAX == _numLayers) + ? (totalSlices - _layer) + : _numLayers + ; + + for (uint32_t slice = _layer, sliceEnd = _layer + numSlices; slice < sliceEnd; ++slice) + { + for (uint32_t yy = 0; yy < mipH; yy += tileDim) + { + const uint32_t th = bx::min(tileDim, mipH - yy); + + for (uint32_t xx = 0; xx < mipW; xx += tileDim) + { + const uint32_t tw = bx::min(tileDim, mipW - xx); + + s_renderWGPU->m_cmd.writeTexture( + { + .texture = m_texture, + .mipLevel = mip, + .origin = + { + .x = xx, + .y = yy, + .z = slice, + }, + .aspect = WGPUTextureAspect_All, + } + , zeros + , bytesPerRow*th + , { + .offset = 0, + .bytesPerRow = bytesPerRow, + .rowsPerImage = th, + } + , { + .width = tw, + .height = th, + .depthOrArrayLayers = 1, + }); + } + } + } + } + } + void TextureWGPU::update(uint8_t _side, uint8_t _mip, const Rect& _rect, uint16_t _z, uint16_t _depth, uint16_t _pitch, const Memory* _mem) { const uint32_t bpp = bimg::getBitsPerPixel(bimg::TextureFormat::Enum(m_textureFormat) ); diff --git a/src/renderer_webgpu.h b/src/renderer_webgpu.h index 5683d733b..6697dca7d 100644 --- a/src/renderer_webgpu.h +++ b/src/renderer_webgpu.h @@ -638,6 +638,7 @@ namespace wgpu { void create(const Memory* _mem, uint64_t _flags, uint8_t _skip); void destroy(); void update(uint8_t _side, uint8_t _mip, const Rect& _rect, uint16_t _z, uint16_t _depth, uint16_t _pitch, const Memory* _mem); + void clear(uint8_t _mip, uint8_t _numMips, uint16_t _layer, uint16_t _numLayers); WGPUSampler getSamplerState(uint32_t _samplerFlags) const; WGPUTextureView getTextureView(uint8_t _baseMipLevel, uint8_t _mipLevelCount, bool _storage, uint16_t _baseArrayLayer = 0, uint16_t _arrayLayerCount = UINT16_MAX, bool _force2DArray = false) const;