Metal fixes, and instance data fallback on all renderers. (#4103)

This commit is contained in:
Branimir Karadžić
2026-10-28 21:08:38 -07:00
committed by GitHub
parent 4367089705
commit e7c58be8b6
8 changed files with 215 additions and 32 deletions
+25
View File
@@ -2932,6 +2932,31 @@ namespace bgfx { namespace d3d11
curr->AlignedByteOffset = ii*16;
}
const D3D11_INPUT_ELEMENT_DESC fallback = { "TEXCOORD", 0, DXGI_FORMAT_R8G8B8A8_UNORM, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 };
const uint32_t numFallback = 0 < _numStreams ? BGFX_CONFIG_MAX_INSTANCE_DATA_COUNT : 0;
for (uint32_t ii = _numInstanceData; ii < numFallback && uint32_t(elem-vertexElements) < D3D11_IA_VERTEX_INPUT_STRUCTURE_ELEMENT_COUNT; ++ii)
{
const uint32_t index = BGFX_CONFIG_INSTANCE_DATA_FIRST_TEXCOORD - ii;
bool found = false;
for (const D3D11_INPUT_ELEMENT_DESC* curr = vertexElements; curr != elem && !found; ++curr)
{
found = true
&& 0 == bx::strCmp(curr->SemanticName, "TEXCOORD")
&& curr->SemanticIndex == index
;
}
if (!found)
{
bx::memCopy(elem, &fallback, sizeof(D3D11_INPUT_ELEMENT_DESC) );
elem->SemanticIndex = index;
++elem;
}
}
num = uint32_t(elem-vertexElements);
DX_CHECK(m_device->CreateInputLayout(vertexElements
, num
+25
View File
@@ -3870,6 +3870,31 @@ namespace bgfx { namespace d3d12
curr->AlignedByteOffset = ii*16;
}
const D3D12_INPUT_ELEMENT_DESC fallback = { "TEXCOORD", 0, DXGI_FORMAT_R8G8B8A8_UNORM, 0, 0, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 };
const uint32_t numFallback = 0 < _numStreams ? BGFX_CONFIG_MAX_INSTANCE_DATA_COUNT : 0;
for (uint32_t ii = _numInstanceData; ii < numFallback && uint32_t(elem-_vertexElements) < D3D12_IA_VERTEX_INPUT_STRUCTURE_ELEMENT_COUNT; ++ii)
{
const uint32_t index = BGFX_CONFIG_INSTANCE_DATA_FIRST_TEXCOORD - ii;
bool found = false;
for (const D3D12_INPUT_ELEMENT_DESC* curr = _vertexElements; curr != elem && !found; ++curr)
{
found = true
&& 0 == bx::strCmp(curr->SemanticName, "TEXCOORD")
&& curr->SemanticIndex == index
;
}
if (!found)
{
bx::memCopy(elem, &fallback, sizeof(D3D12_INPUT_ELEMENT_DESC) );
elem->SemanticIndex = index;
++elem;
}
}
return uint32_t(elem-_vertexElements);
}
+79 -26
View File
@@ -96,14 +96,14 @@ namespace bgfx { namespace mtl
static const MTL::VertexFormat s_attribType[][4][2] = //type, count, normalized
{
{ // Uint8
{ MTL::VertexFormatChar2, MTL::VertexFormatChar2Normalized },
{ // Int8
{ MTL::VertexFormatChar, MTL::VertexFormatCharNormalized },
{ MTL::VertexFormatChar2, MTL::VertexFormatChar2Normalized },
{ MTL::VertexFormatChar3, MTL::VertexFormatChar3Normalized },
{ MTL::VertexFormatChar4, MTL::VertexFormatChar4Normalized },
},
{ // Uint8
{ MTL::VertexFormatUChar2, MTL::VertexFormatUChar2Normalized },
{ MTL::VertexFormatUChar, MTL::VertexFormatUCharNormalized },
{ MTL::VertexFormatUChar2, MTL::VertexFormatUChar2Normalized },
{ MTL::VertexFormatUChar3, MTL::VertexFormatUChar3Normalized },
{ MTL::VertexFormatUChar4, MTL::VertexFormatUChar4Normalized },
@@ -115,19 +115,19 @@ namespace bgfx { namespace mtl
{ MTL::VertexFormatUInt1010102Normalized, MTL::VertexFormatUInt1010102Normalized },
},
{ // Int16
{ MTL::VertexFormatShort2, MTL::VertexFormatShort2Normalized },
{ MTL::VertexFormatShort, MTL::VertexFormatShortNormalized },
{ MTL::VertexFormatShort2, MTL::VertexFormatShort2Normalized },
{ MTL::VertexFormatShort3, MTL::VertexFormatShort3Normalized },
{ MTL::VertexFormatShort4, MTL::VertexFormatShort4Normalized },
},
{ // Int16
{ MTL::VertexFormatUShort2, MTL::VertexFormatUShort2Normalized },
{ // Uint16
{ MTL::VertexFormatUShort, MTL::VertexFormatUShortNormalized },
{ MTL::VertexFormatUShort2, MTL::VertexFormatUShort2Normalized },
{ MTL::VertexFormatUShort3, MTL::VertexFormatUShort3Normalized },
{ MTL::VertexFormatUShort4, MTL::VertexFormatUShort4Normalized },
},
{ // Half
{ MTL::VertexFormatHalf2, MTL::VertexFormatHalf2 },
{ MTL::VertexFormatHalf, MTL::VertexFormatHalf },
{ MTL::VertexFormatHalf2, MTL::VertexFormatHalf2 },
{ MTL::VertexFormatHalf3, MTL::VertexFormatHalf3 },
{ MTL::VertexFormatHalf4, MTL::VertexFormatHalf4 },
@@ -337,8 +337,8 @@ BX_PRAGMA_DIAGNOSTIC_IGNORED_CLANG("-Wunguarded-availability-new");
{ MTL::PixelFormatRGBA16Uint, MTL::PixelFormatInvalid, MTL::ReadWriteTextureTier2, { $R, $G, $B, $A }, false }, // RGBA16U
{ MTL::PixelFormatRGBA16Float, MTL::PixelFormatInvalid, MTL::ReadWriteTextureTier2, { $R, $G, $B, $A }, true }, // RGBA16F
{ MTL::PixelFormatRGBA16Snorm, MTL::PixelFormatInvalid, MTL::ReadWriteTextureTierNone, { $R, $G, $B, $A }, true }, // RGBA16S
{ MTL::PixelFormatRGBA32Sint, MTL::PixelFormatInvalid, MTL::ReadWriteTextureTier2, { $R, $G, $B, $A }, true }, // RGBA32I
{ MTL::PixelFormatRGBA32Uint, MTL::PixelFormatInvalid, MTL::ReadWriteTextureTier2, { $R, $G, $B, $A }, true }, // RGBA32U
{ MTL::PixelFormatRGBA32Sint, MTL::PixelFormatInvalid, MTL::ReadWriteTextureTier2, { $R, $G, $B, $A }, false }, // RGBA32I
{ MTL::PixelFormatRGBA32Uint, MTL::PixelFormatInvalid, MTL::ReadWriteTextureTier2, { $R, $G, $B, $A }, false }, // RGBA32U
{ MTL::PixelFormatRGBA32Float, MTL::PixelFormatInvalid, MTL::ReadWriteTextureTier2, { $R, $G, $B, $A }, true }, // RGBA32F
{ MTL::PixelFormatB5G6R5Unorm, MTL::PixelFormatInvalid, MTL::ReadWriteTextureTierNone, { $R, $G, $B, $A }, true }, // B5G6R5
{ MTL::PixelFormatB5G6R5Unorm, MTL::PixelFormatInvalid, MTL::ReadWriteTextureTierNone, { $B, $G, $R, $A }, true }, // R5G6B5
@@ -3418,16 +3418,6 @@ static_assert(BX_COUNTOF(s_accessNames) == Access::Count, "Invalid s_accessNames
}
}
MTL::VertexBufferLayoutDescriptor* vbld = vertexDesc->layouts()->object(1);
if (usedFallbackAttrib
&& 0 == vbld->stride() )
{
vbld->setStride(4);
vbld->setStepFunction(MTL::VertexStepFunctionConstant);
vbld->setStepRate(0);
}
if (0 < _numInstanceData)
{
uint32_t numAttribs = 0;
@@ -3450,6 +3440,30 @@ static_assert(BX_COUNTOF(s_accessNames) == Access::Count, "Invalid s_accessNames
vertexDesc->layouts()->object(stream+1)->setStepRate(1);
}
}
else
{
for (uint32_t ii = 0; ii < BX_COUNTOF(s_instanceDataName); ++ii)
{
const uint32_t loc = program.m_instanceData[ii];
if (UINT32_MAX != loc)
{
vertexDesc->attributes()->object(loc)->setFormat(MTL::VertexFormatUChar4);
vertexDesc->attributes()->object(loc)->setBufferIndex(1);
vertexDesc->attributes()->object(loc)->setOffset(0);
usedFallbackAttrib = true;
}
}
}
MTL::VertexBufferLayoutDescriptor* vbld = vertexDesc->layouts()->object(1);
if (usedFallbackAttrib
&& 0 == vbld->stride() )
{
vbld->setStride(4);
vbld->setStepFunction(MTL::VertexStepFunctionConstant);
vbld->setStepRate(0);
}
pd->setVertexDescriptor(vertexDesc);
@@ -3457,7 +3471,7 @@ static_assert(BX_COUNTOF(s_accessNames) == Access::Count, "Invalid s_accessNames
MTL::RenderPipelineReflection* reflection = NULL;
pso->m_rps = newRenderPipelineStateWithDescriptor(m_device, pd, MTL::PipelineOptionBufferTypeInfo, &reflection);
BGFX_FATAL(NULL != pso->m_rps, Fatal::InvalidShader, "Failed to create graphics PSO!");
BGFX_FATAL(NULL != pso->m_rps, Fatal::InvalidShader, "Failed to create graphics PSO: %s", s_lastPipelineError);
if (NULL != reflection)
{
@@ -4658,6 +4672,7 @@ static_assert(BX_COUNTOF(s_accessNames) == Access::Count, "Invalid s_accessNames
MTL_RELEASE_DEFERRED(m_ptrMsaa);
MTL_RELEASE_DEFERRED(m_ptrStencil);
MTL_RELEASE_DEFERRED(m_ptrMsaaStencil);
MTL_RELEASE_DEFERRED(m_ptrAlt);
MTL_RELEASE_DEFERRED(m_ptrMsaaAlt);
@@ -4811,12 +4826,41 @@ static_assert(BX_COUNTOF(s_accessNames) == Access::Count, "Invalid s_accessNames
;
}
MTL::Texture* TextureMtl::getMultisampleStencilView()
{
if (NULL == m_ptrMsaa
|| 0 == (m_flags & BGFX_TEXTURE_MSAA_SAMPLE) )
{
return NULL;
}
if (NULL != m_ptrMsaaStencil)
{
return m_ptrMsaaStencil;
}
MTL::PixelFormat format;
switch (m_ptrMsaa->pixelFormat() )
{
case MTL::PixelFormatDepth32Float_Stencil8: format = MTL::PixelFormatX32_Stencil8; break;
case MTL::PixelFormatDepth24Unorm_Stencil8: format = MTL::PixelFormatX24_Stencil8; break;
case MTL::PixelFormatStencil8: return m_ptrMsaa;
default: return NULL;
}
m_ptrMsaaStencil = m_ptrMsaa->newTextureView(format);
return m_ptrMsaaStencil;
}
MTL::Texture* TextureMtl::getSampledView(uint8_t _textureType, uint32_t _flags, uint16_t _firstLayer, uint16_t _numLayers, uint8_t _firstMip, uint8_t _numMips, bool _stencil)
{
if (MTL::TextureType2DMultisample == _textureType
|| MTL::TextureType2DMultisampleArray == _textureType)
{
MTL::Texture* ptr = getMultisampleView(_flags);
MTL::Texture* ptr = _stencil
? getMultisampleStencilView()
: getMultisampleView(_flags)
;
if (NULL != ptr)
{
@@ -4924,8 +4968,12 @@ static_assert(BX_COUNTOF(s_accessNames) == Access::Count, "Invalid s_accessNames
}
const bool isCube = TextureCube == m_type;
const uint32_t rangeScale = isCube ? 6 : 1;
const uint32_t totalUnits = uint32_t(ptr->arrayLength() );
const bool wants2D = MTL::TextureType2D == _textureType || MTL::TextureType2DArray == _textureType;
const bool wantsCube = MTL::TextureTypeCube == _textureType || MTL::TextureTypeCubeArray == _textureType;
const bool facesAsLayers = isCube && wants2D;
const uint32_t rangeScale = isCube && !facesAsLayers ? 6 : 1;
const uint32_t totalUnits = uint32_t(ptr->arrayLength() ) * (facesAsLayers ? 6 : 1);
const uint32_t totalLayers = totalUnits * rangeScale;
const uint8_t firstMip = bx::min<uint8_t>(_firstMip, uint8_t(m_numMips - 1) );
@@ -4937,7 +4985,14 @@ static_assert(BX_COUNTOF(s_accessNames) == Access::Count, "Invalid s_accessNames
MTL::TextureType type = ptr->textureType();
if (isCube)
if (facesAsLayers)
{
type = 1 == numLayers && MTL::TextureType2D == _textureType
? (MTL::TextureType)MTL::TextureType2D
: (MTL::TextureType)MTL::TextureType2DArray
;
}
else if (isCube)
{
type = 1 == numUnits
? (MTL::TextureType)MTL::TextureTypeCube
@@ -4952,8 +5007,6 @@ static_assert(BX_COUNTOF(s_accessNames) == Access::Count, "Invalid s_accessNames
const bool arrayOf2D = MTL::TextureType2D == type || MTL::TextureType2DArray == type;
const bool arrayOfCube = MTL::TextureTypeCube == type || MTL::TextureTypeCubeArray == type;
const bool wants2D = MTL::TextureType2D == _textureType || MTL::TextureType2DArray == _textureType;
const bool wantsCube = MTL::TextureTypeCube == _textureType || MTL::TextureTypeCubeArray == _textureType;
if ( (arrayOf2D && wants2D && (MTL::TextureType2DArray == _textureType || 1 == numLayers) )
|| (arrayOfCube && wantsCube && (MTL::TextureTypeCubeArray == _textureType || 1 == numUnits ) ) )
+10
View File
@@ -143,6 +143,8 @@ namespace bgfx { namespace mtl
return lib;
}
inline char s_lastPipelineError[1024] = "";
inline MTL::RenderPipelineState* newRenderPipelineStateWithDescriptor(MTL::Device* _device, MTL::RenderPipelineDescriptor* _descriptor)
{
NS::Error* error = NULL;
@@ -163,6 +165,11 @@ namespace bgfx { namespace mtl
{
NS::Error* error = NULL;
MTL::RenderPipelineState* state = _device->newRenderPipelineState(_descriptor, _options, _reflection, &error);
if (NULL != error)
{
bx::strCopy(s_lastPipelineError, sizeof(s_lastPipelineError), error->localizedDescription()->utf8String() );
}
BX_WARN(NULL == error
, "newRenderPipelineStateWithDescriptor failed: %s"
, error->localizedDescription()->utf8String()
@@ -479,6 +486,7 @@ namespace bgfx { namespace mtl
, m_ptrStencil(NULL)
, m_ptrAlt(NULL)
, m_ptrMsaaAlt(NULL)
, m_ptrMsaaStencil(NULL)
, m_sampler(NULL)
, m_videoDecoder(NULL)
, m_flags(0)
@@ -519,6 +527,7 @@ namespace bgfx { namespace mtl
);
MTL::Texture* getMultisampleView(uint32_t _flags) const;
MTL::Texture* getMultisampleStencilView();
MTL::Texture* getSampledView(uint8_t _textureType, uint32_t _flags, uint16_t _firstLayer, uint16_t _numLayers, uint8_t _firstMip, uint8_t _numMips, bool _stencil);
MTL::Texture* getTextureImage(uint8_t _mip, uint16_t _firstLayer = 0, uint16_t _numLayers = UINT16_MAX);
@@ -532,6 +541,7 @@ namespace bgfx { namespace mtl
MTL::Texture* m_ptrStencil; // for emulating packed depth/stencil formats - only for iOS8...
MTL::Texture* m_ptrAlt;
MTL::Texture* m_ptrMsaaAlt;
MTL::Texture* m_ptrMsaaStencil;
stl::unordered_map<uint64_t, MTL::Texture*> m_ptrViews;
MTL::SamplerState* m_sampler;
VideoDecoderMtl* m_videoDecoder;
+37
View File
@@ -2305,6 +2305,23 @@ VK_IMPORT_INSTANCE
fmt = s_textureFormat[ii].m_fmtSrgb;
}
if (0 != (support & BGFX_CAPS_FORMAT_TEXTURE_MIP_AUTOGEN) )
{
VkFormatProperties fp;
vkGetPhysicalDeviceFormatProperties(m_physicalDevice, depth ? s_textureFormat[ii].m_fmtDsv : s_textureFormat[ii].m_fmt, &fp);
const VkFormatFeatureFlags mipFeatures = 0
| VK_FORMAT_FEATURE_BLIT_SRC_BIT
| VK_FORMAT_FEATURE_BLIT_DST_BIT
| (depth ? 0 : VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT)
;
if (mipFeatures != (fp.optimalTilingFeatures & mipFeatures) )
{
support &= ~BGFX_CAPS_FORMAT_TEXTURE_MIP_AUTOGEN;
}
}
g_caps.formats[ii] = support;
}
@@ -4135,10 +4152,24 @@ VK_IMPORT_DEVICE
}
}
const uint32_t firstInstanceLocation = _vertexInputState.vertexAttributeDescriptionCount;
if (0 < _numInstanceData)
{
fillInstanceBinding(_program.m_vsh, _vertexInputState, _numInstanceData);
}
const uint32_t numFallback = 0 < _numStream ? _program.m_vsh->m_numInstanceData : 0;
for (uint32_t ii = _numInstanceData; ii < numFallback; ++ii)
{
VkVertexInputAttributeDescription* inputAttrib = const_cast<VkVertexInputAttributeDescription*>(_vertexInputState.pVertexAttributeDescriptions + _vertexInputState.vertexAttributeDescriptionCount);
inputAttrib->location = firstInstanceLocation + ii;
inputAttrib->binding = 0;
inputAttrib->format = VK_FORMAT_R8G8B8A8_UNORM;
inputAttrib->offset = 0;
_vertexInputState.vertexAttributeDescriptionCount++;
}
}
VkResult getRenderPass(uint8_t _num, const VkFormat* _formats, const VkImageAspectFlags* _aspects, const bool* _resolve, VkSampleCountFlagBits _samples, uint16_t _clearFlags, uint8_t _depthFlags, ::VkRenderPass* _outRenderPass, uint32_t* _outHashKey)
@@ -7000,6 +7031,8 @@ VK_DESTROY
bx::read(&reader, m_numAttrs, &err);
m_numInstanceData = 0;
for (uint8_t ii = 0; ii < m_numAttrs; ++ii)
{
uint16_t id;
@@ -7012,6 +7045,10 @@ VK_DESTROY
m_attrMask[attr] = UINT16_MAX;
m_attrRemap[attr] = ii;
}
else
{
++m_numInstanceData;
}
}
bx::HashMurmur2A murmur;
+1
View File
@@ -576,6 +576,7 @@ VK_DESTROY_FUNC(DescriptorSet);
uint16_t m_size;
uint8_t m_numPredefined;
uint8_t m_numAttrs;
uint8_t m_numInstanceData;
BindInfo m_bindInfo[BGFX_CONFIG_MAX_TEXTURE_SAMPLERS];
+37 -6
View File
@@ -547,6 +547,14 @@ namespace bgfx { namespace wgpu
return 0 <= idx && s_feature[idx].supported;
}
static bool isMipGenFormat(TextureFormat::Enum _format)
{
return false
|| TextureFormat::RGBA8 == _format
|| TextureFormat::BGRA8 == _format
;
}
struct TextureFormatCaps
{
TextureFormatCaps()
@@ -735,7 +743,10 @@ namespace bgfx { namespace wgpu
;
}
if (MipGen::isSupported(_fmt) )
if (true
&& storage
&& isMipGenFormat(_fmt)
&& MipGen::isSupported(_fmt) )
{
caps |= BGFX_CAPS_FORMAT_TEXTURE_MIP_AUTOGEN;
}
@@ -3957,10 +3968,25 @@ WGPU_IMPORT
}
}
const uint32_t firstInstanceLocation = maxShaderLocation + (0 < numStreams);
const uint32_t numFallback = 0 < numStreams ? program.m_vsh->m_numInstanceData : 0;
for (uint32_t ii = _numInstanceData; ii < numFallback; ++ii)
{
*elem =
{
.nextInChain = NULL,
.format = WGPUVertexFormat_Unorm8x4,
.offset = 0,
.shaderLocation = firstInstanceLocation+ii,
};
++elem;
++vertexBufferLayout[numStreams-1].attributeCount;
}
if (0 < _numInstanceData)
{
maxShaderLocation += 0 < numStreams;
for (uint32_t ii = 0; ii < _numInstanceData; ++ii)
{
elem[ii] =
@@ -3968,7 +3994,7 @@ WGPU_IMPORT
.nextInChain = 0,
.format = WGPUVertexFormat_Float32x4,
.offset = ii*16ull,
.shaderLocation = maxShaderLocation+ii,
.shaderLocation = firstInstanceLocation+ii,
};
}
@@ -4962,6 +4988,8 @@ WGPU_IMPORT
bx::read(&reader, m_numAttrs, &err);
m_numInstanceData = 0;
for (uint8_t ii = 0; ii < m_numAttrs; ++ii)
{
uint16_t id;
@@ -4974,6 +5002,10 @@ WGPU_IMPORT
m_attrMask[attr] = UINT16_MAX;
m_attrRemap[attr] = ii;
}
else
{
++m_numInstanceData;
}
}
bx::HashMurmur3 murmur;
@@ -5157,9 +5189,8 @@ WGPU_IMPORT
static bool canGenerateMips(TextureFormat::Enum _format)
{
return true
&& isMipGenFormat(_format)
&& 0 != (g_caps.formats[_format] & BGFX_CAPS_FORMAT_TEXTURE_IMAGE_WRITE)
&& !bimg::isDepth(bimg::TextureFormat::Enum(_format) )
&& !bimg::isCompressed(bimg::TextureFormat::Enum(_format) )
;
}
+1
View File
@@ -547,6 +547,7 @@ namespace wgpu {
uint16_t m_blockSize;
uint8_t m_numPredefined;
uint8_t m_numAttrs;
uint8_t m_numInstanceData;
ShaderBinding m_shaderBinding[BGFX_CONFIG_MAX_TEXTURE_SAMPLERS];