0513 cpp 비트필드
260513
C/C++ 비트필드 문법
C에서부터 이어져 온
기괴한 문법이다.
대충
short a : 1
이렇게 쓰면 a는 16비트 중에서 1비트만 쓴다.
다시 말해서
boolean을 1바이트가 아닌
1비트로 저장하게 해준다.
tight-packing인것이다.
웃긴 건
밑에 벌칸 코드에서
unsigned int cullMode : 2
이게 뭘 뜻하는지 알겠는가?
맞다.
GL과 똑같이,
None / Front / Back / FrontAndBack
이렇게 4개밖에 존재하지 않기 때문에,
VK_CULL_MODE_NONE = 0
VK_CULL_MODE_FRONT_BIT = 0x1
VK_CULL_MODE_BACK_BIT = 0x2
VK_CULL_MODE_FRONT_AND_BACK = 0x3
걍 2비트, 00 / 01 / 10 / 11 로
저장하는 것이다.
또 VkBlendFactor같이
// Provided by VK_VERSION_1_0
typedef enum VkBlendFactor {
VK_BLEND_FACTOR_ZERO = 0,
VK_BLEND_FACTOR_ONE = 1,
VK_BLEND_FACTOR_SRC_COLOR = 2,
VK_BLEND_FACTOR_ONE_MINUS_SRC_COLOR = 3,
VK_BLEND_FACTOR_DST_COLOR = 4,
VK_BLEND_FACTOR_ONE_MINUS_DST_COLOR = 5,
VK_BLEND_FACTOR_SRC_ALPHA = 6,
VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA = 7,
VK_BLEND_FACTOR_DST_ALPHA = 8,
VK_BLEND_FACTOR_ONE_MINUS_DST_ALPHA = 9,
VK_BLEND_FACTOR_CONSTANT_COLOR = 10,
VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_COLOR = 11,
VK_BLEND_FACTOR_CONSTANT_ALPHA = 12,
VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA = 13,
VK_BLEND_FACTOR_SRC_ALPHA_SATURATE = 14,
VK_BLEND_FACTOR_SRC1_COLOR = 15,
VK_BLEND_FACTOR_ONE_MINUS_SRC1_COLOR = 16,
VK_BLEND_FACTOR_SRC1_ALPHA = 17,
VK_BLEND_FACTOR_ONE_MINUS_SRC1_ALPHA = 18,
} VkBlendFactor;
이렇게 애매...하게 19개 있는 경우?
unsigned int srcColor : 5; // VkBlendFactor
unsigned int destColor : 5; // VkBlendFactor
unsigned int srcAlpha : 5; // VkBlendFactor
unsigned int destAlpha : 5; // VkBlendFactor
이렇게 5비트를 써서?
2의 5승 마이너스 1. 최대 0 ~ 31까지 표현이 가능하게 한다.
밑에 코드는
Blend가 36비트,
DepthStencil관련이 22비트,
레스터라이저가 6비트
36+22+6 = 64비트 딱 나온다.
근데 이런거 주의할 게
컴파일러마다 다르단다.
하드웨어 플랫폼에 따라서도 다를 수 있단다.
따라서 컴파일 타임 어설션을 넣어주자.
static_assert(sizeof(VulkanPipelineRasterStateKey) == 8);
참고로 쓰는 비트 수가
타입 크기를 전부 더한것보다 큰 경우
걍 잘린다고 한다.
(이게 아마 psp에뮬에서 뽑아왔던걸로 기억한다..)
// Let's pack this tight using bitfields.
// If an enable flag is set to 0, all the data fields for that section should
// also be set to 0.
// ~64 bits.
// Can't use enums unfortunately, they end up signed and breaking values above half their ranges.
struct VulkanPipelineRasterStateKey {
// Blend
unsigned int blendEnable : 1;
unsigned int srcColor : 5; // VkBlendFactor
unsigned int destColor : 5; // VkBlendFactor
unsigned int srcAlpha : 5; // VkBlendFactor
unsigned int destAlpha : 5; // VkBlendFactor
// bool useBlendConstant : 1; // sacrifice a bit to cheaply check if we need to update the blend color
unsigned int blendOpColor : 3; // VkBlendOp
unsigned int blendOpAlpha : 3; // VkBlendOp
unsigned int logicOpEnable : 1;
unsigned int logicOp : 4; // VkLogicOp
unsigned int colorWriteMask : 4;
// Depth/Stencil
unsigned int depthClampEnable : 1;
unsigned int depthTestEnable : 1;
unsigned int depthWriteEnable : 1;
unsigned int depthCompareOp : 3; // VkCompareOp
unsigned int stencilTestEnable : 1;
unsigned int stencilCompareOp : 3; // VkCompareOp
unsigned int stencilPassOp : 4; // VkStencilOp
unsigned int stencilFailOp : 4; // VkStencilOp
unsigned int stencilDepthFailOp : 4; // VkStencilOp
// We'll use dynamic state for writemask, reference and comparemask to start with,
// and viewport/scissor.
// Rasterizer
unsigned int cullMode : 2; // VkCullModeFlagBits
unsigned int topology : 4; // VkPrimitiveTopology
bool operator < (const VulkanPipelineRasterStateKey &other) const {
size_t size = sizeof(VulkanPipelineRasterStateKey);
return memcmp(this, &other, size) < 0;
}
};