J.D*_*Doe 1 xcode objective-c ios swift metal
这是完整的 shadertypes.h 文件。我将把它分解成我无法理解的部分。
#ifndef ShaderTypes_h
#define ShaderTypes_h
//Part 1 Compiler flags
#ifdef __METAL_VERSION__
#define NS_ENUM(_type, _name) enum _name : _type _name; enum _name : _type
#define NSInteger metal::int32_t
#else
#import <Foundation/Foundation.h>
#endif
#include <simd/simd.h>
//Part 2 buffer index
typedef NS_ENUM(NSInteger, BufferIndex)
{
BufferIndexMeshPositions = 0,
BufferIndexMeshGenerics = 1,
BufferIndexUniforms = 2
};
//Part 3 vertex attribute and position
typedef NS_ENUM(NSInteger, VertexAttribute)
{
VertexAttributePosition = 0,
VertexAttributeTexcoord = 1,
};
//Part 4 texture index color
typedef NS_ENUM(NSInteger, TextureIndex)
{
TextureIndexColor = 0,
};
//Part 5 uniforms
typedef struct
{
matrix_float4x4 projectionMatrix;
matrix_float4x4 modelViewMatrix;
} Uniforms;
#endif /* ShaderTypes_h */
Run Code Online (Sandbox Code Playgroud)
第1部分
#ifdef __METAL_VERSION__
#define NS_ENUM(_type, _name) enum _name : _type _name; enum _name : _type
#define NSInteger metal::int32_t
#else
#import <Foundation/Foundation.h>
#endif
//A bunch of definitions go after this
#endif
Run Code Online (Sandbox Code Playgroud)
我的困惑主要是我们为什么要编写所有这些代码。它似乎在检查用户是否有金属,但是它定义的 NS_ENUM 是什么?为什么要定义金属变量?基础是有条件导入的吗?
第2部分
typedef NS_ENUM(NSInteger, BufferIndex)
{
BufferIndexMeshPositions = 0,
BufferIndexMeshGenerics = 1,
BufferIndexUniforms = 2
};
Run Code Online (Sandbox Code Playgroud)
不确定这是做什么的,特别是因为我找不到任何人在任何地方明确引用它们。
第 3 部分
typedef NS_ENUM(NSInteger, VertexAttribute)
{
VertexAttributePosition = 0,
VertexAttributeTexcoord = 1,
};
Run Code Online (Sandbox Code Playgroud)
这个有一点更明确的用法,因为它在 .metal 文件中被引用
typedef struct
{
float3 position [[attribute(VertexAttributePosition)]];
float2 texCoord [[attribute(VertexAttributeTexcoord)]];
} Vertex;
Run Code Online (Sandbox Code Playgroud)
以及在顶点描述符代码的属性部分
mtlVertexDescriptor.attributes[VertexAttribute.position.rawValue].format = MTLVertexFormat.float3
mtlVertexDescriptor.attributes[VertexAttribute.position.rawValue].offset = 0
mtlVertexDescriptor.attributes[VertexAttribute.position.rawValue].bufferIndex = BufferIndex.meshPositions.rawValue
...
Run Code Online (Sandbox Code Playgroud)
不知何故,它似乎像缓冲区一样跟踪各种元素的索引。
第 4 部分
这个我有点得到,因为它在这里的渲染中被引用
renderEncoder.setFragmentTexture(colorMap, index: TextureIndex.color.rawValue)
Run Code Online (Sandbox Code Playgroud)
以及这里的着色器
fragment float4 fragmentShader(..., texture2d<half> colorMap [[ texture(TextureIndexColor) ]]){
Run Code Online (Sandbox Code Playgroud)
我有点得到这个(减去 NSEnum 部分),但是我不明白只为一件事做这件事是什么好习惯。
第 5 部分
这实际上是我理解的唯一一个它看起来像是所有统一组件的结构,这很有意义,因为它存储了统一的实际类型,允许着色器暴露给结构以及渲染器.
我想最终我想知道为什么采用这种方法以及为什么它是 Apple 建议的最佳实践。我认为以这种方式做事是有道理的,除了金属似乎与 Objective-c 一起玩得更好,即使它看起来很迅速。
这是一个由 Metal 着色器代码和应用程序代码(Objective-C 或,通过桥接,Swift)共享的头文件。必须在这两种语言之间共享它需要一些小心。
该#ifdef __METAL_VERSION__测试确定哪种语言它在被编译,金属,一对夫妇宏定义。对于 Objective-C,它导入 Foundation。(当然编译Metal代码时不能导入Foundation。)
在他们的 (Objective-)C 头文件中,Apple 经常使用NS_ENUM()宏声明枚举。该宏定义在 Foundation 头文件中,因此可以在将此头文件编译为应用程序代码时使用它。它没有在 Metal 头文件中定义,所以如果它想使用它(就像它一样),这个头需要为它自己定义它。宏的 Foundation 版本很有用,因为它检测编译器功能以使用类型化枚举(如果可用)和常规枚举(如果不可用)。在这个头文件中,Apple 正在为 Metal 着色器语言实现相同的宏。由于编译器是否支持类型化枚举是毫无疑问的(它确实支持),因此只有一个宏定义利用了该功能。
稍后在标题中,他们计划使用该NSInteger类型。这是由应用程序代码的 Foundation 标头定义的。由于他们想对 Metal 使用相同的代码,但该类型未在那里定义,因此他们需要在此标头中定义它。不过,他们做出了一些奇怪的选择。首先,他们使用宏而不是typedef. 其次,他们将它定义为等效于int32_t(在metal命名空间中)。这很奇怪,因为应用程序代码将是 64 位的(Metal 不适用于 32 位应用程序)导致NSInteger成为 64 位整数类型(相当于int64_t)。因此,这两个世界将不同意NSInteger基于它的枚举的大小以及所有枚举。这有点糟糕,但考虑到这些枚举的实际使用方式,可能不会引起真正的问题。
简单地将枚举基于 可能会更好int,它在所有 Apple 环境中都是 32 位的。
第 2、3 和 4 部分都相似。使用“符号”常量而不仅仅是魔术数字(即代码中的整数文字)通常是一种很好的做法。它不易出错并提高了可读性。这些部分只是定义了一些这样的符号常量,供 Metal 代码和应用程序代码共享使用。这些名称中的某些名称未在您正在检查的特定示例项目中使用这一事实表明 Apple 对多个示例项目或类似项目使用了相同的标头。
| 归档时间: |
|
| 查看次数: |
1193 次 |
| 最近记录: |