~emersion/go-kdf

12ae7750950f03c963ad33453b761cef69764fa0 — Simon Ser 4 months ago 2ff42c5 master
Rename Block to Descriptor
M cairo/cairo.go => cairo/cairo.go +2 -2
@@ 26,10 26,10 @@ var pixmanTable = map[Format]pixman.Format{
	FormatRGBA128F:  pixman.Format_rgba_float,
}

func GetBlock(fmt Format, endianness kdf.Endianness) *kdf.Block {
func GetDescriptor(fmt Format, endianness kdf.Endianness) *kdf.Descriptor {
	pixmanFmt, ok := pixmanTable[fmt]
	if !ok {
		return nil
	}
	return pixman.GetBlock(pixmanFmt, endianness)
	return pixman.GetDescriptor(pixmanFmt, endianness)
}

M cmd/go-kdf/explain.go => cmd/go-kdf/explain.go +1 -1
@@ 25,7 25,7 @@ type sampleKey struct {
	pos [4]uint8
}

func explainBlock(block *kdf.Block) {
func explainBlock(block *kdf.Descriptor) {
	basic := block.Basic

	numBytes := 0

M cmd/go-kdf/main.go => cmd/go-kdf/main.go +10 -10
@@ 82,19 82,19 @@ func main() {
			os.Exit(1)
		}

		var block *kdf.Block
		var block *kdf.Descriptor
		if strings.HasPrefix(name, "DRM_FORMAT_") {
			fmt, ok := drm.FormatTable[strings.TrimPrefix(name, "DRM_FORMAT_")]
			if !ok {
				log.Fatalf("unknown DRM format %q", name)
			}
			block = drm.GetBlock(fmt)
			block = drm.GetDescriptor(fmt)
		} else if strings.HasPrefix(name, "VK_FORMAT_") {
			fmt, ok := vulkan.FormatTable[strings.TrimPrefix(name, "VK_FORMAT_")]
			if !ok {
				log.Fatalf("unknown Vulkan format %q", name)
			}
			block = vulkan.GetBlock(fmt, endianness)
			block = vulkan.GetDescriptor(fmt, endianness)
		} else if strings.HasPrefix(name, "GL_") {
			parts := strings.SplitN(name, ",", 2)
			if len(parts) != 2 || !strings.HasPrefix(parts[1], "GL_") {


@@ 108,32 108,32 @@ func main() {
			if !ok {
				log.Fatalf("unknown GL pixel type %q", parts[1])
			}
			block = opengl.GetBlock(format, typ, endianness)
			block = opengl.GetDescriptor(format, typ, endianness)
		} else if strings.HasPrefix(name, "PIXMAN_") {
			fmt, ok := pixman.FormatTable[strings.TrimPrefix(name, "PIXMAN_")]
			if !ok {
				log.Fatalf("unknown Pixman format: %v", name)
			}
			block = pixman.GetBlock(fmt, endianness)
			block = pixman.GetDescriptor(fmt, endianness)
		} else if strings.HasPrefix(name, "CAIRO_FORMAT_") {
			fmt, ok := cairo.FormatTable[strings.TrimPrefix(name, "CAIRO_FORMAT_")]
			if !ok {
				log.Fatalf("unknown Cairo format: %v", name)
			}
			block = cairo.GetBlock(fmt, endianness)
			block = cairo.GetDescriptor(fmt, endianness)
		} else if strings.HasPrefix(name, "GPUTextureFormat.") {
			fmt, ok := webgpu.FormatTable[strings.TrimPrefix(name, "GPUTextureFormat.")]
			if !ok {
				log.Fatalf("unknown WebGPU format: %v", name)
			}
			// TODO: How to deal with runtime params
			block = webgpu.GetBlock(fmt, endianness, nil)
			block = webgpu.GetDescriptor(fmt, endianness, nil)
		} else if strings.HasPrefix(name, "AV_PIX_FMT_") {
			fmt, ok := ffmpeg.FormatTable[strings.TrimPrefix(name, "AV_PIX_FMT_")]
			if !ok {
				log.Fatalf("unknown ffmpeg format: %v", name)
			}
			block = ffmpeg.GetBlock(fmt)
			block = ffmpeg.GetDescriptor(fmt)
		} else {
			log.Fatalf("unknown format family for %q", name)
		}


@@ 153,7 153,7 @@ func main() {
	}
}

func printBlock(block *kdf.Block) {
func printBlock(block *kdf.Descriptor) {
	fmt.Printf("Type: %v\n", block.Type.Name(block.VendorID))
	fmt.Printf("Vendor: %v\n", block.VendorID)
	fmt.Printf("Version: %v\n", block.VersionNumber)


@@ 172,7 172,7 @@ func printBlock(block *kdf.Block) {
	}
}

func printSampleInfo(info *kdf.SampleInfo, basic *kdf.BlockBasic) {
func printSampleInfo(info *kdf.SampleInfo, basic *kdf.BasicDescriptor) {
	var dataType []string
	if info.Float {
		dataType = append(dataType, "float")

M drm/drm.go => drm/drm.go +8 -8
@@ 91,8 91,8 @@ func parseRGBAPackedFormat(s string) (channels []kdf.Channel, bitsPerChannel []i
	return channels, bitsPerChannel
}

func genRGBAPacked(channels []kdf.Channel, bitsPerChannel []int) *kdf.Block {
	return kdf.NewBlockBasic(&kdf.BlockBasic{
func genRGBAPacked(channels []kdf.Channel, bitsPerChannel []int) *kdf.Descriptor {
	return kdf.NewBasicDescriptor(&kdf.BasicDescriptor{
		ColorModel:          kdf.ColorModelRGBSDA,
		TexelBlockDimension: [4]int{1, 1, 1, 1},
		BytesPlane:          []uint8{getBytesPerPixel(bitsPerChannel)},


@@ 141,7 141,7 @@ var twoPlaneRGBAFormats = []Format{
	FormatBGR565_A8,
}

func genRGBATwoPlane(fmt Format) *kdf.Block {
func genRGBATwoPlane(fmt Format) *kdf.Descriptor {
	if !strings.HasSuffix(fmt.String(), "_A8") {
		panic("unsupported: second plane must be A8")
	}


@@ 217,7 217,7 @@ var packedYUVAFormats = map[Format]struct {
	// TODO: VUY101010 has a single Y channel and is 10-bit
}

func genYUVAPacked(texelBlockDim [4]int, channels []kdf.Channel, bitsPerChannel []int) *kdf.Block {
func genYUVAPacked(texelBlockDim [4]int, channels []kdf.Channel, bitsPerChannel []int) *kdf.Descriptor {
	sampleInfo := genPackedSamples(channels, bitsPerChannel)
	numY := 0
	for i := len(sampleInfo) - 1; i >= 0; i-- {


@@ 229,7 229,7 @@ func genYUVAPacked(texelBlockDim [4]int, channels []kdf.Channel, bitsPerChannel 
		numY++
	}

	return kdf.NewBlockBasic(&kdf.BlockBasic{
	return kdf.NewBasicDescriptor(&kdf.BasicDescriptor{
		ColorModel:          kdf.ColorModelYUVSDA,
		TexelBlockDimension: texelBlockDim,
		BytesPlane:          []uint8{getBytesPerPixel(bitsPerChannel)},


@@ 238,10 238,10 @@ func genYUVAPacked(texelBlockDim [4]int, channels []kdf.Channel, bitsPerChannel 
}

var blockTableOnce sync.Once
var blockTable map[Format]*kdf.Block
var blockTable map[Format]*kdf.Descriptor

func genTable() {
	blockTable = make(map[Format]*kdf.Block)
	blockTable = make(map[Format]*kdf.Descriptor)

	for name, fmt := range FormatTable {
		channels, bitsPerChannel := parseRGBAPackedFormat(name)


@@ 281,7 281,7 @@ func genTable() {
	}
}

func GetBlock(format Format) *kdf.Block {
func GetDescriptor(format Format) *kdf.Descriptor {
	blockTableOnce.Do(genTable)

	return blockTable[format]

M ffmpeg/ffmpeg.go => ffmpeg/ffmpeg.go +3 -3
@@ 79,14 79,14 @@ var packedRGBAFormats = map[Format]packedFormatInfo{
	},
}

func GetBlock(format Format) *kdf.Block {
func GetDescriptor(format Format) *kdf.Descriptor {
	if packed, ok := packedRGBAFormats[format]; ok {
		return genRGBAPacked(&packed)
	}
	return nil
}

func genRGBAPacked(info *packedFormatInfo) *kdf.Block {
func genRGBAPacked(info *packedFormatInfo) *kdf.Descriptor {
	if len(info.channels) != len(info.bitsPerChannel) {
		panic("mismatch between channels and bits per channel")
	}


@@ 100,7 100,7 @@ func genRGBAPacked(info *packedFormatInfo) *kdf.Block {
		sampleInfo = append(sampleInfo, sample)
	}

	return kdf.NewBlockBasic(&kdf.BlockBasic{
	return kdf.NewBasicDescriptor(&kdf.BasicDescriptor{
		ColorModel:          kdf.ColorModelRGBSDA,
		TexelBlockDimension: [4]int{1, 1, 1, 1},
		BytesPlane:          []uint8{getBytesPerPixel(info.bitsPerChannel)},

M kdf.go => kdf.go +41 -41
@@ 8,93 8,93 @@ import (
	"fmt"
)

type BlockType uint16
type DescriptorType uint16

// Khronos block types.
// Khronos descriptor block types.
const (
	BlockTypeKhronosBasic                BlockType = 0
	BlockTypeKhronosAdditionalPlanes     BlockType = 0x6001
	BlockTypeKhronosAdditionalDimensions BlockType = 0x6002
	DescriptorTypeKhronosBasic                DescriptorType = 0
	DescriptorTypeKhronosAdditionalPlanes     DescriptorType = 0x6001
	DescriptorTypeKhronosAdditionalDimensions DescriptorType = 0x6002
)

func (t BlockType) Name(v BlockVendor) string {
func (t DescriptorType) Name(v Vendor) string {
	switch v {
	case BlockVendorKhronos:
	case VendorKhronos:
		switch t {
		case BlockTypeKhronosBasic:
		case DescriptorTypeKhronosBasic:
			return "basic"
		case BlockTypeKhronosAdditionalPlanes:
		case DescriptorTypeKhronosAdditionalPlanes:
			return "additional planes"
		case BlockTypeKhronosAdditionalDimensions:
		case DescriptorTypeKhronosAdditionalDimensions:
			return "additional dimensions"
		}
	}
	return fmt.Sprintf("unknown (%d)", t)
}

type BlockVendor uint16
type Vendor uint16

const (
	BlockVendorKhronos BlockVendor = 0
	VendorKhronos Vendor = 0
)

func (v BlockVendor) String() string {
func (v Vendor) String() string {
	switch v {
	case BlockVendorKhronos:
	case VendorKhronos:
		return "Khronos"
	default:
		return fmt.Sprintf("unknown (%d)", v)
	}
}

type BlockVersion uint16
type DescriptorVersion uint16

const (
	BlockVersion1_1 BlockVersion = 0
	BlockVersion1_2 BlockVersion = 1
	BlockVersion1_3 BlockVersion = 2
	DescriptorVersion1_1 DescriptorVersion = 0
	DescriptorVersion1_2 DescriptorVersion = 1
	DescriptorVersion1_3 DescriptorVersion = 2
)

func (v BlockVersion) String() string {
func (v DescriptorVersion) String() string {
	switch v {
	case BlockVersion1_1:
	case DescriptorVersion1_1:
		return "1.1"
	case BlockVersion1_2:
	case DescriptorVersion1_2:
		return "1.2"
	case BlockVersion1_3:
	case DescriptorVersion1_3:
		return "1.3"
	default:
		return fmt.Sprintf("unknown (%d)", v)
	}
}

type Block struct {
	Type          BlockType
	VendorID      BlockVendor
	VersionNumber BlockVersion
type Descriptor struct {
	Type          DescriptorType
	VendorID      Vendor
	VersionNumber DescriptorVersion

	Basic *BlockBasic
	Basic *BasicDescriptor
}

func NewBlockBasic(basic *BlockBasic) *Block {
	return &Block{
		Type:          BlockTypeKhronosBasic,
		VendorID:      BlockVendorKhronos,
		VersionNumber: BlockVersion1_3,
func NewBasicDescriptor(basic *BasicDescriptor) *Descriptor {
	return &Descriptor{
		Type:          DescriptorTypeKhronosBasic,
		VendorID:      VendorKhronos,
		VersionNumber: DescriptorVersion1_3,
		Basic:         basic,
	}
}

func (block *Block) Copy() *Block {
	var basicCopy *BlockBasic
	if basic := block.Basic; basic != nil {
func (desc *Descriptor) Copy() *Descriptor {
	var basicCopy *BasicDescriptor
	if basic := desc.Basic; basic != nil {
		bytesPlaneCopy := make([]uint8, len(basic.BytesPlane))
		copy(bytesPlaneCopy, basic.BytesPlane)

		sampleInfoCopy := make([]SampleInfo, len(basic.SampleInfo))
		copy(sampleInfoCopy, basic.SampleInfo)

		basicCopy = &BlockBasic{
		basicCopy = &BasicDescriptor{
			ColorModel:          basic.ColorModel,
			ColorPrimaries:      basic.ColorPrimaries,
			TransferFunction:    basic.TransferFunction,


@@ 105,10 105,10 @@ func (block *Block) Copy() *Block {
		}
	}

	return &Block{
		Type:          block.Type,
		VendorID:      block.VendorID,
		VersionNumber: block.VersionNumber,
	return &Descriptor{
		Type:          desc.Type,
		VendorID:      desc.VendorID,
		VersionNumber: desc.VersionNumber,
		Basic:         basicCopy,
	}
}


@@ 344,7 344,7 @@ func (f Flags) String() string {
	return "pre-multiplied alpha"
}

type BlockBasic struct {
type BasicDescriptor struct {
	ColorModel       ColorModel
	ColorPrimaries   ColorPrimaries
	TransferFunction TransferFunction

M opengl/opengl.go => opengl/opengl.go +2 -2
@@ 133,7 133,7 @@ func getSampleBounds(bits int, typ PixelType) (lower, upper uint32) {
	}
}

func GetBlock(format PixelFormat, typ PixelType, endianness kdf.Endianness) *kdf.Block {
func GetDescriptor(format PixelFormat, typ PixelType, endianness kdf.Endianness) *kdf.Descriptor {
	channels := pixelFormatChannels[format]
	if typ.isReversed() {
		channels = reverseChannels(channels)


@@ 183,7 183,7 @@ func GetBlock(format PixelFormat, typ PixelType, endianness kdf.Endianness) *kdf
		panic("unsupported: bits per pixel not divisible by 8")
	}

	return kdf.NewBlockBasic(&kdf.BlockBasic{
	return kdf.NewBasicDescriptor(&kdf.BasicDescriptor{
		ColorModel:          kdf.ColorModelRGBSDA,
		TransferFunction:    kdf.TransferFunctionLinear,
		TexelBlockDimension: [4]int{1, 1, 1, 1},

M pixman/pixman.go => pixman/pixman.go +2 -2
@@ 145,7 145,7 @@ func getSampleBounds(bits int, typ FormatType) (lower, upper uint32) {
// TODO: use a better way to indicate unused bits
var unusedChannel kdf.Channel = 255

func GetBlock(fmt Format, endianness kdf.Endianness) *kdf.Block {
func GetDescriptor(fmt Format, endianness kdf.Endianness) *kdf.Descriptor {
	channels := fmt.Type().channels()
	bitsPerChannelMap := getBitsPerChannel(fmt)
	if channels == nil || bitsPerChannelMap == nil {


@@ 202,7 202,7 @@ func GetBlock(fmt Format, endianness kdf.Endianness) *kdf.Block {
		})
	}

	return kdf.NewBlockBasic(&kdf.BlockBasic{
	return kdf.NewBasicDescriptor(&kdf.BasicDescriptor{
		ColorModel:          kdf.ColorModelRGBSDA,
		ColorPrimaries:      kdf.ColorPrimariesBT709OrSRGB,
		TransferFunction:    fmt.Type().transferFunction(),

M reader.go => reader.go +11 -11
@@ 32,14 32,14 @@ func read4Uint8(r io.Reader) ([4]uint8, error) {
	}, err
}

func Read(r io.Reader) ([]Block, error) {
func Read(r io.Reader) ([]Descriptor, error) {
	totalSize, err := readUint32(r)
	if err != nil {
		return nil, err
	}
	var _ = totalSize // TODO

	var l []Block
	var l []Descriptor
	for {
		block, err := readBlock(r)
		if err == io.EOF {


@@ 54,20 54,20 @@ func Read(r io.Reader) ([]Block, error) {
	return l, nil
}

func readBlock(r io.Reader) (*Block, error) {
func readBlock(r io.Reader) (*Descriptor, error) {
	v, err := readUint32(r)
	if err != nil {
		return nil, err
	}
	descType := BlockType(getBitRange(v, 31, 17))
	vendorID := BlockVendor(getBitRange(v, 16, 0))
	descType := DescriptorType(getBitRange(v, 31, 17))
	vendorID := Vendor(getBitRange(v, 16, 0))

	v, err = readUint32(r)
	if err != nil {
		return nil, err
	}
	descBlockSize := int64(getBitRange(v, 31, 16))
	versionNumber := BlockVersion(getBitRange(v, 15, 0))
	versionNumber := DescriptorVersion(getBitRange(v, 15, 0))

	if versionNumber != 2 {
		return nil, fmt.Errorf("incompatible block version number")


@@ 78,8 78,8 @@ func readBlock(r io.Reader) (*Block, error) {
		return nil, fmt.Errorf("descriptor block size smaller than header size")
	}

	var basic *BlockBasic
	if vendorID == BlockVendorKhronos && descType == BlockTypeKhronosBasic {
	var basic *BasicDescriptor
	if vendorID == VendorKhronos && descType == DescriptorTypeKhronosBasic {
		basic, err = readBlockBasic(r, descBlockSize-headerSize)
		if err != nil {
			return nil, err


@@ 92,7 92,7 @@ func readBlock(r io.Reader) (*Block, error) {
		}
	}

	return &Block{
	return &Descriptor{
		Type:          descType,
		VendorID:      vendorID,
		VersionNumber: versionNumber,


@@ 100,7 100,7 @@ func readBlock(r io.Reader) (*Block, error) {
	}, nil
}

func readBlockBasic(r io.Reader, size int64) (*BlockBasic, error) {
func readBlockBasic(r io.Reader, size int64) (*BasicDescriptor, error) {
	v, err := read4Uint8(r)
	if err != nil {
		return nil, err


@@ 150,7 150,7 @@ func readBlockBasic(r io.Reader, size int64) (*BlockBasic, error) {
		sampleInfo = append(sampleInfo, *info)
	}

	return &BlockBasic{
	return &BasicDescriptor{
		ColorModel:          colorModel,
		ColorPrimaries:      colorPrimaries,
		TransferFunction:    transferFunction,

M vulkan/vulkan.go => vulkan/vulkan.go +12 -12
@@ 113,13 113,13 @@ func genSample(ch kdf.Channel, nf numericFormat, bitLength int, bitOffset uint16
	}
}

func genRGBAUnpacked(bytesPerChannel int, channels []kdf.Channel, nf numericFormat, endianness kdf.Endianness) *kdf.Block {
func genRGBAUnpacked(bytesPerChannel int, channels []kdf.Channel, nf numericFormat, endianness kdf.Endianness) *kdf.Descriptor {
	var sampleInfo []kdf.SampleInfo
	for _, sample := range internal.UnpackedSamples(channels, bytesPerChannel, endianness) {
		sampleInfo = append(sampleInfo, *genSample(sample.Channel, nf, sample.BitLength, sample.BitOffset))
	}

	return kdf.NewBlockBasic(&kdf.BlockBasic{
	return kdf.NewBasicDescriptor(&kdf.BasicDescriptor{
		ColorModel:          kdf.ColorModelRGBSDA,
		ColorPrimaries:      kdf.ColorPrimariesBT709OrSRGB,
		TransferFunction:    numericFormatTF(nf),


@@ 129,7 129,7 @@ func genRGBAUnpacked(bytesPerChannel int, channels []kdf.Channel, nf numericForm
	})
}

func genYUVAUnpacked(bytesPerChannel int, channels []kdf.Channel, nf numericFormat, endianness kdf.Endianness) *kdf.Block {
func genYUVAUnpacked(bytesPerChannel int, channels []kdf.Channel, nf numericFormat, endianness kdf.Endianness) *kdf.Descriptor {
	var sampleInfo []kdf.SampleInfo
	for _, sample := range internal.UnpackedSamples(channels, bytesPerChannel, endianness) {
		sampleInfo = append(sampleInfo, *genSample(sample.Channel, nf, sample.BitLength, sample.BitOffset))


@@ 145,7 145,7 @@ func genYUVAUnpacked(bytesPerChannel int, channels []kdf.Channel, nf numericForm
		numY++
	}

	return kdf.NewBlockBasic(&kdf.BlockBasic{
	return kdf.NewBasicDescriptor(&kdf.BasicDescriptor{
		ColorModel:          kdf.ColorModelYUVSDA,
		TexelBlockDimension: [4]int{2, 1, 1, 1},
		BytesPlane:          []uint8{uint8(bytesPerChannel * len(channels))},


@@ 153,7 153,7 @@ func genYUVAUnpacked(bytesPerChannel int, channels []kdf.Channel, nf numericForm
	})
}

func genRGBAPacked(channels []kdf.Channel, bitsPerChannel []int, nf numericFormat, endianness kdf.Endianness) *kdf.Block {
func genRGBAPacked(channels []kdf.Channel, bitsPerChannel []int, nf numericFormat, endianness kdf.Endianness) *kdf.Descriptor {
	totalBits := 0
	for _, n := range bitsPerChannel {
		totalBits += n


@@ 167,7 167,7 @@ func genRGBAPacked(channels []kdf.Channel, bitsPerChannel []int, nf numericForma
		sampleInfo = append(sampleInfo, *genSample(sample.Channel, nf, sample.BitLength, sample.BitOffset))
	}

	return kdf.NewBlockBasic(&kdf.BlockBasic{
	return kdf.NewBasicDescriptor(&kdf.BasicDescriptor{
		ColorModel:          kdf.ColorModelRGBSDA,
		ColorPrimaries:      kdf.ColorPrimariesBT709OrSRGB,
		TransferFunction:    numericFormatTF(nf),


@@ 305,7 305,7 @@ func parseUnpackedBase(s string) (bytesPerChannel int, channels []kdf.Channel) {
	return bytesPerChannel, channels
}

func mergeMultiPlanar(planes []*kdf.Block) *kdf.Block {
func mergeMultiPlanar(planes []*kdf.Descriptor) *kdf.Descriptor {
	block := planes[0].Copy()
	basic := block.Basic
	bitOffset := 8 * uint16(basic.BytesPlane[0])


@@ 322,13 322,13 @@ func mergeMultiPlanar(planes []*kdf.Block) *kdf.Block {

type blockTable struct {
	once sync.Once
	m    map[Format]*kdf.Block
	m    map[Format]*kdf.Descriptor
}

var blockTableLE, blockTableBE blockTable

func genTable(endianness kdf.Endianness) map[Format]*kdf.Block {
	blockTable := make(map[Format]*kdf.Block)
func genTable(endianness kdf.Endianness) map[Format]*kdf.Descriptor {
	blockTable := make(map[Format]*kdf.Descriptor)

	for _, base := range unpackedBaseFormats {
		bytesPerChannel, channels := parseUnpackedBase(base)


@@ 380,7 380,7 @@ func genTable(endianness kdf.Endianness) map[Format]*kdf.Block {
		base = strings.TrimRight(base, "_2PLANE")
		base = strings.TrimRight(base, "_3PLANE")

		var planes []*kdf.Block
		var planes []*kdf.Descriptor
		for _, planeBase := range strings.Split(base, "_") {
			bytesPerChannel, channels := parseUnpackedBase(planeBase)
			plane := genRGBAUnpacked(bytesPerChannel, channels, numericFormatUnorm, endianness)


@@ 393,7 393,7 @@ func genTable(endianness kdf.Endianness) map[Format]*kdf.Block {
	return blockTable
}

func GetBlock(format Format, endianness kdf.Endianness) *kdf.Block {
func GetDescriptor(format Format, endianness kdf.Endianness) *kdf.Descriptor {
	var table *blockTable
	switch endianness {
	case kdf.LittleEndian:

M webgpu/webgpu.go => webgpu/webgpu.go +3 -3
@@ 13,7 13,7 @@ type Format int

var FormatTable map[string]Format = formatTable

// FormatOptions contains options for GetBlock.
// FormatOptions contains options for GetDescriptor.
//
// webgpu's conversions sometimes depend on the runtime environment.
type FormatOptions struct {


@@ 28,12 28,12 @@ type FormatOptions struct {
	Stencil8IsReal bool
}

func GetBlock(fmt Format, endianness kdf.Endianness, options *FormatOptions) *kdf.Block {
func GetDescriptor(fmt Format, endianness kdf.Endianness, options *FormatOptions) *kdf.Descriptor {
	// TODO: Handle runtime conversion options

	vulkanFmt, ok := vulkanTable[fmt]
	if !ok {
		return nil
	}
	return vulkan.GetBlock(vulkanFmt, endianness)
	return vulkan.GetDescriptor(vulkanFmt, endianness)
}

M writer.go => writer.go +5 -5
@@ 16,7 16,7 @@ func write4Uint8(w io.Writer, b [4]uint8) error {
	return writeUint32(w, v)
}

func Write(w io.Writer, blocks []Block) error {
func Write(w io.Writer, blocks []Descriptor) error {
	var buf bytes.Buffer
	for i, block := range blocks {
		if err := writeBlock(&buf, &block); err != nil {


@@ 31,8 31,8 @@ func Write(w io.Writer, blocks []Block) error {
	return err
}

func writeBlock(w io.Writer, block *Block) error {
	if block.VersionNumber != BlockVersion1_3 {
func writeBlock(w io.Writer, block *Descriptor) error {
	if block.VersionNumber != DescriptorVersion1_3 {
		return fmt.Errorf("unsupported block version: %v", block.VersionNumber)
	}



@@ 40,7 40,7 @@ func writeBlock(w io.Writer, block *Block) error {
		buf bytes.Buffer
		err error
	)
	if block.VendorID == BlockVendorKhronos && block.Type == BlockTypeKhronosBasic {
	if block.VendorID == VendorKhronos && block.Type == DescriptorTypeKhronosBasic {
		err = writeBlockBasic(w, block.Basic)
	} else {
		err = fmt.Errorf("unsupported block (vendor: %v, type: %v)", block.VendorID, block.Type)


@@ 65,7 65,7 @@ func writeBlock(w io.Writer, block *Block) error {
	return err
}

func writeBlockBasic(w io.Writer, basic *BlockBasic) error {
func writeBlockBasic(w io.Writer, basic *BasicDescriptor) error {
	if err := write4Uint8(w, [4]uint8{
		uint8(basic.ColorModel),
		uint8(basic.ColorPrimaries),