metal: improve shader resource binding code.

This commit is contained in:
Sasha Szpakowski
2024-01-09 21:11:04 -04:00
parent fb002ee59b
commit 7ff6f74a92
2 changed files with 62 additions and 42 deletions
+1 -1
View File
@@ -1063,7 +1063,7 @@ bool Graphics::applyShaderUniforms(id<MTLComputeCommandEncoder> encoder, love::g
if ((b.access & Shader::ACCESS_WRITE) != 0 && texture == nil) if ((b.access & Shader::ACCESS_WRITE) != 0 && texture == nil)
allWritableVariablesSet = false; allWritableVariablesSet = false;
} }
if (sampindex != LOVE_UINT8_MAX) if (sampindex != LOVE_UINT8_MAX)
setSampler(encoder, bindings, sampindex, samplertex); setSampler(encoder, bindings, sampindex, samplertex);
} }
+61 -41
View File
@@ -390,20 +390,24 @@ void Shader::addImage(const spirv_cross::CompilerMSL &msl, const spirv_cross::Re
case spv::Dim2D: case spv::Dim2D:
u.textureType = basetype.image.arrayed ? TEXTURE_2D_ARRAY : TEXTURE_2D; u.textureType = basetype.image.arrayed ? TEXTURE_2D_ARRAY : TEXTURE_2D;
u.textures = new love::graphics::Texture*[u.count]; u.textures = new love::graphics::Texture*[u.count];
memset(u.textures, 0, sizeof(love::graphics::Texture *) * u.count);
break; break;
case spv::Dim3D: case spv::Dim3D:
u.textureType = TEXTURE_VOLUME; u.textureType = TEXTURE_VOLUME;
u.textures = new love::graphics::Texture*[u.count]; u.textures = new love::graphics::Texture*[u.count];
memset(u.textures, 0, sizeof(love::graphics::Texture *) * u.count);
break; break;
case spv::DimCube: case spv::DimCube:
if (basetype.image.arrayed) if (basetype.image.arrayed)
throw love::Exception("Cubemap Arrays are not currently supported."); throw love::Exception("Cubemap Arrays are not currently supported.");
u.textureType = TEXTURE_CUBE; u.textureType = TEXTURE_CUBE;
u.textures = new love::graphics::Texture*[u.count]; u.textures = new love::graphics::Texture*[u.count];
memset(u.textures, 0, sizeof(love::graphics::Texture *) * u.count);
break; break;
case spv::DimBuffer: case spv::DimBuffer:
u.baseType = UNIFORM_TEXELBUFFER; u.baseType = UNIFORM_TEXELBUFFER;
u.buffers = new love::graphics::Buffer*[u.count]; u.buffers = new love::graphics::Buffer*[u.count];
memset(u.buffers, 0, sizeof(love::graphics::Buffer *) * u.count);
break; break;
default: default:
// TODO: error? continue? // TODO: error? continue?
@@ -415,33 +419,6 @@ void Shader::addImage(const spirv_cross::CompilerMSL &msl, const spirv_cross::Re
for (int i = 0; i < u.count; i++) for (int i = 0; i < u.count; i++)
u.ints[i] = -1; // Initialized below, after compiling. u.ints[i] = -1; // Initialized below, after compiling.
if (u.baseType == UNIFORM_SAMPLER)
{
auto tex = Graphics::getInstance()->getDefaultTexture(u.textureType, u.dataBaseType);
for (int i = 0; i < u.count; i++)
{
tex->retain();
u.textures[i] = tex;
}
}
else if (u.baseType == UNIFORM_TEXELBUFFER)
{
for (int i = 0; i < u.count; i++)
u.buffers[i] = nullptr; // TODO
}
else if (u.baseType == UNIFORM_STORAGETEXTURE)
{
Texture *tex = nullptr;
if ((u.access & ACCESS_WRITE) == 0)
tex = Graphics::getInstance()->getDefaultTexture(u.textureType, u.dataBaseType);
for (int i = 0; i < u.count; i++)
{
if (tex)
tex->retain();
u.textures[i] = tex;
}
}
uniforms[u.name] = u; uniforms[u.name] = u;
BuiltinUniform builtin; BuiltinUniform builtin;
@@ -571,7 +548,7 @@ void Shader::compileFromGLSLang(id<MTLDevice> device, const glslang::TProgram &p
for (int i = 0; i < u.count; i++) for (int i = 0; i < u.count; i++)
{ {
u.ints[i] = -1; // Initialized below, after compiling. u.ints[i] = -1; // Initialized below, after compiling.
u.buffers[i] = nullptr; // TODO u.buffers[i] = nullptr;
} }
uniforms[u.name] = u; uniforms[u.name] = u;
@@ -668,7 +645,11 @@ void Shader::compileFromGLSLang(id<MTLDevice> device, const glslang::TProgram &p
uint32 samplerbinding = msl.get_automatic_msl_resource_binding_secondary(resource.id); uint32 samplerbinding = msl.get_automatic_msl_resource_binding_secondary(resource.id);
if (texturebinding == (uint32)-1) if (texturebinding == (uint32)-1)
{
// No valid binding, the uniform was likely optimized out because it's not used.
uniforms.erase(resource.name);
return; return;
}
for (int i = 0; i < u.count; i++) for (int i = 0; i < u.count; i++)
{ {
@@ -678,15 +659,8 @@ void Shader::compileFromGLSLang(id<MTLDevice> device, const glslang::TProgram &p
TextureBinding b = {}; TextureBinding b = {};
b.access = u.access; b.access = u.access;
if (u.baseType == UNIFORM_TEXELBUFFER) if (u.baseType == UNIFORM_SAMPLER)
{ {
// TODO
}
else
{
b.texture = getMTLTexture(u.textures[i]);
b.samplerTexture = u.textures[i];
BuiltinUniform builtin = BUILTIN_MAX_ENUM; BuiltinUniform builtin = BUILTIN_MAX_ENUM;
if (getConstant(u.name.c_str(), builtin) && builtin == BUILTIN_TEXTURE_MAIN) if (getConstant(u.name.c_str(), builtin) && builtin == BUILTIN_TEXTURE_MAIN)
b.isMainTexture = true; b.isMainTexture = true;
@@ -726,7 +700,11 @@ void Shader::compileFromGLSLang(id<MTLDevice> device, const glslang::TProgram &p
uint32 bufferbinding = msl.get_automatic_msl_resource_binding(resource.id); uint32 bufferbinding = msl.get_automatic_msl_resource_binding(resource.id);
if (bufferbinding == (uint32)-1) if (bufferbinding == (uint32)-1)
{
// No valid binding, the uniform was likely optimized out because it's not used.
uniforms.erase(resource.name);
continue; continue;
}
for (int i = 0; i < u.count; i++) for (int i = 0; i < u.count; i++)
{ {
@@ -752,6 +730,25 @@ void Shader::compileFromGLSLang(id<MTLDevice> device, const glslang::TProgram &p
} }
} }
// Initialize default resource bindings.
for (auto &kvp : uniforms)
{
UniformInfo &info = kvp.second;
switch (info.baseType)
{
case UNIFORM_SAMPLER:
case UNIFORM_STORAGETEXTURE:
sendTextures(&info, info.textures, info.count);
break;
case UNIFORM_TEXELBUFFER:
case UNIFORM_STORAGEBUFFER:
sendBuffers(&info, info.buffers, info.count);
break;
default:
break;
}
}
firstVertexBufferBinding = metalBufferIndices[SHADERSTAGE_VERTEX]; firstVertexBufferBinding = metalBufferIndices[SHADERSTAGE_VERTEX];
} }
@@ -878,6 +875,7 @@ void Shader::sendTextures(const UniformInfo *info, love::graphics::Texture **tex
for (int i = 0; i < count; i++) for (int i = 0; i < count; i++)
{ {
love::graphics::Texture *tex = textures[i]; love::graphics::Texture *tex = textures[i];
bool isdefault = tex == nullptr;
if (tex != nullptr) if (tex != nullptr)
{ {
@@ -897,8 +895,17 @@ void Shader::sendTextures(const UniformInfo *info, love::graphics::Texture **tex
info->textures[i] = tex; info->textures[i] = tex;
textureBindings[info->ints[i]].texture = getMTLTexture(tex); auto &binding = textureBindings[info->ints[i]];
textureBindings[info->ints[i]].samplerTexture = tex; if (isdefault && (binding.access & ACCESS_WRITE) != 0)
{
binding.texture = nil;
binding.samplerTexture = nullptr;
}
else
{
binding.texture = getMTLTexture(tex);
binding.samplerTexture = tex;
}
} }
}} }}
@@ -919,13 +926,23 @@ void Shader::sendBuffers(const UniformInfo *info, love::graphics::Buffer **buffe
for (int i = 0; i < count; i++) for (int i = 0; i < count; i++)
{ {
love::graphics::Buffer *buffer = buffers[i]; love::graphics::Buffer *buffer = buffers[i];
bool isdefault = buffer == nullptr;
if (buffer != nullptr) if (buffer != nullptr)
{ {
if (!validateBuffer(info, buffer, false)) if (!validateBuffer(info, buffer, false))
continue; continue;
buffer->retain();
} }
else
{
auto gfx = Graphics::getInstance();
if (texelbinding)
buffer = gfx->getDefaultTexelBuffer(info->dataBaseType);
else
buffer = gfx->getDefaultStorageBuffer();
}
buffer->retain();
if (info->buffers[i] != nullptr) if (info->buffers[i] != nullptr)
info->buffers[i]->release(); info->buffers[i]->release();
@@ -938,8 +955,11 @@ void Shader::sendBuffers(const UniformInfo *info, love::graphics::Buffer **buffe
} }
else if (storagebinding) else if (storagebinding)
{ {
// TODO auto &binding = bufferBindings[info->ints[i]];
bufferBindings[info->ints[i]].buffer = getMTLBuffer(buffer); if (isdefault && (binding.access & ACCESS_WRITE) != 0)
binding.buffer = nil;
else
binding.buffer = getMTLBuffer(buffer);
} }
} }
} }