Skip to main content

TSMPDecodeByteOutput.cginc

Optional combined header output​

To eliminate the decoder's separate packing pass, include TSMPDecodeCommon.cginc and add both hidden shader properties below. Their defaults preserve ordinary byte output. Only advertise these properties if the fragment implements prefix handling.

TSMPReadOutputPrefix(float2 uv, out int baseByte, out float4 prefix) returns true for the header area: return prefix without decoding a payload byte. Otherwise baseByte is the payload-relative index. With a 14-pixel prefix, output pixels 0..13 contain the 56 header bytes, pixel 14 contains payload bytes 0..3, then subsequent payload pixels follow across rows. _ByteCount remains the payload length, excluding the prefix. Padding returns zero. Header texture coordinates use exact texel loads; do not apply source-image flipY again.

The standard TSMPDecodeByteOutputFragment handles this automatically when TSMP_COMBINED_BYTE_OUTPUT is defined by the common include. A custom fragment must call the helper before its byte/symbol calculations. Use #if defined(TSMP_COMBINED_BYTE_OUTPUT) with the original pixel calculation as the #else path if supporting older Core versions. Without the common include, standalone byte-output shaders retain their original behavior.

[HideInInspector] _TSMPHeaderTex ("Decoded Header", 2D) = "black" {}
[HideInInspector] _TSMPHeaderPixels ("Header Pixels", Float) = 0

TSMPDecodeByteOutput.cginc is a shader include for codec decode passes. It turns a byte-addressed DecodeByte(index) function into a fragment shader that writes decoded bytes into an RGBA output texture.

Use it when your custom codec can recover one byte by index and you want Core's decoder readback path to receive those bytes in a standard texture layout.

Include path:

#include "Packages/com.kibalab.tsmp.core/Runtime/Codecs/Common/Shaders/cgincs/TSMPDecodeByteOutput.cginc"

Required inputs​

The include expects these symbols to exist in the shader before it is included or before the fragment runs.

SymbolTypePurpose
v2fstructFragment input type. It must expose float2 uv.
_OutputWidthnumeric uniformWidth of the byte output texture in pixels.
_OutputHeightnumeric uniformHeight of the byte output texture in pixels.
_ByteCountnumeric uniformNumber of valid decoded bytes requested by the decoder.
DecodeByte(int byteIndex)functionReturns one decoded byte for a byte index.

_OutputWidth, _OutputHeight, and _ByteCount are usually assigned by the decoder or codec material setup.

DecodeByte(int byteIndex) contract​

By default the include calls:

int DecodeByte(int byteIndex)

The function should return an integer byte value from 0 to 255.

Rules:

  • byteIndex is a zero-based payload byte index.
  • The function may be called for indices beyond _ByteCount inside the last RGBA pixel.
  • Out-of-range reads should return 0.
  • Values outside 0..255 should be clamped or avoided by the codec.
  • The function should not rely on filtered sampling for exact byte values.

Custom byte function name​

Define TSMP_DECODE_BYTE_FUNC before including the file to use a different function name.

int MyCodecDecodeByte(int byteIndex)
{
return DecodeMySymbol(byteIndex);
}

#define TSMP_DECODE_BYTE_FUNC MyCodecDecodeByte
#include "Packages/com.kibalab.tsmp.core/Runtime/Codecs/Common/Shaders/cgincs/TSMPDecodeByteOutput.cginc"

The replacement function must have the same call shape: one int index in, one byte-like int out.

Output layout​

Each output pixel stores four bytes:

ChannelByte index
RbaseByte + 0
GbaseByte + 1
BbaseByte + 2
AbaseByte + 3

The base index is calculated as:

baseByte = ((int)pixel.y * (int)_OutputWidth + (int)pixel.x) * 4;

The returned fragment color is:

float4(b0 / 255.0, b1 / 255.0, b2 / 255.0, b3 / 255.0)

If baseByte >= _ByteCount, the fragment returns black transparent zero.

TSMPDecodeByteOutputFragment(v2f i)​

float4 TSMPDecodeByteOutputFragment(v2f i)

Main helper function exported by the include. It:

  1. Converts i.uv into an output pixel coordinate.
  2. Clamps the pixel coordinate to the output texture bounds.
  3. Calculates the first byte index for that pixel.
  4. Calls TSMP_DECODE_BYTE_FUNC for up to four bytes.
  5. Packs those bytes into RGBA channels.

Use this function when your shader already has its own frag entry point.

Default frag(v2f i)​

Unless suppressed, the include defines:

float4 frag(v2f i) : SV_Target
{
return TSMPDecodeByteOutputFragment(i);
}

This is convenient for a simple decode material where the pass only writes the byte output texture.

TSMP_SUPPRESS_DEFAULT_FRAG​

Define TSMP_SUPPRESS_DEFAULT_FRAG before including the file if you want to provide your own fragment function.

#define TSMP_SUPPRESS_DEFAULT_FRAG
#include "Packages/com.kibalab.tsmp.core/Runtime/Codecs/Common/Shaders/cgincs/TSMPDecodeByteOutput.cginc"

float4 frag(v2f i) : SV_Target
{
return TSMPDecodeByteOutputFragment(i);
}

This is useful when the pass needs extra debug output, conditional logic, or a different entry point name.

Minimal shader pass example​

struct v2f
{
float4 pos : SV_POSITION;
float2 uv : TEXCOORD0;
};

float _OutputWidth;
float _OutputHeight;
float _ByteCount;

int DecodeByte(int byteIndex)
{
return byteIndex & 255;
}

#include "Packages/com.kibalab.tsmp.core/Runtime/Codecs/Common/Shaders/cgincs/TSMPDecodeByteOutput.cginc"

This example writes a predictable byte pattern into the output texture. A real codec should decode from the TSMP source frame instead.

Common mistakes​

SymptomLikely cause
Output is all zero_ByteCount is zero or DecodeByte always returns zero.
Last bytes contain garbageDecodeByte does not guard indices beyond payload length.
Every fourth byte is wrongRGBA channel order does not match the output layout.
Works in editor but fails in runtimeShader property names or material setup differ in the runtime path.
Stale bytes after a smaller frameThe output texture is not cleared and the decoder reads more than _ByteCount.