Add new Graphics::Features.

This commit is contained in:
Erin Maus
2026-07-23 05:48:40 -04:00
parent 7d09352e94
commit d9ee9a40ac
6 changed files with 60 additions and 5 deletions
+3
View File
@@ -2988,6 +2988,9 @@ STRINGMAP_CLASS_BEGIN(Graphics, Graphics::Feature, Graphics::FEATURE_MAX_ENUM, f
{ "texelbuffer", Graphics::FEATURE_TEXEL_BUFFER },
{ "copytexturetobuffer", Graphics::FEATURE_COPY_TEXTURE_TO_BUFFER },
{ "indirectdraw", Graphics::FEATURE_INDIRECT_DRAW },
{ "vertexwrite", Graphics::FEATURE_VERTEX_WRITE },
{ "pixelwrite", Graphics::FEATURE_PIXEL_WRITE },
{ "imageatomics", Graphics::FEATURE_IMAGE_ATOMICS },
}
STRINGMAP_CLASS_END(Graphics, Graphics::Feature, Graphics::FEATURE_MAX_ENUM, feature)
+3
View File
@@ -163,6 +163,9 @@ public:
FEATURE_TEXEL_BUFFER,
FEATURE_COPY_TEXTURE_TO_BUFFER,
FEATURE_INDIRECT_DRAW,
FEATURE_VERTEX_WRITE,
FEATURE_PIXEL_WRITE,
FEATURE_IMAGE_ATOMICS,
FEATURE_MAX_ENUM
};
+27 -2
View File
@@ -1307,6 +1307,7 @@ bool Shader::validateInternal(StrongRef<ShaderStage> stages[], std::string &err,
reflection.textureCount = 0;
reflection.bufferCount = 0;
auto &capabilities = Module::getInstance<Graphics>(Module::M_GRAPHICS)->getCapabilities();
for (int i = 0; i < program.getNumUniformVariables(); i++)
{
const glslang::TObjectReflection &info = program.getUniform(i);
@@ -1349,12 +1350,24 @@ bool Shader::validateInternal(StrongRef<ShaderStage> stages[], std::string &err,
}
else if (type->isImage())
{
if ((info.stages & (~EShLangComputeMask)) != 0 && !options.features[FEATURE_STORAGE_TEXTURES])
if ((info.stages & (~EShLangComputeMask)) != 0 && !options.features[FEATURE_WRITE])
{
err = "Shader validation error:\nStorage Texture uniform variables (image2D, etc) are only allowed in compute shaders unless explicitly enabled.";
return false;
}
if ((!qualifiers.isReadOnly() || qualifiers.isWriteOnly()) && ((info.stages & (~EShLangFragmentMask)) != 0) && !capabilities.features[Graphics::FEATURE_PIXEL_WRITE])
{
err = "Shader validation error:\nPlatform does not have writable Storage Texture uniform variables (image2D, etc) capabilities in pixel shaders.";
return false;
}
if ((!qualifiers.isReadOnly() || qualifiers.isWriteOnly()) && ((info.stages & (~EShLangVertexMask)) != 0) && !capabilities.features[Graphics::FEATURE_VERTEX_WRITE])
{
err = "Shader validation error:\nPlatform does not have writable Storage Texture uniform variables (image2D, etc) capabilities in vertex shaders.";
return false;
}
if (!qualifiers.hasFormat())
{
err = "Shader validation error:\nStorage Texture '" + u.name + "' must have an explicit format set in its layout declaration.";
@@ -1467,11 +1480,23 @@ bool Shader::validateInternal(StrongRef<ShaderStage> stages[], std::string &err,
{
const glslang::TQualifier &qualifiers = type->getQualifier();
if ((!qualifiers.isReadOnly() || qualifiers.isWriteOnly()) && ((info.stages & (~EShLangComputeMask)) != 0) && !options.features[FEATURE_WRITABLE_BUFFERS])
if ((!qualifiers.isReadOnly() || qualifiers.isWriteOnly()) && ((info.stages & (~EShLangComputeMask)) != 0) && !options.features[FEATURE_WRITE])
{
err = "Shader validation error:\nStorage Buffer block '" + info.name + "' must be marked as readonly in vertex and pixel shaders unless explicitly enabled.";
return false;
}
if ((!qualifiers.isReadOnly() || qualifiers.isWriteOnly()) && ((info.stages & (~EShLangFragmentMask)) != 0) && !capabilities.features[Graphics::FEATURE_PIXEL_WRITE])
{
err = "Shader validation error:\nPlatform does not have writable Storage Buffer blocks capabilities in pixel shaders.";
return false;
}
if ((!qualifiers.isReadOnly() || qualifiers.isWriteOnly()) && ((info.stages & (~EShLangVertexMask)) != 0) && !capabilities.features[Graphics::FEATURE_VERTEX_WRITE])
{
err = "Shader validation error:\nPlatform does not have writable Storage Buffer blocks capabilities in vertex shaders.";
return false;
}
if (qualifiers.layoutPacking != glslang::ElpStd430)
{
+17 -1
View File
@@ -2250,8 +2250,24 @@ void Graphics::initCapabilities()
capabilities.features[FEATURE_INDIRECT_DRAW] = true;
else
capabilities.features[FEATURE_INDIRECT_DRAW] = false;
// Apple 3 devices support read/write to buffers in functions, while Apple 4 supports read/write to images.
// So let's err on the safe side and check support for Apple 4.
if (families.apple[4])
{
capabilities.features[FEATURE_VERTEX_WRITE] = true;
capabilities.features[FEATURE_PIXEL_WRITE] = true;
}
else
{
capabilities.features[FEATURE_VERTEX_WRITE] = false;
capabilities.features[FEATURE_PIXEL_WRITE] = false;
}
// Not supported until Metal 3
capabilities.features[FEATURE_IMAGE_ATOMICS] = false;
static_assert(FEATURE_MAX_ENUM == 13, "Graphics::initCapabilities must be updated when adding a new graphics feature!");
static_assert(FEATURE_MAX_ENUM == 16, "Graphics::initCapabilities must be updated when adding a new graphics feature!");
// https://developer.apple.com/metal/Metal-Feature-Set-Tables.pdf
capabilities.limits[LIMIT_POINT_SIZE] = 511;
+4 -1
View File
@@ -1632,7 +1632,10 @@ void Graphics::initCapabilities()
capabilities.features[FEATURE_TEXEL_BUFFER] = gl.isBufferUsageSupported(BUFFERUSAGE_TEXEL);
capabilities.features[FEATURE_COPY_TEXTURE_TO_BUFFER] = gl.isCopyTextureToBufferSupported();
capabilities.features[FEATURE_INDIRECT_DRAW] = capabilities.features[FEATURE_GLSL4];
static_assert(FEATURE_MAX_ENUM == 13, "Graphics::initCapabilities must be updated when adding a new graphics feature!");
capabilities.features[FEATURE_VERTEX_WRITE] = true;
capabilities.features[FEATURE_PIXEL_WRITE] = true;
capabilities.features[FEATURE_IMAGE_ATOMICS] = true;
static_assert(FEATURE_MAX_ENUM == 16, "Graphics::initCapabilities must be updated when adding a new graphics feature!");
capabilities.limits[LIMIT_POINT_SIZE] = gl.getMaxPointSize();
capabilities.limits[LIMIT_TEXTURE_SIZE] = gl.getMax2DTextureSize();
+6 -1
View File
@@ -821,6 +821,8 @@ bool Graphics::setMode(void *context, const BackbufferSettings &settings)
void Graphics::initCapabilities()
{
VkPhysicalDeviceFeatures features;
vkGetPhysicalDeviceFeatures(physicalDevice, &features);
capabilities.features[FEATURE_MULTI_RENDER_TARGET_FORMATS] = true;
capabilities.features[FEATURE_CLAMP_ZERO] = true;
capabilities.features[FEATURE_CLAMP_ONE] = true;
@@ -834,7 +836,10 @@ void Graphics::initCapabilities()
capabilities.features[FEATURE_TEXEL_BUFFER] = true;
capabilities.features[FEATURE_COPY_TEXTURE_TO_BUFFER] = true;
capabilities.features[FEATURE_INDIRECT_DRAW] = true;
static_assert(FEATURE_MAX_ENUM == 13, "Graphics::initCapabilities must be updated when adding a new graphics feature!");
capabilities.features[FEATURE_VERTEX_WRITE] = features.vertexPipelineStoresAndAtomics;
capabilities.features[FEATURE_PIXEL_WRITE] = features.fragmentStoresAndAtomics;
capabilities.features[FEATURE_IMAGE_ATOMICS] = true;
static_assert(FEATURE_MAX_ENUM == 16, "Graphics::initCapabilities must be updated when adding a new graphics feature!");
VkPhysicalDeviceProperties properties;
vkGetPhysicalDeviceProperties(physicalDevice, &properties);