DCTL
Why this lesson
Section titled “Why this lesson”A LUT is a sealed box; a DCTL is a box you can open and write. DCTL — DaVinci Color Transform Language — lets you build custom color operations as small programs, which means when a look or a transform doesn’t exist yet, you can make it exist. You don’t need to become a programmer. You need to read a DCTL without fear, change the parts that matter, and understand the handful of math operations underneath the common ones. This lesson gets you there with one complete example built line by line, so the syntax stops being intimidating and starts being obvious.
DCTL is a Studio-only feature. Everything here reads and reasons the same on free Resolve; you just can’t run it until you have Studio.
The explainer
Section titled “The explainer”The shape of every DCTL. Resolve runs your DCTL’s transform() function once for every pixel of every frame. It hands you the pixel’s position and its red, green and blue values (floats, 0–1 for a normalized image), and you must return a float3 — the new RGB. That’s the whole contract. A do-nothing DCTL:
__DEVICE__ float3 transform(int p_Width, int p_Height, int p_X, int p_Y, float p_R, float p_G, float p_B){ float3 out = make_float3(p_R, p_G, p_B); // build an RGB triplet from the inputs return out; // hand it back unchanged}Because it runs per pixel, a DCTL can’t blur or read neighbours cheaply, and it can’t write files or metadata — it’s pure “pixel in, pixel out.” That constraint is also why it’s fast enough to run live.
A complete worked example: an exposure / printer-lights DCTL. Here is a real, useful transform — a master exposure control plus three per-channel “printer-light” offsets — built line by line.
// Exposure in stops, plus per-channel printer-light offsets (also in stops).DEFINE_UI_PARAMS(exposure, Exposure, DCTLUI_SLIDER_FLOAT, 0.0f, -5.0f, 5.0f, 0.01f)DEFINE_UI_PARAMS(red_pl, Red print, DCTLUI_SLIDER_FLOAT, 0.0f, -1.0f, 1.0f, 0.01f)DEFINE_UI_PARAMS(grn_pl, Green print,DCTLUI_SLIDER_FLOAT, 0.0f, -1.0f, 1.0f, 0.01f)DEFINE_UI_PARAMS(blu_pl, Blue print, DCTLUI_SLIDER_FLOAT, 0.0f, -1.0f, 1.0f, 0.01f)
__DEVICE__ float3 transform(int p_Width, int p_Height, int p_X, int p_Y, float p_R, float p_G, float p_B){ float master = _powf(2.0f, exposure); // one stop = a doubling, so 2^stops float r_gain = master * _powf(2.0f, red_pl); float g_gain = master * _powf(2.0f, grn_pl); float b_gain = master * _powf(2.0f, blu_pl);
float3 out = make_float3(p_R * r_gain, // scale each channel by its gain p_G * g_gain, p_B * b_gain); return out;}Reading it top to bottom:
- The four
DEFINE_UI_PARAMSlines create sliders in Resolve’s DCTL panel: name, label, type, default, min, max, step. This is how a DCTL exposes controls to a colorist. Every number literal ends inf— DCTL wants floats made explicit. _powf(2.0f, exposure)is the key idea: one stop is a doubling of light, so the linear multiplier for n stops is 2ⁿ. (You can’t write2.0 ^ exposure— as the video shows,^isn’t a power operator here; you must call_powf.)- The three
_gainlines fold the master exposure together with each channel’s own offset. Nudging Red print up warms the image by exposing the red channel harder — which is exactly the intuition behind printer lights: on a film printer you dial the red, green and blue lamp intensities in discrete “points” to time each print. This DCTL is a linear-light approximation of that; true printer lights work in log density (Lesson 3.5), but the mental model — per-channel exposure of the image — is identical. make_float3(...)builds the output triplet, scaling each input channel by its gain, andreturn outhands it back. Done.
Save it into your Resolve LUT/DCTL folder, restart Resolve (new DCTLs are only compiled at startup; edits to an existing file reload live), drop a DCTL OFX onto a node, choose the file, and you have four working sliders.
The math you’ll keep meeting. Three operations cover most simple DCTLs. Gain (multiply — what we just did) scales light; it’s exposure and white balance. Offset / power shape tone — a _powf(x, gamma) is a gamma curve, and log-to-linear conversions are power and log functions of exactly this kind (the “log curve math” behind a camera’s LogC → linear). And a matrix — a 3×3 grid of numbers — mixes channels: each output channel is a weighted sum of the three inputs. That’s what the RGB mixer does, what a gamut conversion is under the hood, and what the AMA discussion means by “1D vs 3D operations”: a curve touches each channel alone (1D), a matrix or 3D LUT lets channels influence each other (3D). Hold gain, curve and matrix and you can read the guts of most transforms.
- Type the do-nothing boilerplate, save it to your DCTL folder, restart Resolve, and confirm it changes nothing. That’s your baseline.
- Add the exposure slider and
_powf(2.0f, exposure)gain. Prove it against Resolve’s own controls: set it to +1 stop, wipe it against a Gain node, and check they match on the waveform. - Add the three printer-light sliders. Warm the image with Red print up / Blue print down and watch the parade — you’ve built a printer-light balance from scratch.
- Break it on purpose: delete a semicolon, then read Resolve’s
r_debug.logto find the error. Learning to read the log is the real skill.
Terms introduced
Section titled “Terms introduced”Check yourself
What does a DCTL operate on, and how often does its transform() run?
In the worked exposure DCTL, why is the gain computed as _powf(2.0f, stops)?
What is a 3×3 color matrix used for in a DCTL?
Why does a DCTL need the paid Studio version, and why must you restart Resolve after adding a new one?
You can move on when you can… read a simple DCTL and say what each line does, write an exposure or per-channel-gain transform yourself, explain why one stop is _powf(2, n), and say what a 3×3 matrix does that a curve can’t.
Go deeper
Section titled “Go deeper”Cullen Kelly — AMA, DCTL & color-math segments: a gamut-compression DCTL compared against a sat-vs-sat curve, then 1D-vs-3D operations demonstrated live through the RGB mixer / matrix — the exact “curve touches one channel, matrix mixes all three” distinction, shown on real footage.
Segment: 20:50–39:20 — gamut-compression DCTL vs sat curve, then 1D vs 3D ops via the matrixwatch full video
Segment: 58:30–1:13:23 — gamut excursions in wide working spaces + node blend-mode trickswatch full video
- DaVinci Resolve DCTL developer docs (bundled with Resolve Studio, in the
Developer/DCTLfolder, and mirrored across the community): the authoritative reference forDEFINE_UI_PARAMS, the built-in_powf/_logf/ matrix helpers, and thetransform()signature. - Juan Melara (juanmelara.com.au) and the LiftGammaGain / community DCTL threads: worked DCTLs (log conversions, print emulations) you can read and modify — the best way to learn is to open someone else’s.
The paid path: structured DCTL-and-color-math teaching lives in Mixing Light’s developer tutorials and colour.training’s advanced modules. This page gets you reading and editing; those take you to writing transforms from a spec.
Next up: 3.5 · Print film emulation — construction — building a film look as a chain, with printer lights done properly in log density.